From 7d1c000352a82ff4ec076dc758f0d9fea9daedf5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 12:57:40 -0400 Subject: [PATCH 001/484] Initial models and managers to support ACLs for a generic object --- apps/acls/__init__.py | 21 +++++++++++ apps/acls/admin.py | 23 ++++++++++++ apps/acls/api.py | 62 ++++++++++++++++++++++++++++++++ apps/acls/models.py | 84 +++++++++++++++++++++++++++++++++++++++++++ apps/acls/tests.py | 16 +++++++++ apps/acls/urls.py | 15 ++++++++ apps/acls/views.py | 39 ++++++++++++++++++++ 7 files changed, 260 insertions(+) create mode 100644 apps/acls/__init__.py create mode 100644 apps/acls/admin.py create mode 100644 apps/acls/api.py create mode 100644 apps/acls/models.py create mode 100644 apps/acls/tests.py create mode 100644 apps/acls/urls.py create mode 100644 apps/acls/views.py diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py new file mode 100644 index 0000000000..81de093b2b --- /dev/null +++ b/apps/acls/__init__.py @@ -0,0 +1,21 @@ +from django.utils.translation import ugettext_lazy as _ + +#from documents.models import Document +from navigation.api import register_links, register_multi_item_links +from project_setup.api import register_setup + +from permissions.api import register_permission, set_namespace_title + + +ACLS_EDIT_ACL = {'namespace': 'acls', 'name': 'acl_edit', 'label': _(u'Edit ACLs')} +ACLS_VIEW_ACL = {'namespace': 'acls', 'name': 'acl_view', 'label': _(u'View ACLs')} + +set_namespace_title('acls', _(u'Access control lists')) +register_permission(ACLS_EDIT_ACL) +register_permission(ACLS_VIEW_ACL) + +acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} + + + +#register_links(Document, [acl_list], menu_name='form_header') diff --git a/apps/acls/admin.py b/apps/acls/admin.py new file mode 100644 index 0000000000..630f1d4afe --- /dev/null +++ b/apps/acls/admin.py @@ -0,0 +1,23 @@ +from django.contrib import admin + +from acls.models import AccessEntry + +from django.contrib.contenttypes import generic +from django.contrib.contenttypes.models import ContentType + +#class PermissionHolderInline(admin.StackedInline): +# model = PermissionHolder +# extra = 1 +# classes = ('collapse-open',) +# allow_add = True# +# +class AccessEntryAdmin(admin.ModelAdmin): + related_lookup_fields = { + 'generic': [['holder_type', 'holder_id'], ['content_type', 'object_id']], + } + #inlines = [PermissionHolderInline] + list_display = ('pk', 'holder_object', 'permission', 'content_object') + list_display_links = ('pk',) + model = AccessEntry + +admin.site.register(AccessEntry, AccessEntryAdmin) diff --git a/apps/acls/api.py b/apps/acls/api.py new file mode 100644 index 0000000000..13efbbed28 --- /dev/null +++ b/apps/acls/api.py @@ -0,0 +1,62 @@ +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/acls/models.py b/apps/acls/models.py new file mode 100644 index 0000000000..82d921cc9e --- /dev/null +++ b/apps/acls/models.py @@ -0,0 +1,84 @@ +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.contrib.auth.models import User +#from django.shortcuts import get_object_or_404 +#from django.utils.translation import ugettext +from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse + + +from permissions.models import Permission + + +class AccessEntryManager(models.Manager): + def grant(self, permission, requester, obj): + """ + Grant a permission (what), (to) a requester, (on) a specific object + """ + access_entry, created = AccessEntry.objects.get_or_create( + permission=permission, + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return created + + def revoke(self, permission, holder, obj): + try: + access_entry = AccessEntry.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(holder), + holder_id=holder.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + access_entry.delete() + return True + except AccessEntry.DoesNotExist: + return False + + def check_accesses(self, permission_list, requester, obj): + for permission_item in permission_list: + permission = get_object_or_404(Permission, + namespace=permission_item['namespace'], name=permission_item['name']) + try: + access_entry = AccessEntry.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return True + except AccessEntry.DoesNotExist: + raise PermissionDenied(ugettext(u'Insufficient permissions.')) + + def get_acl_url(self, obj): + content_type = ContentType.objects.get_for_model(obj.__class__) + return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) + + +class AccessEntry(models.Model): + permission = models.ForeignKey(Permission, verbose_name=_(u'permission')) + holder_type = models.ForeignKey(ContentType, + related_name='access_holder', + limit_choices_to={'model__in': ('user', 'group', 'role')}) + holder_id = models.PositiveIntegerField() + holder_object = generic.GenericForeignKey(ct_field='holder_type', fk_field='holder_id') + + content_type = models.ForeignKey(ContentType, + related_name='object_content_type') + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + + objects = AccessEntryManager() + + class Meta: + verbose_name = _(u'access entry') + verbose_name_plural = _(u'access entries') + + def __unicode__(self): + return u'%s: %s' % (self.content_type, self.content_object) diff --git a/apps/acls/tests.py b/apps/acls/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/apps/acls/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/acls/urls.py b/apps/acls/urls.py new file mode 100644 index 0000000000..00baddf5ea --- /dev/null +++ b/apps/acls/urls.py @@ -0,0 +1,15 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('acls.views', + url(r'^list_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_list', (), 'acl_list'), + +# url(r'^role/list/$', 'role_list', (), 'role_list'), +# url(r'^role/create/$', 'role_create', (), 'role_create'), +# url(r'^role/(?P\d+)/permissions/$', 'role_permissions', (), 'role_permissions'), +# 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/acls/views.py b/apps/acls/views.py new file mode 100644 index 0000000000..be8a154646 --- /dev/null +++ b/apps/acls/views.py @@ -0,0 +1,39 @@ +from django.utils.translation import ugettext_lazy as _ +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.views.generic.list_detail import object_list +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 permissions.api import check_permissions, namespace_titles + +from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL + + +def acl_list_for(request, obj, extra_context=None): + check_permissions(request.user, [ACLS_VIEW_ACL]) + + context = { + 'object_list': [], + 'title': _(u'access control lists for: %s' % obj), + #'multi_select_as_buttons': True, + #'hide_links': True, + } + + if extra_context: + context.update(extra_context) + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def acl_list(request, app_label, model_name, object_id): + ct = get_object_or_404(ContentType, app_label=app_label, model=model_name) + obj = get_object_or_404(ContentType.user_type.get_object_for_this_type, pk=object_id) + return acl_list_for(request, obj) + + From 6bbaca774554fe30945c7eb4cb6f68394e4a34ce Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 12:58:14 -0400 Subject: [PATCH 002/484] Added a new docuent_acls app to tie in documents with ACLs --- apps/document_acls/__init__.py | 12 ++++++++++++ apps/document_acls/models.py | 3 +++ apps/document_acls/tests.py | 16 ++++++++++++++++ apps/document_acls/urls.py | 5 +++++ apps/document_acls/views.py | 18 ++++++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 apps/document_acls/__init__.py create mode 100644 apps/document_acls/models.py create mode 100644 apps/document_acls/tests.py create mode 100644 apps/document_acls/urls.py create mode 100644 apps/document_acls/views.py diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py new file mode 100644 index 0000000000..c83609ef16 --- /dev/null +++ b/apps/document_acls/__init__.py @@ -0,0 +1,12 @@ +from django.utils.translation import ugettext_lazy as _ + +from documents.models import Document +from navigation.api import register_links, register_multi_item_links +from project_setup.api import register_setup + +from acls import ACLS_VIEW_ACL + + +acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} + +register_links(Document, [acl_list], menu_name='form_header') diff --git a/apps/document_acls/models.py b/apps/document_acls/models.py new file mode 100644 index 0000000000..71a8362390 --- /dev/null +++ b/apps/document_acls/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/document_acls/tests.py b/apps/document_acls/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/apps/document_acls/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/document_acls/urls.py b/apps/document_acls/urls.py new file mode 100644 index 0000000000..ed86e90c81 --- /dev/null +++ b/apps/document_acls/urls.py @@ -0,0 +1,5 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('document_acls.views', + url(r'^list_for/(?P\d+)/$', 'document_acl_list', (), 'document_acl_list'), +) diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py new file mode 100644 index 0000000000..879e30fcf4 --- /dev/null +++ b/apps/document_acls/views.py @@ -0,0 +1,18 @@ +from django.shortcuts import render_to_response, get_object_or_404 +from django.utils.translation import ugettext_lazy as _ + +from documents.models import Document +from acls.views import acl_list_for +from acls.models import AccessEntry + + +def document_acl_list(request, document_id): + document = get_object_or_404(Document, pk=document_id) + return acl_list_for( + request, + document, + extra_context={ + 'object': document, + 'object_name': _(u'document'), + } + ) From 0f5d68670a883280e4e56a56a2ea224d68dd7da5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 12:58:48 -0400 Subject: [PATCH 003/484] Updated to a newer version of django_extensions and Grappelli --- requirements/development.txt | 4 ++-- requirements/production.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements/development.txt b/requirements/development.txt index 10496b3b5d..d82c3c1f7b 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -1,6 +1,6 @@ Django==1.3 Werkzeug==0.6.2 -django-extensions==0.6 +django-extensions==0.7.1 django-pagination==1.0.7 django-rosetta==0.6.2 wsgiref==0.1.2 @@ -14,7 +14,7 @@ slate==0.3 ghostscript==0.4.1 pdfminer==20110227 APScheduler==2.0.2 -django-grappelli==2.3.3 +django-grappelli==2.3.5 Pillow==1.7.4 cssmin==0.1.4 django-compressor==1.1 diff --git a/requirements/production.txt b/requirements/production.txt index ba444a2bbf..6053cfa899 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -11,7 +11,7 @@ slate==0.3 ghostscript==0.4.1 pdfminer==20110227 APScheduler==2.0.2 -django-grappelli==2.3.3 +django-grappelli==2.3.5 Pillow==1.7.4 cssmin==0.1.4 django-compressor==1.1 From cf2dd00dec991d906977a0ae52e8c03241697d8d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 12:59:31 -0400 Subject: [PATCH 004/484] Removed repeated import --- apps/permissions/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/permissions/views.py b/apps/permissions/views.py index 1a1d843faf..df7b8c847b 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -11,7 +11,6 @@ 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 0cb468ca9bcec4f65d7e2627339cc95e966aee1f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 12:59:45 -0400 Subject: [PATCH 005/484] Added and enabled the acls and document_acls apps --- settings.py | 2 ++ urls.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/settings.py b/settings.py index 25182f6e98..9fb0fe96e6 100644 --- a/settings.py +++ b/settings.py @@ -133,6 +133,7 @@ INSTALLED_APPS = ( 'lock_manager', 'web_theme', 'common', + 'acls', 'metadata', 'pagination', 'dynamic_search', @@ -155,6 +156,7 @@ INSTALLED_APPS = ( 'grouping', 'mptt', 'document_indexing', + 'document_acls', 'ocr', 'sources', 'mimetype', diff --git a/urls.py b/urls.py index 6127fe570e..f78307b60e 100644 --- a/urls.py +++ b/urls.py @@ -28,6 +28,8 @@ 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')), ) From acd23eebab6f2a716f96709f6fd8fd45ef9ba6fe Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 20:34:01 -0400 Subject: [PATCH 006/484] ACL app updates, display generic object proper ACL holders list with content type icon widget --- apps/acls/__init__.py | 8 ------ apps/acls/literals.py | 7 +++++ apps/acls/models.py | 65 +++++++++++++++++++++++++++++++------------ apps/acls/views.py | 18 ++++++++++-- apps/acls/widgets.py | 26 +++++++++++++++++ 5 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 apps/acls/literals.py create mode 100644 apps/acls/widgets.py diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 81de093b2b..3a4c29a3aa 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -1,9 +1,5 @@ from django.utils.translation import ugettext_lazy as _ -#from documents.models import Document -from navigation.api import register_links, register_multi_item_links -from project_setup.api import register_setup - from permissions.api import register_permission, set_namespace_title @@ -15,7 +11,3 @@ register_permission(ACLS_EDIT_ACL) register_permission(ACLS_VIEW_ACL) acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} - - - -#register_links(Document, [acl_list], menu_name='form_header') diff --git a/apps/acls/literals.py b/apps/acls/literals.py new file mode 100644 index 0000000000..5222fdb4f5 --- /dev/null +++ b/apps/acls/literals.py @@ -0,0 +1,7 @@ + +CONTENT_TYPE_ICON_MAP = { + 'auth.user': 'user', + 'auth.group': 'group', + 'documents.document': 'page', + 'permissions.role': 'medal_gold_1', +} diff --git a/apps/acls/models.py b/apps/acls/models.py index 82d921cc9e..81f2afdbb6 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -3,21 +3,20 @@ from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic from django.contrib.auth.models import User -#from django.shortcuts import get_object_or_404 -#from django.utils.translation import ugettext from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse - from permissions.models import Permission +from acls.widgets import object_w_content_type_icon + class AccessEntryManager(models.Manager): def grant(self, permission, requester, obj): """ Grant a permission (what), (to) a requester, (on) a specific object """ - access_entry, created = AccessEntry.objects.get_or_create( + access_entry, created = self.model.objects.get_or_create( permission=permission, holder_type=ContentType.objects.get_for_model(requester), holder_id=requester.pk, @@ -28,7 +27,7 @@ class AccessEntryManager(models.Manager): def revoke(self, permission, holder, obj): try: - access_entry = AccessEntry.objects.get( + access_entry = self.model.objects.get( permission=permission, holder_type=ContentType.objects.get_for_model(holder), holder_id=holder.pk, @@ -37,7 +36,7 @@ class AccessEntryManager(models.Manager): ) access_entry.delete() return True - except AccessEntry.DoesNotExist: + except self.model.DoesNotExist: return False def check_accesses(self, permission_list, requester, obj): @@ -45,7 +44,7 @@ class AccessEntryManager(models.Manager): permission = get_object_or_404(Permission, namespace=permission_item['namespace'], name=permission_item['name']) try: - access_entry = AccessEntry.objects.get( + access_entry = self.model.objects.get( permission=permission, holder_type=ContentType.objects.get_for_model(requester), holder_id=requester.pk, @@ -53,26 +52,56 @@ class AccessEntryManager(models.Manager): object_id=obj.pk ) return True - except AccessEntry.DoesNotExist: + except self.model.DoesNotExist: raise PermissionDenied(ugettext(u'Insufficient permissions.')) def get_acl_url(self, obj): - content_type = ContentType.objects.get_for_model(obj.__class__) - return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) + content_type = ContentType.objects.get_for_model(obj) + return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) + + def get_holders_for(self, obj): + content_type = ContentType.objects.get_for_model(obj) + holder_list = [] + for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): + entry = { + 'object': access_entry.holder_object, + 'label': '%s: %s' % (access_entry.holder_type, access_entry.holder_object), + 'widget': object_w_content_type_icon(access_entry.holder_object), + } + if entry not in holder_list: + holder_list.append(entry) + + return holder_list + + def get_acls_for_holder(self, obj, holder): + holder_type = ContentType.objects.get_for_model(holder) + content_type = ContentType.objects.get_for_model(obj) + return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] class AccessEntry(models.Model): permission = models.ForeignKey(Permission, verbose_name=_(u'permission')) - holder_type = models.ForeignKey(ContentType, - related_name='access_holder', - limit_choices_to={'model__in': ('user', 'group', 'role')}) - holder_id = models.PositiveIntegerField() - holder_object = generic.GenericForeignKey(ct_field='holder_type', fk_field='holder_id') - content_type = models.ForeignKey(ContentType, - related_name='object_content_type') + holder_type = models.ForeignKey( + ContentType, + related_name='access_holder', + limit_choices_to={'model__in': ('user', 'group', 'role')} + ) + holder_id = models.PositiveIntegerField() + holder_object = generic.GenericForeignKey( + ct_field='holder_type', + fk_field='holder_id' + ) + + content_type = models.ForeignKey( + ContentType, + related_name='object_content_type' + ) object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + content_object = generic.GenericForeignKey( + ct_field='content_type', + fk_field='object_id' + ) objects = AccessEntryManager() diff --git a/apps/acls/views.py b/apps/acls/views.py index be8a154646..6e5671d03a 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -9,19 +9,33 @@ from django.views.generic.create_update import create_object, delete_object, upd from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User, Group -from permissions.api import check_permissions, namespace_titles +from permissions.api import check_permissions, namespace_titles, get_permission_label +from common.utils import generate_choices_w_labels, encapsulate from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL +from acls.models import AccessEntry +def _permission_titles(permission_list): + return u', '.join([get_permission_label(permission) for permission in permission_list]) + + def acl_list_for(request, obj, extra_context=None): check_permissions(request.user, [ACLS_VIEW_ACL]) context = { - 'object_list': [], + 'object_list': AccessEntry.objects.get_holders_for(obj), 'title': _(u'access control lists for: %s' % obj), #'multi_select_as_buttons': True, #'hide_links': True, + 'extra_columns': [ + #{'name': _(u'holder'), 'attribute': 'label'}, + {'name': _(u'holder'), 'attribute': 'widget'}, + {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_acls_for_holder(obj, x['object'])))}, + #{'name': _(u'arguments'), 'attribute': 'arguments'} + ], + #'hide_link': True, + 'hide_object': True, } if extra_context: diff --git a/apps/acls/widgets.py b/apps/acls/widgets.py new file mode 100644 index 0000000000..c35501df58 --- /dev/null +++ b/apps/acls/widgets.py @@ -0,0 +1,26 @@ +from django.utils.translation import ugettext_lazy as _ +from django.utils.safestring import mark_safe +from django import forms +from django.forms.util import flatatt +from django.utils.html import conditional_escape +from django.utils.encoding import force_unicode +from django.contrib.contenttypes.models import ContentType + +from acls.literals import CONTENT_TYPE_ICON_MAP + + +def content_type_icon(content_type): + return mark_safe(u'' % CONTENT_TYPE_ICON_MAP.get('%s.%s' % (content_type.app_label, content_type.name), 'help')) + + +def object_w_content_type_icon(obj): + content_type = ContentType.objects.get_for_model(obj) + + ct_fullname = '%s.%s' % (content_type.app_label, content_type.name) + + if ct_fullname == 'auth.user': + label = obj.get_full_name() + else: + label = unicode(obj) + + return mark_safe('%s%s' % (content_type_icon(content_type), label)) From f0f924a1d4662011dca5ee423dc6e2ce35f205a4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 20:35:32 -0400 Subject: [PATCH 007/484] Added function to return a translatable label for a permission object --- apps/permissions/api.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/permissions/api.py b/apps/permissions/api.py index 13efbbed28..aa0ab34022 100644 --- a/apps/permissions/api.py +++ b/apps/permissions/api.py @@ -22,6 +22,8 @@ namespace_titles = { 'permissions': _(u'Permissions') } +permission_titles = {} + def set_namespace_title(namespace, title): namespace_titles.setdefault(namespace, title) @@ -34,6 +36,7 @@ def register_permission(permission): namespace=permission['namespace'], name=permission['name']) permission_obj.label = unicode(permission['label']) permission_obj.save() + permission_titles['%s.%s' % (permission['namespace'], permission['name'])] = permission['label'] except DatabaseError: transaction.rollback() # Special case for ./manage.py syncdb @@ -54,6 +57,11 @@ def check_permissions(requester, permission_list): raise PermissionDenied(ugettext(u'Insufficient permissions.')) + +def get_permission_label(permission): + return unicode(permission_titles.get('%s.%s' % (permission.namespace, permission.name), permission.label)) + + register_permission(PERMISSION_ROLE_VIEW) register_permission(PERMISSION_ROLE_EDIT) register_permission(PERMISSION_ROLE_CREATE) From 4f1a234c0a7806c7793b603e1b51d00d65894697 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 20:36:09 -0400 Subject: [PATCH 008/484] Return the namespace and label of a permission object instead of just the label --- apps/permissions/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 637a59efab..59665c7ee8 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -21,7 +21,7 @@ class Permission(models.Model): verbose_name_plural = _(u'permissions') def __unicode__(self): - return self.label + return '%s: %s' % (self.namespace, self.label) def get_holders(self): return [holder.holder_object for holder in self.permissionholder_set.all()] From d45ad40233e59f90eb882d4bf44ecbe22d77fcff Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Oct 2011 20:36:52 -0400 Subject: [PATCH 009/484] Changed development admin serving rom grappelli based to a more generic django admin based --- runserver_plus.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 3f9e79f0bc02d406cbcffb75d5a503b2ff9baef6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 27 Oct 2011 07:44:51 -0400 Subject: [PATCH 010/484] Added encapsulation and semi working acl edititing view --- apps/acls/__init__.py | 6 + apps/acls/models.py | 247 +++++++++++++++++++++++++++--------------- apps/acls/urls.py | 2 + apps/acls/views.py | 116 +++++++++++++++----- 4 files changed, 255 insertions(+), 116 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 3a4c29a3aa..679830b4bf 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -1,6 +1,9 @@ from django.utils.translation import ugettext_lazy as _ from permissions.api import register_permission, set_namespace_title +from navigation.api import register_links + +from acls.models import AccessHolder ACLS_EDIT_ACL = {'namespace': 'acls', 'name': 'acl_edit', 'label': _(u'Edit ACLs')} @@ -11,3 +14,6 @@ register_permission(ACLS_EDIT_ACL) register_permission(ACLS_VIEW_ACL) acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +acl_detail = {'text': _(u'Edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} + +register_links(AccessHolder, [acl_detail]) diff --git a/apps/acls/models.py b/apps/acls/models.py index 81f2afdbb6..08e1ffc3fb 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -5,109 +5,178 @@ from django.contrib.contenttypes import generic from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse +from django.core.exceptions import ObjectDoesNotExist from permissions.models import Permission -from acls.widgets import object_w_content_type_icon +#from acls.widgets import object_w_content_type_icon +_encapsulation_cache = {} + +class EncapsulatedObject(object): + source_object_name = u'source_object' + ''' + @classmethod + def get_by_ct(cls, content_type, object_id): + """ + Return a single ACLHolder instance corresponding to the content + type object given as argument + """ + try: + return AccessHolder( + holder_object=ContentType.objects.get(content_type=access_entry.holder_type, object_id=access_entry.holder_id) + ) + except ContentType.DoesNotExits: + raise ObjectDoesNotExist + ''' + @classmethod + def set_source_object_name(cls, new_name): + cls.source_object_name = new_name + + @classmethod + def encapsulate(cls, source_object): + if source_object not in _encapsulation_cache: + encapsulated_object = cls(source_object) + _encapsulation_cache[source_object] = encapsulated_object + else: + return _encapsulation_cache[source_object] + return encapsulated_object + + @classmethod + def get(cls, gid): + app_label, model, pk = gid.split('.') + content_type = ContentType.objects.get(app_label=app_label, model=model) + source_object = content_type.get_object_for_this_type(pk=pk) + return cls.encapsulate(source_object) + + def __init__(self, source_object): + content_type = ContentType.objects.get_for_model(source_object) + self.gid = '%s.%s.%s' % (content_type.app_label, content_type.name, source_object.pk) + #self.source_object_name = self.__class__.source_object_name + #self.source_object = source_object + setattr(self, self.__class__.source_object_name, source_object) + + def __unicode__(self): + return unicode(getattr(self, self.__class__.source_object_name, None)) + + def __repr__(self): + return self.__unicode__() + + @property + def source_object(self): + return getattr(self, self.__class__.source_object_name, None) + + +class AccessHolder(EncapsulatedObject): + source_object_name = u'holder_object' + + +class AccessObject(EncapsulatedObject): + source_object_name = u'obj' + class AccessEntryManager(models.Manager): - def grant(self, permission, requester, obj): - """ - Grant a permission (what), (to) a requester, (on) a specific object - """ - access_entry, created = self.model.objects.get_or_create( - permission=permission, - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) - return created + def grant(self, permission, requester, obj): + """ + Grant a permission (what), (to) a requester, (on) a specific object + """ + access_entry, created = self.model.objects.get_or_create( + permission=permission, + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return created - def revoke(self, permission, holder, obj): - try: - access_entry = self.model.objects.get( - permission=permission, - holder_type=ContentType.objects.get_for_model(holder), - holder_id=holder.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) - access_entry.delete() - return True - except self.model.DoesNotExist: - return False + def revoke(self, permission, holder, obj): + try: + access_entry = self.model.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(holder), + holder_id=holder.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + access_entry.delete() + return True + except self.model.DoesNotExist: + return False - def check_accesses(self, permission_list, requester, obj): - for permission_item in permission_list: - permission = get_object_or_404(Permission, - namespace=permission_item['namespace'], name=permission_item['name']) - try: - access_entry = self.model.objects.get( - permission=permission, - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) - return True - except self.model.DoesNotExist: - raise PermissionDenied(ugettext(u'Insufficient permissions.')) - - def get_acl_url(self, obj): - content_type = ContentType.objects.get_for_model(obj) - return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) - - def get_holders_for(self, obj): - content_type = ContentType.objects.get_for_model(obj) - holder_list = [] - for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): - entry = { - 'object': access_entry.holder_object, - 'label': '%s: %s' % (access_entry.holder_type, access_entry.holder_object), - 'widget': object_w_content_type_icon(access_entry.holder_object), - } - if entry not in holder_list: - holder_list.append(entry) - - return holder_list + def check_accesses(self, permission_list, requester, obj): + for permission_item in permission_list: + permission = get_object_or_404(Permission, + namespace=permission_item['namespace'], name=permission_item['name']) + try: + access_entry = self.model.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return True + except self.model.DoesNotExist: + raise PermissionDenied(ugettext(u'Insufficient permissions.')) + + def get_acl_url(self, obj): + content_type = ContentType.objects.get_for_model(obj) + return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) + + def get_holders_for(self, obj): + content_type = ContentType.objects.get_for_model(obj) + holder_list = [] + for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): + #entry = { + # 'object': access_entry.holder_object, + # 'label': '%s: %s' % (access_entry.holder_type, access_entry.holder_object), + # #'widget': object_w_content_type_icon(access_entry.holder_object), + # 'compound_id': '9', + #} + #entry = ACLHolder.objects.get(content_type=access_entry.holder_type, object_id=access_entry.holder_id) + #entry = access_entry.holder_object + entry = AccessHolder.encapsulate(access_entry.holder_object) + + if entry not in holder_list: + holder_list.append(entry) + + return holder_list - def get_acls_for_holder(self, obj, holder): - holder_type = ContentType.objects.get_for_model(holder) - content_type = ContentType.objects.get_for_model(obj) - return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] + def get_permissions_for_holder(self, obj, holder): + holder_type = ContentType.objects.get_for_model(holder) + content_type = ContentType.objects.get_for_model(obj) + return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] class AccessEntry(models.Model): - permission = models.ForeignKey(Permission, verbose_name=_(u'permission')) + permission = models.ForeignKey(Permission, verbose_name=_(u'permission')) - holder_type = models.ForeignKey( - ContentType, - related_name='access_holder', - limit_choices_to={'model__in': ('user', 'group', 'role')} - ) - holder_id = models.PositiveIntegerField() - holder_object = generic.GenericForeignKey( - ct_field='holder_type', - fk_field='holder_id' - ) + holder_type = models.ForeignKey( + ContentType, + related_name='access_holder', + limit_choices_to={'model__in': ('user', 'group', 'role')} + ) + holder_id = models.PositiveIntegerField() + holder_object = generic.GenericForeignKey( + ct_field='holder_type', + fk_field='holder_id' + ) - content_type = models.ForeignKey( - ContentType, - related_name='object_content_type' - ) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey( - ct_field='content_type', - fk_field='object_id' - ) + content_type = models.ForeignKey( + ContentType, + related_name='object_content_type' + ) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey( + ct_field='content_type', + fk_field='object_id' + ) - objects = AccessEntryManager() + objects = AccessEntryManager() - class Meta: - verbose_name = _(u'access entry') - verbose_name_plural = _(u'access entries') + class Meta: + verbose_name = _(u'access entry') + verbose_name_plural = _(u'access entries') - def __unicode__(self): - return u'%s: %s' % (self.content_type, self.content_object) + def __unicode__(self): + return u'%s: %s' % (self.content_type, self.content_object) diff --git a/apps/acls/urls.py b/apps/acls/urls.py index 00baddf5ea..7dfc8c25f5 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -2,6 +2,8 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('acls.views', url(r'^list_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_list', (), 'acl_list'), + #url(r'^object/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/holder/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_detail', (), 'acl_detail'), + url(r'^details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acl_detail', (), 'acl_detail'), # url(r'^role/list/$', 'role_list', (), 'role_list'), # url(r'^role/create/$', 'role_create', (), 'role_create'), diff --git a/apps/acls/views.py b/apps/acls/views.py index 6e5671d03a..21ef01fa6f 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -9,45 +9,107 @@ from django.views.generic.create_update import create_object, delete_object, upd from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User, Group -from permissions.api import check_permissions, namespace_titles, get_permission_label +from permissions.api import check_permissions, namespace_titles, get_permission_label, get_permission_namespace_label from common.utils import generate_choices_w_labels, encapsulate from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL -from acls.models import AccessEntry +from acls.models import AccessEntry, AccessObject, AccessHolder +from acls.widgets import object_w_content_type_icon def _permission_titles(permission_list): - return u', '.join([get_permission_label(permission) for permission in permission_list]) - - + return u', '.join([get_permission_label(permission) for permission in permission_list]) + + def acl_list_for(request, obj, extra_context=None): - check_permissions(request.user, [ACLS_VIEW_ACL]) + check_permissions(request.user, [ACLS_VIEW_ACL]) - context = { - 'object_list': AccessEntry.objects.get_holders_for(obj), - 'title': _(u'access control lists for: %s' % obj), - #'multi_select_as_buttons': True, - #'hide_links': True, - 'extra_columns': [ - #{'name': _(u'holder'), 'attribute': 'label'}, - {'name': _(u'holder'), 'attribute': 'widget'}, - {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_acls_for_holder(obj, x['object'])))}, - #{'name': _(u'arguments'), 'attribute': 'arguments'} - ], - #'hide_link': True, - 'hide_object': True, - } + ct = ContentType.objects.get_for_model(obj) - if extra_context: - context.update(extra_context) + context = { + #'app_label': ct.app_label, + #'model_name': ct.model, + 'object_list': AccessEntry.objects.get_holders_for(obj), + 'title': _(u'access control lists for: %s' % obj), + #'multi_select_as_buttons': True, + #'hide_links': True, + 'extra_columns': [ + #{'name': _(u'holder'), 'attribute': 'label'}, + #{'name': _(u'obj'), 'attribute': 'holder_object'}, + {'name': _(u'gid'), 'attribute': 'gid'}, + {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, + {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_permissions_for_holder(obj, x.source_object)))}, + #{'name': _(u'arguments'), 'attribute': 'arguments'} + ], + #'hide_link': True, + #'hide_object': True, + 'access_object': AccessObject.encapsulate(obj) + } - return render_to_response('generic_list.html', context, - context_instance=RequestContext(request)) + if extra_context: + context.update(extra_context) + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) def acl_list(request, app_label, model_name, object_id): - ct = get_object_or_404(ContentType, app_label=app_label, model=model_name) - obj = get_object_or_404(ContentType.user_type.get_object_for_this_type, pk=object_id) - return acl_list_for(request, obj) + ct = get_object_or_404(ContentType, app_label=app_label, model=model_name) + obj = get_object_or_404(ct.get_object_for_this_type, pk=object_id) + return acl_list_for(request, obj) +#def acl_detail(request, app_label, model_name, object_id, holder_app_label, holder_model_name, holder_id): +def acl_detail(request, access_object_gid, holder_object_gid): + #check_permissions(request.user, [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE]) + #ct = get_object_or_404(ContentType, app_label=app_label, model=model_name) + #obj = get_object_or_404(ct.get_object_for_this_type, pk=object_id) + + #ct = get_object_or_404(ContentType, app_label=holder_app_label, model=holder_model_name) + #holder = get_object_or_404(ct.get_object_for_this_type, pk=holder_id) + + #access_entry = get_object_or_404(AccessEntry, pk=access_entry_id) + #holder = + #role = get_object_or_404(Role, pk=role_id) + #form = RoleForm_view(instance=role) + + #role_permissions_list = Permission.objects.get_for_holder(role) + + #try; + holder = AccessHolder.get(gid=holder_object_gid) + access_object = AccessObject.get(gid=access_object_gid) + #raise 404 + + subtemplates_list = [ + { + 'name': u'generic_list_subtemplate.html', + 'context': { + 'title': _(u'permissions held by: %s for %s' % (holder, access_object)), + 'object_list': AccessEntry.objects.get_permissions_for_holder(access_object.source_object, holder.source_object), + 'extra_columns': [ + {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: get_permission_namespace_label(x))}, + {'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))}, + #{ + # 'name':_(u'has permission'), + # 'attribute': encapsulate(lambda x: two_state_template(x.has_permission(role))), + #}, + ], + #'hide_link': True, + #'hide_object': True, + } + }, + ] + + return render_to_response('generic_detail.html', { + #'form': form, + 'object': access_object.obj, + 'object_name': _(u'object'), + 'subtemplates_list': subtemplates_list, + #'multi_select_as_buttons': True, + #'multi_select_item_properties': { + # 'permission_id': lambda x: x.pk, + # 'requester_id': lambda x: role.pk, + # 'requester_app_label': lambda x: ContentType.objects.get_for_model(role).app_label, + # 'requester_model': lambda x: ContentType.objects.get_for_model(role).model, + #}, + }, context_instance=RequestContext(request)) From 548abaaf70b2a251ebf8d77ab4723c34bab5d56f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 27 Oct 2011 07:45:26 -0400 Subject: [PATCH 011/484] Added get_permission_namespace_label helper function --- apps/permissions/api.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/permissions/api.py b/apps/permissions/api.py index aa0ab34022..c74cfe5e67 100644 --- a/apps/permissions/api.py +++ b/apps/permissions/api.py @@ -61,7 +61,11 @@ def check_permissions(requester, permission_list): def get_permission_label(permission): return unicode(permission_titles.get('%s.%s' % (permission.namespace, permission.name), permission.label)) - + +def get_permission_namespace_label(permission): + return namespace_titles[permission.namespace] if permission.namespace in namespace_titles else permission.namespace + + register_permission(PERMISSION_ROLE_VIEW) register_permission(PERMISSION_ROLE_EDIT) register_permission(PERMISSION_ROLE_CREATE) From 0c512ccaec4ccfb2a736d6e8f8885a21b0231e9e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 28 Oct 2011 21:47:46 -0400 Subject: [PATCH 012/484] Use source class as a cache namespace, more expesive lookups to the encapsulate method and made the get method lightweight --- apps/acls/models.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index 08e1ffc3fb..713309f029 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -34,20 +34,29 @@ class EncapsulatedObject(object): cls.source_object_name = new_name @classmethod - def encapsulate(cls, source_object): - if source_object not in _encapsulation_cache: + def encapsulate(cls, source_object=None, app_label=None, model=None, pk=None): + if source_object: + content_type = ContentType.objects.get_for_model(source_object) + elif app_label and model and pk: + content_type = ContentType.objects.get(app_label=app_label, model=model) + source_object = content_type.get_object_for_this_type(pk=pk) + + object_id = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) + if object_id not in _encapsulation_cache: encapsulated_object = cls(source_object) - _encapsulation_cache[source_object] = encapsulated_object + _encapsulation_cache[object_id] = encapsulated_object else: - return _encapsulation_cache[source_object] + return _encapsulation_cache[object_id] return encapsulated_object @classmethod def get(cls, gid): app_label, model, pk = gid.split('.') - content_type = ContentType.objects.get(app_label=app_label, model=model) - source_object = content_type.get_object_for_this_type(pk=pk) - return cls.encapsulate(source_object) + object_id = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) + try: + return _encapsulation_cache[object_id] + except KeyError: + return cls.encapsulate(app_label=app_label, model=model, pk=pk) def __init__(self, source_object): content_type = ContentType.objects.get_for_model(source_object) From e048711d824dc0ebb04b44baea6c2db6af0900a0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:23:33 -0400 Subject: [PATCH 013/484] Updated permissions app to only return active permissions on the views and querysets --- apps/permissions/api.py | 7 +------ apps/permissions/managers.py | 16 +++++++++++++++- apps/permissions/views.py | 8 ++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/apps/permissions/api.py b/apps/permissions/api.py index c74cfe5e67..4b469d092d 100644 --- a/apps/permissions/api.py +++ b/apps/permissions/api.py @@ -17,12 +17,7 @@ from permissions import PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, \ PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE from permissions.models import Permission - -namespace_titles = { - 'permissions': _(u'Permissions') -} - -permission_titles = {} +from permissions.runtime import namespace_titles, permission_titles def set_namespace_title(namespace, title): diff --git a/apps/permissions/managers.py b/apps/permissions/managers.py index e4cfd1fdf5..919bb720bd 100644 --- a/apps/permissions/managers.py +++ b/apps/permissions/managers.py @@ -1,6 +1,8 @@ from django.db import models from django.contrib.contenttypes.models import ContentType +from permissions.runtime import permission_titles + class RoleMemberManager(models.Manager): def get_roles_for_member(self, member_obj): @@ -11,4 +13,16 @@ class RoleMemberManager(models.Manager): class PermissionManager(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) + return self.model.objects.active_only().filter(permissionholder__holder_type=ct).filter(permissionholder__holder_id=holder.pk) + + def active_only(self): + namespaces = [] + names = [] + for key in permission_titles: + namespace, name = key.split(u'.') + if namespace: + namespaces.append(namespace) + if name: + names.append(name) + + return super(PermissionManager, self).get_query_set().filter(namespace__in=namespaces).filter(name__in=names).exclude(label=u'') diff --git a/apps/permissions/views.py b/apps/permissions/views.py index df7b8c847b..7199cc6e33 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -22,7 +22,7 @@ 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.api import check_permissions, namespace_titles, get_permission_label, get_permission_namespace_label from permissions.widgets import role_permission_link @@ -52,10 +52,10 @@ def role_permissions(request, role_id): 'name': u'generic_list_subtemplate.html', 'context': { 'title': _(u'permissions'), - 'object_list': Permission.objects.all(), + 'object_list': Permission.objects.active_only(), '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: get_permission_namespace_label(x))}, + {'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))}, { 'name':_(u'has permission'), 'attribute': encapsulate(lambda x: two_state_template(x.has_permission(role))), From c9d1b225fdb5290d93dd4145d17f6711c84d8dbb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:24:35 -0400 Subject: [PATCH 014/484] Improved the return_type function --- apps/common/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/common/utils.py b/apps/common/utils.py index 61973996ac..c60c0ac1e1 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- + # -*- coding: utf-8 -*- import os import re import types @@ -288,11 +288,11 @@ def return_type(value): if isinstance(value, types.FunctionType): return value.__doc__ if value.__doc__ else _(u'function found') elif isinstance(value, types.ClassType): - return _(u'class found: %s') % unicode(value).split("'")[1].split('.')[-1] + return u'%s.%s' % (value.__class__.__module__, value.__class__.__name__) elif isinstance(value, types.TypeType): - return _(u'class found: %s') % unicode(value).split("'")[1].split('.')[-1] + return u'%s.%s' % (value.__module__, value.__name__) elif isinstance(value, types.DictType) or isinstance(value, types.DictionaryType): - return ','.join(list(value)) + return u', '.join(list(value)) else: return value From fb9f467804de09c229210da30bee3657494a9a95 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:24:59 -0400 Subject: [PATCH 015/484] Moved runtime memory structures to their on module to avoid circular imports --- apps/permissions/runtime.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 apps/permissions/runtime.py diff --git a/apps/permissions/runtime.py b/apps/permissions/runtime.py new file mode 100644 index 0000000000..a56d8cfeb4 --- /dev/null +++ b/apps/permissions/runtime.py @@ -0,0 +1,8 @@ +from django.utils.translation import ugettext_lazy as _ + + +namespace_titles = { + 'permissions': _(u'Permissions') +} + +permission_titles = {} From 0c87b3356fee2fb9b914c9ca2cd2d7be6f1aceef Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:25:59 -0400 Subject: [PATCH 016/484] Improved the check_permissions_for_holder method, made method admin and staff users aware --- apps/acls/models.py | 125 ++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 50 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index 713309f029..8d1c343b0a 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -1,34 +1,37 @@ +import sys +import types + 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 django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import get_object_or_404 from permissions.models import Permission -#from acls.widgets import object_w_content_type_icon +_cache = {} -_encapsulation_cache = {} class EncapsulatedObject(object): source_object_name = u'source_object' - ''' + + #@classmethod + #def __new__(cls, *args, **kwargs): + # cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) + # return super(EncapsulatedObject, cls).__new__(*args, **kwargs) + @classmethod - def get_by_ct(cls, content_type, object_id): - """ - Return a single ACLHolder instance corresponding to the content - type object given as argument - """ - try: - return AccessHolder( - holder_object=ContentType.objects.get(content_type=access_entry.holder_type, object_id=access_entry.holder_id) - ) - except ContentType.DoesNotExits: - raise ObjectDoesNotExist - ''' + def add_to_class(cls, name, value): + if hasattr(value, 'contribute_to_class'): + value.contribute_to_class(cls, name) + else: + setattr(cls, name, value) + @classmethod def set_source_object_name(cls, new_name): cls.source_object_name = new_name @@ -38,31 +41,40 @@ class EncapsulatedObject(object): if source_object: content_type = ContentType.objects.get_for_model(source_object) elif app_label and model and pk: - content_type = ContentType.objects.get(app_label=app_label, model=model) - source_object = content_type.get_object_for_this_type(pk=pk) - - object_id = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) - if object_id not in _encapsulation_cache: + try: + content_type = ContentType.objects.get(app_label=app_label, model=model) + source_object_model_class = content_type.model_class() + source_object = content_type.get_object_for_this_type(pk=pk) + except ContentType.DoesNotExist: + #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) + #raise cls.DoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) + raise ObjectDoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) + except source_object_model_class.DoesNotExist: + #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) + #raise cls.DoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) + raise ObjectDoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) + + object_key = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) + + try: + return _cache[object_key] + except KeyError: encapsulated_object = cls(source_object) - _encapsulation_cache[object_id] = encapsulated_object - else: - return _encapsulation_cache[object_id] - return encapsulated_object + _cache[object_key] = encapsulated_object + return encapsulated_object @classmethod def get(cls, gid): app_label, model, pk = gid.split('.') - object_id = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) + object_key = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) try: - return _encapsulation_cache[object_id] + return _cache[object_key] except KeyError: return cls.encapsulate(app_label=app_label, model=model, pk=pk) def __init__(self, source_object): content_type = ContentType.objects.get_for_model(source_object) self.gid = '%s.%s.%s' % (content_type.app_label, content_type.name, source_object.pk) - #self.source_object_name = self.__class__.source_object_name - #self.source_object = source_object setattr(self, self.__class__.source_object_name, source_object) def __unicode__(self): @@ -112,21 +124,28 @@ class AccessEntryManager(models.Manager): except self.model.DoesNotExist: return False - def check_accesses(self, permission_list, requester, obj): - for permission_item in permission_list: - permission = get_object_or_404(Permission, - namespace=permission_item['namespace'], name=permission_item['name']) - try: - access_entry = self.model.objects.get( - permission=permission, - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) + def has_accesses(self, permission, requester, obj): + if isinstance(requester, User): + if requester.is_superuser or requester.is_staff: return True - except self.model.DoesNotExist: - raise PermissionDenied(ugettext(u'Insufficient permissions.')) + + try: + access_entry = self.model.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return True + except self.model.DoesNotExist: + return False + + def check_access(self, permission, requester, obj): + if has_accesses(permission, requester, obj): + return True + else: + raise PermissionDenied(ugettext(u'Insufficient permissions.')) def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) @@ -136,14 +155,6 @@ class AccessEntryManager(models.Manager): content_type = ContentType.objects.get_for_model(obj) holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): - #entry = { - # 'object': access_entry.holder_object, - # 'label': '%s: %s' % (access_entry.holder_type, access_entry.holder_object), - # #'widget': object_w_content_type_icon(access_entry.holder_object), - # 'compound_id': '9', - #} - #entry = ACLHolder.objects.get(content_type=access_entry.holder_type, object_id=access_entry.holder_id) - #entry = access_entry.holder_object entry = AccessHolder.encapsulate(access_entry.holder_object) if entry not in holder_list: @@ -152,6 +163,10 @@ class AccessEntryManager(models.Manager): return holder_list def get_permissions_for_holder(self, obj, holder): + if isinstance(holder, User): + if holder.is_superuser or holder.is_staff: + return Permission.objects.active_only() + holder_type = ContentType.objects.get_for_model(holder) content_type = ContentType.objects.get_for_model(obj) return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] @@ -189,3 +204,13 @@ class AccessEntry(models.Model): def __unicode__(self): return u'%s: %s' % (self.content_type, self.content_object) + + +if sys.version_info < (2, 5): + # Prior to Python 2.5, Exception was an old-style class + def subclass_exception(name, parents, unused): + return types.ClassType(name, parents, {}) +else: + def subclass_exception(name, parents, module): + return type(name, parents, {'__module__': module}) + From b472383bc0e6fbc62132df2a0a40ba8d6dda31d2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:26:48 -0400 Subject: [PATCH 017/484] Only show the permissions the users hold on the ACL edit view --- apps/acls/views.py | 51 +++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index 21ef01fa6f..df6b0c4a2c 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -1,5 +1,5 @@ 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 @@ -8,9 +8,11 @@ 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.core.exceptions import ObjectDoesNotExist from permissions.api import check_permissions, namespace_titles, get_permission_label, get_permission_namespace_label from common.utils import generate_choices_w_labels, encapsulate +from common.widgets import two_state_template from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL from acls.models import AccessEntry, AccessObject, AccessHolder @@ -22,7 +24,7 @@ def _permission_titles(permission_list): def acl_list_for(request, obj, extra_context=None): - check_permissions(request.user, [ACLS_VIEW_ACL]) + #check_permissions(request.user, [ACLS_VIEW_ACL]) ct = ContentType.objects.get_for_model(obj) @@ -36,13 +38,13 @@ def acl_list_for(request, obj, extra_context=None): 'extra_columns': [ #{'name': _(u'holder'), 'attribute': 'label'}, #{'name': _(u'obj'), 'attribute': 'holder_object'}, - {'name': _(u'gid'), 'attribute': 'gid'}, + #{'name': _(u'gid'), 'attribute': 'gid'}, {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_permissions_for_holder(obj, x.source_object)))}, #{'name': _(u'arguments'), 'attribute': 'arguments'} ], #'hide_link': True, - #'hide_object': True, + 'hide_object': True, 'access_object': AccessObject.encapsulate(obj) } @@ -59,43 +61,33 @@ def acl_list(request, app_label, model_name, object_id): return acl_list_for(request, obj) -#def acl_detail(request, app_label, model_name, object_id, holder_app_label, holder_model_name, holder_id): def acl_detail(request, access_object_gid, holder_object_gid): - #check_permissions(request.user, [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE]) - #ct = get_object_or_404(ContentType, app_label=app_label, model=model_name) - #obj = get_object_or_404(ct.get_object_for_this_type, pk=object_id) - - #ct = get_object_or_404(ContentType, app_label=holder_app_label, model=holder_model_name) - #holder = get_object_or_404(ct.get_object_for_this_type, pk=holder_id) - - #access_entry = get_object_or_404(AccessEntry, pk=access_entry_id) - #holder = - #role = get_object_or_404(Role, pk=role_id) - #form = RoleForm_view(instance=role) - - #role_permissions_list = Permission.objects.get_for_holder(role) - - #try; - holder = AccessHolder.get(gid=holder_object_gid) - access_object = AccessObject.get(gid=access_object_gid) - #raise 404 + #check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) + try: + holder = AccessHolder.get(gid=holder_object_gid) + access_object = AccessObject.get(gid=access_object_gid) + except ObjectDoesNotExist: + raise Http404 + + permission_list = list(set(AccessEntry.objects.get_permissions_for_holder(access_object.source_object, request.user))) + #TODO : get all globalluy assignes permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { 'name': u'generic_list_subtemplate.html', 'context': { 'title': _(u'permissions held by: %s for %s' % (holder, access_object)), - 'object_list': AccessEntry.objects.get_permissions_for_holder(access_object.source_object, holder.source_object), + 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: get_permission_namespace_label(x))}, {'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))}, - #{ - # 'name':_(u'has permission'), - # 'attribute': encapsulate(lambda x: two_state_template(x.has_permission(role))), - #}, + { + 'name':_(u'has permission'), + 'attribute': encapsulate(lambda x: two_state_template(AccessEntry.objects.has_accesses(x, holder.source_object, access_object.source_object))) + }, ], #'hide_link': True, - #'hide_object': True, + 'hide_object': True, } }, ] @@ -103,7 +95,6 @@ def acl_detail(request, access_object_gid, holder_object_gid): return render_to_response('generic_detail.html', { #'form': form, 'object': access_object.obj, - 'object_name': _(u'object'), 'subtemplates_list': subtemplates_list, #'multi_select_as_buttons': True, #'multi_select_item_properties': { From ffc3b2c1b2e2612ac5ac7f78a6b1e9a709754a09 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:28:22 -0400 Subject: [PATCH 018/484] Changed app order in settings.py file --- settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings.py b/settings.py index 9fb0fe96e6..c281b22988 100644 --- a/settings.py +++ b/settings.py @@ -126,6 +126,7 @@ INSTALLED_APPS = ( 'django.contrib.admindocs', 'django.contrib.comments', 'django.contrib.staticfiles', + 'permissions', 'project_setup', 'project_tools', 'smart_settings', @@ -133,13 +134,12 @@ INSTALLED_APPS = ( 'lock_manager', 'web_theme', 'common', - 'acls', 'metadata', 'pagination', 'dynamic_search', 'filetransfers', + 'acls', 'converter', - 'permissions', 'djcelery', 'indexer', 'paging', From e22f6c22949fb2d45057c5f36043e5c5629ec77d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:28:56 -0400 Subject: [PATCH 019/484] Removed object_name inline with the other apps --- apps/document_acls/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 879e30fcf4..4b20a038ee 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -13,6 +13,5 @@ def document_acl_list(request, document_id): document, extra_context={ 'object': document, - 'object_name': _(u'document'), } ) From 3bf0bb268fd43aae338524fa29b19d76106dd770 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:29:33 -0400 Subject: [PATCH 020/484] Disabled checking for permissions for the acl views, temporarily --- apps/document_acls/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index c83609ef16..ec449dac37 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -4,9 +4,7 @@ from documents.models import Document from navigation.api import register_links, register_multi_item_links from project_setup.api import register_setup -from acls import ACLS_VIEW_ACL - - -acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +#from acls import ACLS_VIEW_ACL +acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} register_links(Document, [acl_list], menu_name='form_header') From 8a27b1866bb50e78e80a86486befa834accadbd5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 29 Oct 2011 02:34:38 -0400 Subject: [PATCH 021/484] Removed imported wrongly copied file --- apps/acls/api.py | 62 ------------------------------------------------ 1 file changed, 62 deletions(-) delete mode 100644 apps/acls/api.py diff --git a/apps/acls/api.py b/apps/acls/api.py deleted file mode 100644 index 13efbbed28..0000000000 --- a/apps/acls/api.py +++ /dev/null @@ -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) From 2b3629f8995f7069a5ca1b6136f4f544be61677e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 3 Nov 2011 12:03:47 -0400 Subject: [PATCH 022/484] Return translatable permission labels and permission namespace label straight from the model --- apps/permissions/models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 59665c7ee8..8cc7c2f354 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -5,6 +5,7 @@ from django.contrib.contenttypes import generic from django.contrib.auth.models import User from permissions.managers import RoleMemberManager, PermissionManager +from permissions.runtime import namespace_titles, permission_titles class Permission(models.Model): @@ -21,7 +22,7 @@ class Permission(models.Model): verbose_name_plural = _(u'permissions') def __unicode__(self): - return '%s: %s' % (self.namespace, self.label) + return u'%s: %s' % (self.get_namespace_label(), self.get_label()) def get_holders(self): return [holder.holder_object for holder in self.permissionholder_set.all()] @@ -60,6 +61,12 @@ class Permission(models.Model): except PermissionHolder.DoesNotExist: return False + def get_label(self): + return unicode(permission_titles.get('%s.%s' % (self.namespace, self.name), self.label)) + + def get_namespace_label(self): + return unicode(namespace_titles[self.namespace]) if self.namespace in namespace_titles else self.namespace + class PermissionHolder(models.Model): permission = models.ForeignKey(Permission, verbose_name=_(u'permission')) From 1557ae829bf1d5b3279e80fbc4072b0dccb6a08b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 3 Nov 2011 12:04:35 -0400 Subject: [PATCH 023/484] ACL grant view updates --- apps/acls/__init__.py | 6 ++- apps/acls/urls.py | 2 +- apps/acls/views.py | 111 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 11 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 679830b4bf..6406ea087a 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -1,7 +1,7 @@ from django.utils.translation import ugettext_lazy as _ from permissions.api import register_permission, set_namespace_title -from navigation.api import register_links +from navigation.api import register_links, register_multi_item_links from acls.models import AccessHolder @@ -14,6 +14,8 @@ register_permission(ACLS_EDIT_ACL) register_permission(ACLS_VIEW_ACL) acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -acl_detail = {'text': _(u'Edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} register_links(AccessHolder, [acl_detail]) +register_multi_item_links(['acl_detail'], [acl_grant])#, permission_revoke]) diff --git a/apps/acls/urls.py b/apps/acls/urls.py index 7dfc8c25f5..1570140c5e 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -12,6 +12,6 @@ urlpatterns = patterns('acls.views', # 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'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), # url(r'^permissions/multiple/revoke/$', 'permission_revoke', (), 'permission_multiple_revoke'), ) diff --git a/apps/acls/views.py b/apps/acls/views.py index df6b0c4a2c..eab8f25f73 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -1,3 +1,6 @@ +import operator +import itertools + from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect, Http404 from django.shortcuts import render_to_response, get_object_or_404 @@ -9,8 +12,10 @@ from django.views.generic.create_update import create_object, delete_object, upd from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User, Group from django.core.exceptions import ObjectDoesNotExist +from django.utils.simplejson import loads from permissions.api import check_permissions, namespace_titles, get_permission_label, get_permission_namespace_label +from permissions.models import Permission from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template @@ -71,7 +76,7 @@ def acl_detail(request, access_object_gid, holder_object_gid): raise Http404 permission_list = list(set(AccessEntry.objects.get_permissions_for_holder(access_object.source_object, request.user))) - #TODO : get all globalluy assignes permission, new function get_permissions_for_holder (roles aware) + #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { 'name': u'generic_list_subtemplate.html', @@ -96,11 +101,101 @@ def acl_detail(request, access_object_gid, holder_object_gid): #'form': form, 'object': access_object.obj, 'subtemplates_list': subtemplates_list, - #'multi_select_as_buttons': True, - #'multi_select_item_properties': { - # 'permission_id': lambda x: x.pk, - # 'requester_id': lambda x: role.pk, - # 'requester_app_label': lambda x: ContentType.objects.get_for_model(role).app_label, - # 'requester_model': lambda x: ContentType.objects.get_for_model(role).model, - #}, + 'multi_select_as_buttons': True, + 'multi_select_item_properties': { + 'permission_pk': lambda x: x.pk, + 'holder_gid': lambda x: holder.gid, + 'object_gid': lambda x: access_object.gid, + #'requester_id': lambda x: role.pk, + #'requester_app_label': lambda x: ContentType.objects.get_for_model(role).app_label, + #'requester_model': lambda x: ContentType.objects.get_for_model(role).model, + }, }, context_instance=RequestContext(request)) + + +def acl_grant(request): + check_permissions(request.user, [ACLS_EDIT_ACL]) + items_property_list = loads(request.GET.get('items_property_list', [])) + post_action_redirect = None + + 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))) + + items = {} + for item_properties in items_property_list: + permission = get_object_or_404(Permission, pk=item_properties['permission_pk']) + try: + requester = AccessHolder.get(gid=item_properties['holder_gid']) + access_object = AccessObject.get(gid=item_properties['object_gid']) + except ObjectDoesNotExist: + raise Http404 + + items.setdefault(requester, {}) + items[requester].setdefault(access_object, []) + items[requester][access_object].append(permission) + + title_suffix = [] + for requester, access_objects_dict in items.items(): + title_suffix.append(unicode(requester)) + for access_object, permissions in access_objects_dict.items(): + if len(permissions) == 1: + permissions_label = _(u'permission') + else: + permissions_label = _(u'permissions') + + title_suffix.append(permission for permission in permissions) + + + title_suffix.append(unicode(access_object)) + #title_suffix.append(_(u'the permissions')) + + + #items = access_objects[access_object] + #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] + + #title_suffix + # Warning: trial and error black magic ahead + #title_suffix.append(_(u' and ').join([_(u'%s to %s') % (', '.join(['"%s"' % unicode(ps) for ps in p]), 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: + # permissions_label = _(u'permissions') + #title_suffix.append(_(t + + print title_suffix + #title_suffix = _(u' and ').join(title_suffix) + permissions_label = _(u'permissions') + + if request.method == 'POST': + for item in items: + if item['permission'].grant_to(item['requester']): + messages.success(request, _(u'Permission "%(permission)s" granted to: %(requester)s.') % { + 'permission': item['permission'], 'requester': item['requester']}) + else: + messages.warning(request, _(u'%(requester)s, already had the permission "%(permission)s" granted.') % { + 'requester': item['requester'], 'permission': item['permission']}) + + return HttpResponseRedirect(next) + + context = { + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'key_add.png', + } + + context['title'] = _(u'Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?') % { + '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)) From 30f668b8764f9af348f1089174025c1f9978dab1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 7 Dec 2011 04:51:50 -0400 Subject: [PATCH 024/484] Fix statistics --- apps/documents/statistics.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/documents/statistics.py b/apps/documents/statistics.py index 786f902651..8787c7eb22 100644 --- a/apps/documents/statistics.py +++ b/apps/documents/statistics.py @@ -3,7 +3,7 @@ from django.utils.translation import ugettext_lazy as _ from common.utils import pretty_size, pretty_size_10 from documents.conf.settings import STORAGE_BACKEND -from documents.models import Document, DocumentType, DocumentPage +from documents.models import Document, DocumentType, DocumentPage, DocumentVersion from django.db.models import Avg, Count, Min, Max @@ -54,9 +54,9 @@ def get_statistics(): paragraphs.extend( [ _(u'Document pages in database: %d') % DocumentPage.objects.only('pk',).count(), - _(u'Minimum amount of pages per document: %(page_count__min)d') % Document.objects.annotate(page_count=Count('documentpage')).aggregate(Min('page_count')), - _(u'Maximum amount of pages per document: %(page_count__max)d') % Document.objects.annotate(page_count=Count('documentpage')).aggregate(Max('page_count')), - _(u'Average amount of pages per document: %(page_count__avg)f') % Document.objects.annotate(page_count=Count('documentpage')).aggregate(Avg('page_count')), + _(u'Minimum amount of pages per document: %(page_count__min)d') % DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Min('page_count')), + _(u'Maximum amount of pages per document: %(page_count__max)d') % DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Max('page_count')), + _(u'Average amount of pages per document: %(page_count__avg)f') % DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Avg('page_count')), ] ) #[(day_count['date_added'].strftime('%Y-%m-%d'), day_count['id__count']) for day_count in Document.objects.values('date_added').annotate(Count("id"))] From e6ae00d357cea98e380690b119d747606c265375 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 7 Dec 2011 15:51:28 -0400 Subject: [PATCH 025/484] Update Transifex configuration file to add the Italian language resources --- .tx/config | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.tx/config b/.tx/config index acbc95abba..0ee87646bb 100644 --- a/.tx/config +++ b/.tx/config @@ -4,6 +4,7 @@ source_lang = en trans.es = apps/converter/locale/es/LC_MESSAGES/django.po trans.pt = apps/converter/locale/pt/LC_MESSAGES/django.po trans.ru = apps/converter/locale/ru/LC_MESSAGES/django.po +trans.it = apps/converter/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-common] source_file = apps/common/locale/en/LC_MESSAGES/django.po @@ -11,6 +12,7 @@ source_lang = en trans.es = apps/common/locale/es/LC_MESSAGES/django.po trans.pt = apps/common/locale/pt/LC_MESSAGES/django.po trans.ru = apps/common/locale/ru/LC_MESSAGES/django.po +trans.it = apps/common/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-permissions] source_file = apps/permissions/locale/en/LC_MESSAGES/django.po @@ -18,6 +20,7 @@ source_lang = en trans.es = apps/permissions/locale/es/LC_MESSAGES/django.po trans.pt = apps/permissions/locale/pt/LC_MESSAGES/django.po trans.ru = apps/permissions/locale/ru/LC_MESSAGES/django.po +trans.it = apps/permissions/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-sources] source_file = apps/sources/locale/en/LC_MESSAGES/django.po @@ -25,6 +28,7 @@ source_lang = en trans.es = apps/sources/locale/es/LC_MESSAGES/django.po trans.pt = apps/sources/locale/pt/LC_MESSAGES/django.po trans.ru = apps/sources/locale/ru/LC_MESSAGES/django.po +trans.it = apps/sources/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-document_indexing] source_file = apps/document_indexing/locale/en/LC_MESSAGES/django.po @@ -32,6 +36,7 @@ source_lang = en trans.es = apps/document_indexing/locale/es/LC_MESSAGES/django.po trans.pt = apps/document_indexing/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_indexing/locale/ru/LC_MESSAGES/django.po +trans.it = apps/document_indexing/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-user_management] source_file = apps/user_management/locale/en/LC_MESSAGES/django.po @@ -39,6 +44,7 @@ source_lang = en trans.es = apps/user_management/locale/es/LC_MESSAGES/django.po trans.pt = apps/user_management/locale/pt/LC_MESSAGES/django.po trans.ru = apps/user_management/locale/ru/LC_MESSAGES/django.po +trans.it = apps/user_management/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-main] source_file = apps/main/locale/en/LC_MESSAGES/django.po @@ -46,6 +52,7 @@ source_lang = en trans.es = apps/main/locale/es/LC_MESSAGES/django.po trans.pt = apps/main/locale/pt/LC_MESSAGES/django.po trans.ru = apps/main/locale/ru/LC_MESSAGES/django.po +trans.it = apps/main/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-ocr] source_file = apps/ocr/locale/en/LC_MESSAGES/django.po @@ -53,6 +60,7 @@ source_lang = en trans.es = apps/ocr/locale/es/LC_MESSAGES/django.po trans.pt = apps/ocr/locale/pt/LC_MESSAGES/django.po trans.ru = apps/ocr/locale/ru/LC_MESSAGES/django.po +trans.it = apps/ocr/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-project_setup] source_file = apps/project_setup/locale/en/LC_MESSAGES/django.po @@ -60,6 +68,7 @@ source_lang = en trans.es = apps/project_setup/locale/es/LC_MESSAGES/django.po trans.pt = apps/project_setup/locale/pt/LC_MESSAGES/django.po trans.ru = apps/project_setup/locale/ru/LC_MESSAGES/django.po +trans.it = apps/project_setup/locale/it/LC_MESSAGES/django.po [main] host = https://www.transifex.net @@ -70,6 +79,7 @@ source_lang = en trans.es = apps/folders/locale/es/LC_MESSAGES/django.po trans.pt = apps/folders/locale/pt/LC_MESSAGES/django.po trans.ru = apps/folders/locale/ru/LC_MESSAGES/django.po +trans.it = apps/folders/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-history] source_file = apps/history/locale/en/LC_MESSAGES/django.po @@ -77,6 +87,7 @@ source_lang = en trans.es = apps/history/locale/es/LC_MESSAGES/django.po trans.pt = apps/history/locale/pt/LC_MESSAGES/django.po trans.ru = apps/history/locale/ru/LC_MESSAGES/django.po +trans.it = apps/history/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-dynamic_search] source_file = apps/dynamic_search/locale/en/LC_MESSAGES/django.po @@ -84,6 +95,7 @@ source_lang = en trans.es = apps/dynamic_search/locale/es/LC_MESSAGES/django.po trans.pt = apps/dynamic_search/locale/pt/LC_MESSAGES/django.po trans.ru = apps/dynamic_search/locale/ru/LC_MESSAGES/django.po +trans.it = apps/dynamic_search/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-smart_settings] source_file = apps/smart_settings/locale/en/LC_MESSAGES/django.po @@ -91,6 +103,7 @@ source_lang = en trans.es = apps/smart_settings/locale/es/LC_MESSAGES/django.po trans.pt = apps/smart_settings/locale/pt/LC_MESSAGES/django.po trans.ru = apps/smart_settings/locale/ru/LC_MESSAGES/django.po +trans.it = apps/smart_settings/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-navigation] source_file = apps/navigation/locale/en/LC_MESSAGES/django.po @@ -98,6 +111,7 @@ source_lang = en trans.es = apps/navigation/locale/es/LC_MESSAGES/django.po trans.pt = apps/navigation/locale/pt/LC_MESSAGES/django.po trans.ru = apps/navigation/locale/ru/LC_MESSAGES/django.po +trans.it = apps/navigation/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-tags] source_file = apps/tags/locale/en/LC_MESSAGES/django.po @@ -105,6 +119,7 @@ source_lang = en trans.es = apps/tags/locale/es/LC_MESSAGES/django.po trans.pt = apps/tags/locale/pt/LC_MESSAGES/django.po trans.ru = apps/tags/locale/ru/LC_MESSAGES/django.po +trans.it = apps/tags/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-documents] source_file = apps/documents/locale/en/LC_MESSAGES/django.po @@ -112,6 +127,7 @@ source_lang = en trans.es = apps/documents/locale/es/LC_MESSAGES/django.po trans.pt = apps/documents/locale/pt/LC_MESSAGES/django.po trans.ru = apps/documents/locale/ru/LC_MESSAGES/django.po +trans.it = apps/documents/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-project_tools] source_file = apps/project_tools/locale/en/LC_MESSAGES/django.po @@ -119,6 +135,7 @@ source_lang = en trans.es = apps/project_tools/locale/es/LC_MESSAGES/django.po trans.pt = apps/project_tools/locale/pt/LC_MESSAGES/django.po trans.ru = apps/project_tools/locale/ru/LC_MESSAGES/django.po +trans.it = apps/project_tools/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-linking] source_file = apps/linking/locale/en/LC_MESSAGES/django.po @@ -126,6 +143,7 @@ source_lang = en trans.es = apps/linking/locale/es/LC_MESSAGES/django.po trans.pt = apps/linking/locale/pt/LC_MESSAGES/django.po trans.ru = apps/linking/locale/ru/LC_MESSAGES/django.po +trans.it = apps/linking/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-document_comments] source_file = apps/document_comments/locale/en/LC_MESSAGES/django.po @@ -133,6 +151,7 @@ source_lang = en trans.es = apps/document_comments/locale/es/LC_MESSAGES/django.po trans.pt = apps/document_comments/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_comments/locale/ru/LC_MESSAGES/django.po +trans.it = apps/document_comments/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-metadata] source_file = apps/metadata/locale/en/LC_MESSAGES/django.po @@ -140,6 +159,7 @@ source_lang = en trans.es = apps/metadata/locale/es/LC_MESSAGES/django.po trans.pt = apps/metadata/locale/pt/LC_MESSAGES/django.po trans.ru = apps/metadata/locale/ru/LC_MESSAGES/django.po +trans.it = apps/metadata/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-web_theme] source_file = apps/web_theme/locale/en/LC_MESSAGES/django.po @@ -147,6 +167,7 @@ source_lang = en trans.es = apps/web_theme/locale/es/LC_MESSAGES/django.po trans.pt = apps/web_theme/locale/pt/LC_MESSAGES/django.po trans.ru = apps/web_theme/locale/ru/LC_MESSAGES/django.po +trans.it = apps/web_theme/locale/it/LC_MESSAGES/django.po [mayan-edms.apps-django_gpg] source_file = apps/django_gpg/locale/en/LC_MESSAGES/django.po @@ -154,3 +175,4 @@ source_lang = en trans.es = apps/django_gpg/locale/es/LC_MESSAGES/django.po trans.pt = apps/django_gpg/locale/pt/LC_MESSAGES/django.po trans.ru = apps/django_gpg/locale/ru/LC_MESSAGES/django.po +trans.it = apps/django_gpg/locale/it/LC_MESSAGES/django.po From 6c8e20e783e210d0802ffd5666360d1a1b9a52d1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 7 Dec 2011 15:51:54 -0400 Subject: [PATCH 026/484] Add Italian language to the language helper scripts --- misc/compilemessages_all.sh | 22 ++++++++++++++++++++++ misc/makemessages_all.sh | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index 5e3c5cf2a7..a6abd085c7 100755 --- a/misc/compilemessages_all.sh +++ b/misc/compilemessages_all.sh @@ -7,108 +7,130 @@ cd $BASE/apps/common $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/converter $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/documents $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/document_comments $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/document_indexing $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/dynamic_search $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/folders $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/history $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/linking $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/main $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/metadata $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/navigation $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/ocr $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/permissions $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/project_setup $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/project_tools $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/smart_settings $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/sources $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/tags $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/user_management $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/web_theme $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it cd $BASE/apps/django_gpg $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh index d1e0fcd79e..3cc25f2a01 100755 --- a/misc/makemessages_all.sh +++ b/misc/makemessages_all.sh @@ -8,129 +8,151 @@ $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/converter $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/documents $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/document_comments $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/document_indexing $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/dynamic_search $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/folders $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/history $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/linking $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/main $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/metadata $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/navigation $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/ocr $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/permissions $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/project_setup $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/project_tools $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/smart_settings $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/sources $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/tags $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/user_management $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/web_theme $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it cd $BASE/apps/django_gpg $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es +$MAKEMESSAGES -l it From 9daa442e7152ebe0223dbd6910b34894904ecad1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 7 Dec 2011 15:52:18 -0400 Subject: [PATCH 027/484] Add Italian to the language selection list --- settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.py b/settings.py index bd59969f15..2620793172 100644 --- a/settings.py +++ b/settings.py @@ -53,6 +53,7 @@ LANGUAGES = ( ('es', ugettext('Spanish')), ('pt', ugettext('Portuguese')), ('ru', ugettext('Russian')), + ('it', ugettext('Italian')), ) SITE_ID = 1 From cf3e07d728d5f5b508b677a03f3b30ef8f3aedd6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 7 Dec 2011 15:53:04 -0400 Subject: [PATCH 028/484] Initial Italian language sync --- apps/common/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 5242 bytes apps/common/locale/it/LC_MESSAGES/django.po | 333 ++++++ .../converter/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../converter/locale/it/LC_MESSAGES/django.po | 934 +++++++++++++++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 521 bytes .../locale/it/LC_MESSAGES/django.po | 292 ++++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 102 ++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 205 ++++ .../documents/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 18570 bytes .../documents/locale/it/LC_MESSAGES/django.po | 977 ++++++++++++++++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 116 +++ apps/folders/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/folders/locale/it/LC_MESSAGES/django.po | 212 ++++ apps/history/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/history/locale/it/LC_MESSAGES/django.po | 106 ++ apps/linking/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/linking/locale/it/LC_MESSAGES/django.po | 331 ++++++ apps/main/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/main/locale/it/LC_MESSAGES/django.po | 143 +++ apps/metadata/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/metadata/locale/it/LC_MESSAGES/django.po | 452 ++++++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 32 + apps/ocr/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/ocr/locale/it/LC_MESSAGES/django.po | 448 ++++++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 194 ++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 28 + .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 24 + .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 36 + apps/sources/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/sources/locale/it/LC_MESSAGES/django.po | 462 +++++++++ apps/tags/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes apps/tags/locale/it/LC_MESSAGES/django.po | 267 +++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../locale/it/LC_MESSAGES/django.po | 254 +++++ .../web_theme/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 501 bytes .../web_theme/locale/it/LC_MESSAGES/django.po | 76 ++ 44 files changed, 6024 insertions(+) create mode 100644 apps/common/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/common/locale/it/LC_MESSAGES/django.po create mode 100644 apps/converter/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/converter/locale/it/LC_MESSAGES/django.po create mode 100644 apps/django_gpg/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/django_gpg/locale/it/LC_MESSAGES/django.po create mode 100644 apps/document_comments/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/document_comments/locale/it/LC_MESSAGES/django.po create mode 100644 apps/document_indexing/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/document_indexing/locale/it/LC_MESSAGES/django.po create mode 100644 apps/documents/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/documents/locale/it/LC_MESSAGES/django.po create mode 100644 apps/dynamic_search/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/dynamic_search/locale/it/LC_MESSAGES/django.po create mode 100644 apps/folders/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/folders/locale/it/LC_MESSAGES/django.po create mode 100644 apps/history/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/history/locale/it/LC_MESSAGES/django.po create mode 100644 apps/linking/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/linking/locale/it/LC_MESSAGES/django.po create mode 100644 apps/main/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/main/locale/it/LC_MESSAGES/django.po create mode 100644 apps/metadata/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/metadata/locale/it/LC_MESSAGES/django.po create mode 100644 apps/navigation/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/navigation/locale/it/LC_MESSAGES/django.po create mode 100644 apps/ocr/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/ocr/locale/it/LC_MESSAGES/django.po create mode 100644 apps/permissions/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/permissions/locale/it/LC_MESSAGES/django.po create mode 100644 apps/project_setup/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/project_setup/locale/it/LC_MESSAGES/django.po create mode 100644 apps/project_tools/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/project_tools/locale/it/LC_MESSAGES/django.po create mode 100644 apps/smart_settings/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/smart_settings/locale/it/LC_MESSAGES/django.po create mode 100644 apps/sources/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/sources/locale/it/LC_MESSAGES/django.po create mode 100644 apps/tags/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/tags/locale/it/LC_MESSAGES/django.po create mode 100644 apps/user_management/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/user_management/locale/it/LC_MESSAGES/django.po create mode 100644 apps/web_theme/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/web_theme/locale/it/LC_MESSAGES/django.po diff --git a/apps/common/locale/it/LC_MESSAGES/django.mo b/apps/common/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..5ac939ecbbde5403e8fe6dec4eedccd50892a41d GIT binary patch literal 5242 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 literal 0 HcmV?d00001 diff --git a/apps/common/locale/it/LC_MESSAGES/django.po b/apps/common/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..dd5bb70aee --- /dev/null +++ b/apps/common/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,333 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-12-07 18:22+0000\n" +"Last-Translator: pippo64 \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:17 +msgid "change password" +msgstr "cambia password" + +#: __init__.py:18 +msgid "user details" +msgstr "dettaglio utente" + +#: __init__.py:19 +msgid "edit details" +msgstr "modifica dettagli" + +#: __init__.py:23 __init__.py:29 +msgid "about" +msgstr "a rigurdo" + +#: __init__.py:24 +msgid "changelog" +msgstr "changelog" + +#: __init__.py:25 +msgid "license" +msgstr "licenza" + +#: forms.py:99 +msgid "Selection" +msgstr "Selezione" + +#: forms.py:131 +msgid "Email" +msgstr "Email" + +#: forms.py:142 +msgid "" +"Please enter a correct email and password. Note that the password fields is " +"case-sensitive." +msgstr "" +"Inserisci un'indirizzo mail valido e una password. Ricorda che il campo " +"password è case-sensitive" + +#: forms.py:144 +msgid "This account is inactive." +msgstr "Questo account è inattivo" + +#: literals.py:24 +msgid "A5" +msgstr "A5" + +#: literals.py:25 +msgid "A4" +msgstr "A4" + +#: literals.py:26 +msgid "A3" +msgstr "A3" + +#: literals.py:27 +msgid "B5" +msgstr "B5" + +#: literals.py:28 +msgid "B4" +msgstr "B4" + +#: literals.py:29 +msgid "Letter" +msgstr "Letter" + +#: literals.py:30 +msgid "Legal" +msgstr "Legal" + +#: literals.py:31 +msgid "Ledger" +msgstr "Mastro" + +#: literals.py:38 +msgid "Portrait" +msgstr "Verticale" + +#: literals.py:39 +msgid "Landscape" +msgstr "Orizontale" + +#: utils.py:291 +msgid "function found" +msgstr "trovata funzione" + +#: utils.py:293 utils.py:295 +#, python-format +msgid "class found: %s" +msgstr "classe trovata:%s" + +#: views.py:24 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." +msgstr "La tua password è stata cambiata con successo" + +#: views.py:41 +msgid "No action selected." +msgstr "Nessuna azione selezionata" + +#: views.py:45 +msgid "Must select at least one item." +msgstr "Devi selezionare un item" + +#: views.py:86 +#, python-format +msgid "%(selection)s added successfully added to %(right_list_title)s." +msgstr "%(selection)s aggiunto con successo a %(right_list_title)s." + +#: views.py:89 views.py:106 +#, python-format +msgid "Unable to add %(selection)s to %(right_list_title)s." +msgstr "Impossibile aggiungere %(selection)s a %(right_list_title)s." + +#: views.py:103 +#, python-format +msgid "%(selection)s added successfully removed from %(right_list_title)s." +msgstr "" +"%(selection)s aggiunto correttamente rimosso dal %(right_list_title)s." + +#: views.py:121 +msgid "Add" +msgstr "Aggiungi" + +#: views.py:132 +msgid "Remove" +msgstr "Rimuovi" + +#: views.py:155 +msgid "current user details" +msgstr "dettagli dell'utente corrente" + +#: views.py:172 +msgid "Current user's details updated." +msgstr "Dettagli dell'utente corrente aggiornati" + +#: views.py:181 +msgid "edit current user details" +msgstr "modifica i dettagli dell'utente corrente" + +#: views.py:207 +msgid "Changelog" +msgstr "Changelog" + +#: views.py:220 +msgid "License" +msgstr "Licenza" + +#: widgets.py:58 +msgid "None" +msgstr "Nessuno" + +#: conf/settings.py:15 +msgid "" +"Temporary directory used site wide to store thumbnails, previews and " +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" +msgstr "" +"Directory temporanea utilizzata a livello di sito per thumbnails, anteprime " +"e file temporanei. Se non viene specificato, ne verrà creata utilizzando " +"tempfile.mkdtemp()" + +#: conf/settings.py:65 +msgid "" +"Controls the mechanism used to authenticated user. Options are: username, " +"email" +msgstr "" +"Controllo del meccanismo di autenticazione. Le opzioni possibili " +"sono:username,email" + +#: templates/403.html:3 templates/403.html.py:7 +msgid "Insufficient permissions" +msgstr "Permessi insufficienti" + +#: templates/403.html:9 +msgid "You don't have enough permissions for this operation." +msgstr "Non hai i permessi per effettuare questa operazione." + +#: templates/404.html:3 templates/404.html.py:7 +msgid "Page not found" +msgstr "Pagina non trovata" + +#: templates/404.html:9 +msgid "Sorry, but the requested page could not be found." +msgstr "Scusa ma la pagina richiesta non è disponibile" + +#: templates/calculate_form_title.html:11 +#, python-format +msgid "Details for %(object_name)s: %(object)s" +msgstr "Dettagli per %(object_name)s: %(object)s" + +#: templates/calculate_form_title.html:13 +#, python-format +msgid "Details for: %(object)s" +msgstr "Detaglio per: %(object)s" + +#: templates/calculate_form_title.html:18 +#, python-format +msgid "Edit %(object_name)s:" +msgstr "Modifica %(object_name)s:" + +#: templates/calculate_form_title.html:20 +msgid "Edit" +msgstr "Modifica" + +#: templates/calculate_form_title.html:24 +#, python-format +msgid "Create new %(object_name)s" +msgstr "Crea nuovo %(object_name)s" + +#: templates/calculate_form_title.html:26 +msgid "Create" +msgstr "Crea" + +#: templates/generic_assign_remove.html:3 +#, python-format +msgid "Assign %(title)s %(object)s" +msgstr "Assigna %(title)s %(object)s" + +#: templates/generic_confirm.html:3 templates/generic_confirm.html.py:18 +msgid "Confirm" +msgstr "Conferma" + +#: templates/generic_confirm.html:16 +msgid "Confirm delete" +msgstr "Conferma la cancellazione" + +#: templates/generic_confirm.html:32 +msgid "form icon" +msgstr "icona del modulo" + +#: templates/generic_confirm.html:40 +#, python-format +msgid "Are you sure you wish to delete %(object_name)s: %(object)s?" +msgstr "Sei sicuro di voler cancellare %(object_name)s: %(object)s?" + +#: templates/generic_confirm.html:42 +#, python-format +msgid "Are you sure you wish to delete: %(object)s?" +msgstr "Sei sicuro di volr cancellare: %(object)s?" + +#: templates/generic_confirm.html:50 +msgid "Yes" +msgstr "Si" + +#: templates/generic_confirm.html:54 +msgid "No" +msgstr "No" + +#: templates/generic_form_instance.html:37 +#: templates/generic_form_subtemplate.html:52 +msgid "required" +msgstr "richiesto" + +#: templates/generic_form_subtemplate.html:76 +#: templates/generic_form_subtemplate.html:78 +#: templates/generic_list_horizontal_subtemplate.html:51 +#: templates/generic_list_horizontal_subtemplate.html:178 +#: templates/generic_list_subtemplate.html:52 +#: templates/generic_list_subtemplate.html:178 +msgid "Save" +msgstr "Salva" + +#: templates/generic_form_subtemplate.html:76 +#: templates/generic_form_subtemplate.html:78 +#: templates/generic_list_horizontal_subtemplate.html:51 +#: templates/generic_list_horizontal_subtemplate.html:178 +#: templates/generic_list_subtemplate.html:52 +#: templates/generic_list_subtemplate.html:178 +msgid "Submit" +msgstr "Sottometti" + +#: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 +#, python-format +msgid "List of %(stripped_title)s" +msgstr "Lista di %(stripped_title)s" + +#: templates/generic_list_horizontal_subtemplate.html:23 +#: templates/generic_list_subtemplate.html:24 +#, python-format +msgid "" +"List of %(title)s (%(start)s - %(end)s out of %(total)s) (Page " +"%(page_number)s of %(total_pages)s)" +msgstr "" +"Lista di %(title)s (%(start)s - %(end)s fuori %(total)s) (Page " +"%(page_number)s of %(total_pages)s)" + +#: templates/generic_list_horizontal_subtemplate.html:25 +#: templates/generic_list_subtemplate.html:26 +#, python-format +msgid "List of %(title)s (%(total)s)" +msgstr "Lista di %(title)s (%(total)s)" + +#: templates/generic_list_subtemplate.html:72 +msgid "Identifier" +msgstr "Identificatore" + +#: templates/generic_list_subtemplate.html:152 +#, python-format +msgid "There are no %(stripped_title)s" +msgstr "Non ci sono %(stripped_title)s" + +#: templates/login.html:5 +msgid "Login" +msgstr "Login" + +#: templates/password_change_done.html:3 templates/password_change_form.html:3 +#: templates/password_change_form.html:5 +msgid "Password change" +msgstr "Cambia password" + + diff --git a/apps/converter/locale/it/LC_MESSAGES/django.mo b/apps/converter/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..72cbfdd28e96e44641807cba5841648db40f9397 GIT binary patch literal 501 zcmYjNO-~y!5T$BQd+fP~sl)-)PV8Nv3Z|(@$wrElg(z8iH;LJ}+O=2qYy&@pU&DXt zZ|Q7PL7)6&kNoE2&F}Z`o(>pqm>-yj%(u+X%pODLGk>1*-D_U32>z#86V5jH!-QzP zQ&8wf?I52Nt7K_f9|((B*$sa0s)(gmuqA4h5S68EcQ;u3Mg$*qus(>U&lNVt&ctMK zQ{q)Hnz$@ZG#Le%OjG2OWss&S`-1XRN*3bM{IY%f|8?>lPbA1wb$0eiGLpHDgk{h! z)|z}!Fuk46;d)%;@HH>Sv-#zCGFj%U)i;*9s?(Lh(&$FPjC5_;)zQD%ce~wy`a<^J zJPe#6(e5`9MY}hFX46DLoGmPg&Kg06AuLlYIa_HP(R*#+#Mqaz0&N01&T G2Y&#?){|ub literal 0 HcmV?d00001 diff --git a/apps/converter/locale/it/LC_MESSAGES/django.po b/apps/converter/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..5e8e9ffb0a --- /dev/null +++ b/apps/converter/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,934 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:55+0000\n" +"Last-Translator: FULL NAME \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:10 +msgid "file formats" +msgstr "" + +#: literals.py:19 +msgid "Resize" +msgstr "" + +#: literals.py:20 +msgid "Resize." +msgstr "" + +#: literals.py:22 literals.py:37 +msgid "width" +msgstr "" + +#: literals.py:23 literals.py:38 +msgid "height" +msgstr "" + +#: literals.py:27 +msgid "Rotate" +msgstr "" + +#: literals.py:28 +msgid "Rotate by n degress." +msgstr "" + +#: literals.py:30 +msgid "degrees" +msgstr "" + +#: literals.py:34 +msgid "Density" +msgstr "" + +#: literals.py:35 +msgid "Change the resolution (ie: DPI) without resizing." +msgstr "" + +#: literals.py:42 +msgid "Zoom" +msgstr "" + +#: literals.py:43 +msgid "Zoom by n percent." +msgstr "" + +#: literals.py:45 +msgid "percent" +msgstr "" + +#: literals.py:51 +msgid "Hasselblad Photo RAW, CFV/H3D39II" +msgstr "" + +#: literals.py:52 literals.py:53 +msgid "Photoshop resource format" +msgstr "" + +#: literals.py:54 +msgid "Photoshop resource text format" +msgstr "" + +#: literals.py:55 +msgid "Photoshop resource wide text format" +msgstr "" + +#: literals.py:57 +msgid "Raw alpha samples" +msgstr "" + +#: literals.py:58 +msgid "Adobe Illustrator CS2" +msgstr "" + +#: literals.py:59 +msgid "Raw application information" +msgstr "" + +#: literals.py:60 +msgid "Raw JPEG binary data" +msgstr "" + +#: literals.py:61 +msgid "PFS: 1st Publisher Clip Art" +msgstr "" + +#: literals.py:62 +msgid "Sony Alpha DSLR Raw Image Format" +msgstr "" + +#: literals.py:63 +msgid "Microsoft Audio/Visual Interleaved" +msgstr "" + +#: literals.py:64 +msgid "AVS X image" +msgstr "" + +#: literals.py:66 +msgid "Raw blue samples" +msgstr "" + +#: literals.py:67 +msgid "Raw blue, green, and red samples" +msgstr "" + +#: literals.py:68 +msgid "Raw blue, green, red and alpha samples" +msgstr "" + +#: literals.py:69 +msgid "Microsoft Windows bitmap image" +msgstr "" + +#: literals.py:70 +msgid "Microsoft Windows bitmap image version 2" +msgstr "" + +#: literals.py:71 +msgid "Microsoft Windows bitmap image version 3" +msgstr "" + +#: literals.py:72 +msgid "BRF ASCII Braille format" +msgstr "" + +#: literals.py:73 +msgid "Raw blue, red, and green samples" +msgstr "" + +#: literals.py:75 +msgid "Raw cyan samples" +msgstr "" + +#: literals.py:76 literals.py:181 +msgid "Magick Persistent Cache image format" +msgstr "" + +#: literals.py:77 literals.py:78 +msgid "Continuous Acquisition and Life-cycle Support Type 1 image" +msgstr "" + +#: literals.py:79 +msgid "Image caption" +msgstr "" + +#: literals.py:80 +msgid "Cineon Image File" +msgstr "" + +#: literals.py:81 +msgid "Cisco IP phone image format" +msgstr "" + +#: literals.py:82 +msgid "Image Clip Mask" +msgstr "" + +#: literals.py:83 +msgid "Raw cyan, magenta, yellow, and black samples" +msgstr "" + +#: literals.py:84 +msgid "Raw cyan, magenta, yellow, black, and opacity samples" +msgstr "" + +#: literals.py:85 literals.py:86 +msgid "Canon Digital Camera Raw Image Format" +msgstr "" + +#: literals.py:87 +msgid "Microsoft Cursor Icon" +msgstr "" + +#: literals.py:88 +msgid "DR Halo" +msgstr "" + +#: literals.py:90 +msgid "Digital Imaging and Communications in Medicine image" +msgstr "" + +#: literals.py:91 +msgid "Kodak Digital Camera Raw Image File" +msgstr "" + +#: literals.py:92 +msgid "ZSoft IBM PC multi-page Paintbrush" +msgstr "" + +#: literals.py:93 +msgid "Microsoft DirectDraw Surface" +msgstr "" + +#: literals.py:94 +msgid "Multi-face font package (Freetype 2.4.2)" +msgstr "" + +#: literals.py:95 +msgid "Déjà vu" +msgstr "" + +#: literals.py:96 +msgid "Adobe Digital Negative" +msgstr "" + +#: literals.py:97 +msgid "Graphviz" +msgstr "" + +#: literals.py:98 +msgid "SMPTE 268M-2003 (DPX 2.0)" +msgstr "" + +#: literals.py:100 +msgid "Encapsulated Portable Document Format" +msgstr "" + +#: literals.py:101 literals.py:106 +msgid "Adobe Encapsulated PostScript Interchange format" +msgstr "" + +#: literals.py:102 literals.py:105 +msgid "Adobe Encapsulated PostScript" +msgstr "" + +#: literals.py:103 +msgid "Adobe Level II Encapsulated PostScript" +msgstr "" + +#: literals.py:104 +msgid "Adobe Level III Encapsulated PostScript" +msgstr "" + +#: literals.py:107 +msgid "Adobe Encapsulated PostScript with TIFF preview" +msgstr "" + +#: literals.py:108 +msgid "Adobe Level II Encapsulated PostScript with TIFF preview" +msgstr "" + +#: literals.py:109 +msgid "Adobe Level III Encapsulated PostScript with TIFF preview" +msgstr "" + +#: literals.py:110 +msgid "Epson RAW Format" +msgstr "" + +#: literals.py:111 +msgid "Exif digital camera binary data" +msgstr "" + +#: literals.py:112 +msgid "High Dynamic-range (HDR)" +msgstr "" + +#: literals.py:114 +msgid "Group 3 FAX (Not TIFF Group3 FAX)" +msgstr "" + +#: literals.py:115 +msgid "Autodesk FLI animations file" +msgstr "" + +#: literals.py:116 +msgid "Autodesk FLC animations file" +msgstr "" + +#: literals.py:117 literals.py:120 +msgid "Flexible Image Transport System" +msgstr "" + +#: literals.py:118 +msgid "Kodak FlashPix file" +msgstr "" + +#: literals.py:119 literals.py:225 +msgid "Plasma fractal image" +msgstr "" + +#: literals.py:122 +msgid "Raw green samples" +msgstr "" + +#: literals.py:123 +msgid "Group 3 FAX" +msgstr "" + +#: literals.py:124 +msgid "Raw green, blue, and red samples" +msgstr "" + +#: literals.py:125 +msgid "GIMP brush file" +msgstr "" + +#: literals.py:126 +msgid "CompuServe graphics interchange format (version 89a)" +msgstr "" + +#: literals.py:127 +msgid "CompuServe graphics interchange format (version 87a)" +msgstr "" + +#: literals.py:128 +msgid "Gradual passing from one shade to another" +msgstr "" + +#: literals.py:129 +msgid "Raw gray samples" +msgstr "" + +#: literals.py:130 +msgid "Raw green, red, and blue samples" +msgstr "" + +#: literals.py:131 +msgid "Raw CCITT Group4" +msgstr "" + +#: literals.py:133 +msgid "Histogram of the image" +msgstr "" + +#: literals.py:134 +msgid "HRZ: Slow scan TV" +msgstr "" + +#: literals.py:135 literals.py:136 literals.py:255 +msgid "Hypertext Markup Language and a client-side image map" +msgstr "" + +#: literals.py:138 literals.py:264 literals.py:279 literals.py:283 +msgid "Truevision Targa image" +msgstr "" + +#: literals.py:139 literals.py:140 +msgid "ICC Color Profile" +msgstr "" + +#: literals.py:141 literals.py:142 +msgid "Microsoft Icon" +msgstr "" + +#: literals.py:143 +msgid "Hald CLUT identity image" +msgstr "" + +#: literals.py:144 +msgid "LabEye image format" +msgstr "" + +#: literals.py:145 +msgid "GraphicsMagick Embedded Image" +msgstr "" + +#: literals.py:146 +msgid "The image format and characteristics" +msgstr "" + +#: literals.py:147 +msgid "Base64-encoded inline images" +msgstr "" + +#: literals.py:148 +msgid "IPL Image Sequence" +msgstr "" + +#: literals.py:149 +msgid "IPTC Newsphoto" +msgstr "" + +#: literals.py:150 literals.py:151 +msgid "IPTC Newsphoto text format" +msgstr "" + +#: literals.py:152 +msgid "ISO/TR 11548-1 format" +msgstr "" + +#: literals.py:154 literals.py:157 +msgid "JPEG-2000 Code Stream Syntax" +msgstr "" + +#: literals.py:155 +msgid "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:156 +msgid "JPEG-2000 JP2 File Format Syntax" +msgstr "" + +#: literals.py:158 literals.py:159 +msgid "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" +msgstr "" + +#: literals.py:160 +msgid "JPEG-2000 File Format Syntax" +msgstr "" + +#: literals.py:162 +msgid "Raw black samples" +msgstr "" + +#: literals.py:163 literals.py:164 +msgid "Kodak Digital Camera Raw Image Format" +msgstr "" + +#: literals.py:166 +msgid "Image label" +msgstr "" + +#: literals.py:168 +msgid "Raw magenta samples" +msgstr "" + +#: literals.py:169 literals.py:179 literals.py:182 literals.py:183 +msgid "MPEG Video Stream" +msgstr "" + +#: literals.py:170 +msgid "Raw MPEG-4 Video" +msgstr "" + +#: literals.py:171 +msgid "Colormap intensities and indices" +msgstr "" + +#: literals.py:172 +msgid "MATLAB image format" +msgstr "" + +#: literals.py:173 +msgid "MATTE raw opacity format" +msgstr "" + +#: literals.py:174 +msgid "8-bit McIdas area file" +msgstr "" + +#: literals.py:175 +msgid "Microsoft Image Composer (MIC) file" +msgstr "" + +#: literals.py:176 +msgid "Magick Image File Format" +msgstr "" + +#: literals.py:177 +msgid "" +"Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:178 +msgid "Raw Bi-level bitmap in least-significant-byte first order" +msgstr "" + +#: literals.py:180 +msgid "MPEG-4 Video Stream" +msgstr "" + +#: literals.py:184 +msgid "Sony (Minolta) Raw Image File" +msgstr "" + +#: literals.py:185 +msgid "Magick Scripting Language" +msgstr "" + +#: literals.py:186 +msgid "Windows 1 and 2 MSP file format" +msgstr "" + +#: literals.py:187 +msgid "ImageMagick's own SVG internal renderer" +msgstr "" + +#: literals.py:188 +msgid "MTV Raytracing image format" +msgstr "" + +#: literals.py:189 +msgid "Magick Vector Graphics" +msgstr "" + +#: literals.py:191 +msgid "Nikon Digital SLR Camera Raw Image File" +msgstr "" + +#: literals.py:192 +msgid "Constant image of uniform color" +msgstr "" + +#: literals.py:194 +msgid "Raw opacity samples" +msgstr "" + +#: literals.py:195 +msgid "Olympus Digital Camera Raw Image File" +msgstr "" + +#: literals.py:196 +msgid "On-the-air bitmap" +msgstr "" + +#: literals.py:197 +msgid "Open Type font (Freetype 2.4.2)" +msgstr "" + +#: literals.py:199 +msgid "Xv thumbnail format" +msgstr "" + +#: literals.py:200 literals.py:277 +msgid "16bit/pixel interleaved YUV" +msgstr "" + +#: literals.py:201 +msgid "Palm pixmap" +msgstr "" + +#: literals.py:202 +msgid "Common 2-dimensional bitmap format" +msgstr "" + +#: literals.py:203 +msgid "Predefined pattern" +msgstr "" + +#: literals.py:204 +msgid "Portable bitmap format (black and white)" +msgstr "" + +#: literals.py:205 literals.py:206 +msgid "Photo CD" +msgstr "" + +#: literals.py:207 +msgid "Page Control Language" +msgstr "" + +#: literals.py:208 literals.py:221 +msgid "Apple Macintosh QuickDraw/PICT" +msgstr "" + +#: literals.py:209 +msgid "ZSoft IBM PC Paintbrush" +msgstr "" + +#: literals.py:210 +msgid "Palm Database ImageViewer Format" +msgstr "" + +#: literals.py:211 +msgid "Portable Document Format" +msgstr "" + +#: literals.py:212 +msgid "Portable Document Archive Format" +msgstr "" + +#: literals.py:213 +msgid "Pentax Electronic File" +msgstr "" + +#: literals.py:214 +msgid "Embrid Embroidery Format" +msgstr "" + +#: literals.py:215 +msgid "Postscript Type 1 font (ASCII) (Freetype 2.4.2)" +msgstr "" + +#: literals.py:216 +msgid "Postscript Type 1 font (binary) (Freetype 2.4.2)" +msgstr "" + +#: literals.py:217 +msgid "Portable float format" +msgstr "" + +#: literals.py:218 +msgid "Portable graymap format (gray scale)" +msgstr "" + +#: literals.py:219 +msgid "JPEG-2000 VM Format" +msgstr "" + +#: literals.py:220 +msgid "Personal Icon" +msgstr "" + +#: literals.py:222 +msgid "Alias/Wavefront RLE image format" +msgstr "" + +#: literals.py:223 +msgid "PIXAR raster file" +msgstr "" + +#: literals.py:224 +msgid "Joint Photographic Experts Group JFIF format (62)" +msgstr "" + +#: literals.py:226 +msgid "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:227 +msgid "" +"24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:228 +msgid "" +"32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:229 +msgid "" +"8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:230 +msgid "Portable anymap" +msgstr "" + +#: literals.py:231 +msgid "Portable pixmap format (color)" +msgstr "" + +#: literals.py:232 +msgid "Show a preview an image enhancement, effect, or f/x" +msgstr "" + +#: literals.py:233 +msgid "Adobe PostScript" +msgstr "" + +#: literals.py:234 +msgid "Adobe Level II PostScript" +msgstr "" + +#: literals.py:235 +msgid "Adobe Level III PostScript" +msgstr "" + +#: literals.py:236 +msgid "Adobe Large Document Format" +msgstr "" + +#: literals.py:237 +msgid "Adobe Photoshop bitmap" +msgstr "" + +#: literals.py:238 +msgid "Pyramid encoded TIFF" +msgstr "" + +#: literals.py:239 literals.py:253 +msgid "Seattle Film Works" +msgstr "" + +#: literals.py:241 +msgid "Raw red samples" +msgstr "" + +#: literals.py:242 +msgid "Fuji CCD-RAW Graphic File" +msgstr "" + +#: literals.py:243 literals.py:259 +msgid "SUN Rasterfile" +msgstr "" + +#: literals.py:244 +msgid "Raw red, blue, and green samples" +msgstr "" + +#: literals.py:245 +msgid "Raw red, green, and blue samples" +msgstr "" + +#: literals.py:246 +msgid "Raw red, green, blue, and matte samples" +msgstr "" + +#: literals.py:247 +msgid "Raw red, green, blue, and opacity samples" +msgstr "" + +#: literals.py:248 +msgid "Alias/Wavefront image" +msgstr "" + +#: literals.py:249 +msgid "Utah Run length encoded image" +msgstr "" + +#: literals.py:251 +msgid "ZX-Spectrum SCREEN$" +msgstr "" + +#: literals.py:252 +msgid "Scitex HandShake" +msgstr "" + +#: literals.py:254 +msgid "Irix RGB image" +msgstr "" + +#: literals.py:256 +msgid "Sony Raw Format 2" +msgstr "" + +#: literals.py:257 +msgid "Sony Raw Format" +msgstr "" + +#: literals.py:258 +msgid "Steganographic image" +msgstr "" + +#: literals.py:260 +msgid "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" +msgstr "" + +#: literals.py:261 +msgid "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" +msgstr "" + +#: literals.py:263 literals.py:273 +msgid "Text" +msgstr "" + +#: literals.py:265 +msgid "EXIF Profile Thumbnail" +msgstr "" + +#: literals.py:266 +msgid "Tagged Image File Format (LIBTIFF, Version 3.9.4)" +msgstr "" + +#: literals.py:267 +msgid "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" +msgstr "" + +#: literals.py:268 +msgid "Tile image with a texture" +msgstr "" + +#: literals.py:269 +msgid "PSX TIM" +msgstr "" + +#: literals.py:270 +msgid "TOPOL X Image" +msgstr "" + +#: literals.py:271 +msgid "TrueType font collection (Freetype 2.4.2)" +msgstr "" + +#: literals.py:272 +msgid "TrueType font (Freetype 2.4.2)" +msgstr "" + +#: literals.py:275 +msgid "Unicode Text format" +msgstr "" + +#: literals.py:276 +msgid "X-Motif UIL table" +msgstr "" + +#: literals.py:280 +msgid "VICAR rasterfile format" +msgstr "" + +#: literals.py:281 +msgid "Visual Image Directory" +msgstr "" + +#: literals.py:282 literals.py:299 +msgid "Khoros Visualization image" +msgstr "" + +#: literals.py:285 +msgid "Wireless Bitmap (level 0) image" +msgstr "" + +#: literals.py:286 +msgid "Windows Meta File" +msgstr "" + +#: literals.py:287 +msgid "Word Perfect Graphics" +msgstr "" + +#: literals.py:288 +msgid "Windows Media Video" +msgstr "" + +#: literals.py:289 +msgid "Compressed Windows Meta File" +msgstr "" + +#: literals.py:291 +msgid "X Window System" +msgstr "" + +#: literals.py:292 +msgid "Foveon X3 (Sigma/Polaroid) Raw picture file" +msgstr "" + +#: literals.py:293 +msgid "X Windows system bitmap (black and white)" +msgstr "" + +#: literals.py:294 +msgid "Constant image uniform color" +msgstr "" + +#: literals.py:295 +msgid "GIMP image" +msgstr "" + +#: literals.py:296 +msgid "Adobe XML metadata" +msgstr "" + +#: literals.py:297 +msgid "X Windows system pixmap (color)" +msgstr "" + +#: literals.py:298 +msgid "Microsoft XML Paper Specification" +msgstr "" + +#: literals.py:300 +msgid "XV thumbnail file" +msgstr "" + +#: literals.py:301 +msgid "X Windows system window dump (color)" +msgstr "" + +#: literals.py:303 +msgid "Raw yellow samples" +msgstr "" + +#: literals.py:304 +msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" +msgstr "" + +#: views.py:15 +msgid "suported file formats" +msgstr "" + +#: views.py:20 +msgid "name" +msgstr "" + +#: views.py:24 +msgid "description" +msgstr "" + +#: conf/settings.py:11 +msgid "File path to imagemagick's convert program." +msgstr "" + +#: conf/settings.py:12 +msgid "File path to imagemagick's identify program." +msgstr "" + +#: conf/settings.py:13 +msgid "File path to graphicsmagick's program." +msgstr "" + +#: conf/settings.py:15 +msgid "" +"Graphics conversion backend to use. Options are: " +"converter.backends.imagemagick, converter.backends.graphicsmagick and " +"converter.backends.python." +msgstr "" + +#: conf/settings.py:16 +msgid "Path to the unoconv program." +msgstr "" + +#: conf/settings.py:17 +msgid "" +"Use alternate method of connection to LibreOffice using a pipe, it is slower" +" but less prone to segmentation faults." +msgstr "" + +#: templates/converter_file_formats_help.html:3 +msgid "Help" +msgstr "" + +#: templates/converter_file_formats_help.html:4 +#, python-format +msgid "" +"These are the file formats supported by the currently selected converter " +"backend. In this case: '%(backend)s'" +msgstr "" + + diff --git a/apps/django_gpg/locale/it/LC_MESSAGES/django.mo b/apps/django_gpg/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..78fac47634810def560210d12c106f6b5c48b059 GIT binary patch literal 521 zcmZutO;6)65M>3Y9656^(jGuCu~VUL*HDBgMXIzB6=e7BwnJ)^*pWS!9p+EwCi9TlVZeOh&)B|?Fw)?z}Yvg~y4-Op;ZN~tSuZ}A~@ zNU~XPC(34R3~*6LNt`V$$^9gskB;>q;#KGfSVNYQe#@YJ;iZ(uX=~;hO(p9QKaI`a0ZmVs|LA{bb_} DvA~`_ literal 0 HcmV?d00001 diff --git a/apps/django_gpg/locale/it/LC_MESSAGES/django.po b/apps/django_gpg/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..5fc3342cd5 --- /dev/null +++ b/apps/django_gpg/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,292 @@ +# 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: 2011-12-06 02:06-0400\n" +"PO-Revision-Date: 2011-12-06 06:07+0000\n" +"Last-Translator: rosarior \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:14 +msgid "Verify document signatures" +msgstr "" + +#: __init__.py:15 +msgid "View keys" +msgstr "" + +#: __init__.py:16 +msgid "Delete keys" +msgstr "" + +#: __init__.py:17 +msgid "Query keyservers" +msgstr "" + +#: __init__.py:18 +msgid "Import key from keyservers" +msgstr "" + +#: __init__.py:19 +msgid "Upload detached signatures" +msgstr "" + +#: __init__.py:20 +msgid "Download detached signatures" +msgstr "" + +#: __init__.py:23 +msgid "Signatures" +msgstr "" + +#: __init__.py:39 views.py:67 +msgid "private keys" +msgstr "" + +#: __init__.py:40 views.py:70 +msgid "public keys" +msgstr "" + +#: __init__.py:41 +msgid "delete" +msgstr "" + +#: __init__.py:42 +msgid "query keyservers" +msgstr "" + +#: __init__.py:43 +msgid "import" +msgstr "" + +#: __init__.py:44 +msgid "upload signature" +msgstr "" + +#: __init__.py:45 +msgid "download signature" +msgstr "" + +#: __init__.py:46 +msgid "key management" +msgstr "" + +#: __init__.py:49 +msgid "signatures" +msgstr "" + +#: api.py:22 +msgid "Public" +msgstr "" + +#: api.py:23 +msgid "Secret" +msgstr "" + +#: api.py:31 api.py:36 +msgid "RSA" +msgstr "" + +#: api.py:32 +msgid "DSA" +msgstr "" + +#: api.py:37 +msgid "Elgamal" +msgstr "" + +#: api.py:51 +msgid "Bad signature." +msgstr "" + +#: api.py:55 +msgid "Document not signed or invalid signature." +msgstr "" + +#: api.py:59 +msgid "Signature error." +msgstr "" + +#: api.py:63 +msgid "Document is signed but no public key is available for verification." +msgstr "" + +#: api.py:67 +msgid "Document is signed, and signature is good." +msgstr "" + +#: api.py:71 +msgid "Document is signed with a valid signature." +msgstr "" + +#: api.py:144 +msgid "unknown" +msgstr "" + +#: forms.py:11 +msgid "Term" +msgstr "" + +#: forms.py:12 +msgid "Name, e-mail, key ID or key fingerprint to look for." +msgstr "" + +#: forms.py:18 +msgid "Signature file" +msgstr "" + +#: views.py:45 +#, python-format +msgid "Key: %s, imported successfully." +msgstr "" + +#: views.py:48 +#, python-format +msgid "Unable to import key id: %s" +msgstr "" + +#: views.py:52 +msgid "Import key" +msgstr "" + +#: views.py:53 +#, python-format +msgid "Are you sure you wish to import key id: %s?" +msgstr "" + +#: views.py:78 +msgid "Key ID" +msgstr "" + +#: views.py:82 +msgid "Owner" +msgstr "" + +#: views.py:102 +#, python-format +msgid "Key: %s, deleted successfully." +msgstr "" + +#: views.py:109 +msgid "Delete key" +msgstr "" + +#: views.py:111 +#, python-format +msgid "" +"Are you sure you wish to delete key: %s? If you try to delete a public key " +"that is part of a public/private pair the private key will be deleted as " +"well." +msgstr "" + +#: views.py:129 +msgid "Query key server" +msgstr "" + +#: views.py:142 +msgid "results" +msgstr "" + +#: views.py:147 +msgid "ID" +msgstr "" + +#: views.py:151 +msgid "type" +msgstr "" + +#: views.py:155 +msgid "creation date" +msgstr "" + +#: views.py:159 +msgid "disabled" +msgstr "" + +#: views.py:163 +msgid "expiration date" +msgstr "" + +#: views.py:167 +msgid "expired" +msgstr "" + +#: views.py:171 +msgid "length" +msgstr "" + +#: views.py:175 +msgid "revoked" +msgstr "" + +#: views.py:180 +msgid "Identifies" +msgstr "" + +#: views.py:205 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "" + +#: views.py:212 +msgid "embedded" +msgstr "" + +#: views.py:214 +msgid "detached" +msgstr "" + +#: views.py:219 +#, python-format +msgid "Signature ID: %s" +msgstr "" + +#: views.py:220 +#, python-format +msgid "Signature type: %s" +msgstr "" + +#: views.py:221 +#, python-format +msgid "Key ID: %s" +msgstr "" + +#: views.py:222 +#, python-format +msgid "Timestamp: %s" +msgstr "" + +#: views.py:223 +#, python-format +msgid "Signee: %s" +msgstr "" + +#: views.py:228 +#, python-format +msgid "signature properties for: %s" +msgstr "" + +#: views.py:250 +msgid "Detached signature uploaded successfully." +msgstr "" + +#: views.py:259 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "" + +#: conf/settings.py:13 +msgid "List of keyservers to be queried for unknown keys." +msgstr "" + + diff --git a/apps/document_comments/locale/it/LC_MESSAGES/django.mo b/apps/document_comments/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..518cede71b9f64f7abe8c8b9155d58f69a1bc339 GIT binary patch literal 501 zcmYjN%Wm5+5KPgYbnLl@4bVe^c1=nS3WuqSy0Huxuu{WTdS`4#W+9ORxvG;7>DTmM z@-11#MUnvrHq?_TqaW$?evhH$>cUnWHB zoq|H&YX|wXSSKsf`aoF3%5L#TS4Awnf*nz-gs3d-x|_kqHzN3`gY`i)eXg)Eb|xmv zpCw)fqlwGnRFhGV$uvbiSq5pUvM(slq+}tk%pcpgf31_}IFumI)NuGoGLnUkgk{h! z)|z}!FuPtX;A&Fj@HHu)S|Ri`V1rO}OoIqBN6tCRn;@Avxw^@Z%M zxf?h`qCIRPiuPav&9;exI9pf}r%5p{@|PW@1DRZUN5=6$_bodkbH_z$ZQTWIb~;2u z\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:15 +msgid "Create new comments" +msgstr "" + +#: __init__.py:16 +msgid "Delete comments" +msgstr "" + +#: __init__.py:17 +msgid "Edit comments" +msgstr "" + +#: __init__.py:18 +msgid "View comments" +msgstr "" + +#: __init__.py:20 +msgid "Comments" +msgstr "" + +#: __init__.py:26 __init__.py:27 +msgid "delete" +msgstr "" + +#: __init__.py:28 +msgid "add comment" +msgstr "" + +#: __init__.py:29 utils.py:14 +msgid "comments" +msgstr "" + +#: __init__.py:33 +msgid "date" +msgstr "" + +#: __init__.py:37 +msgid "user" +msgstr "" + +#: __init__.py:41 +msgid "comment" +msgstr "" + +#: views.py:27 +msgid "Must provide at least one comment." +msgstr "" + +#: views.py:37 +#, python-format +msgid "Comment \"%s\" deleted successfully." +msgstr "" + +#: views.py:39 +#, python-format +msgid "Error deleting comment \"%(comment)s\": %(error)s" +msgstr "" + +#: views.py:54 +#, python-format +msgid "Are you sure you wish to delete the comment: %s?" +msgstr "" + +#: views.py:56 +#, python-format +msgid "Are you sure you wish to delete the comments: %s?" +msgstr "" + +#: views.py:86 +msgid "Comment added successfully." +msgstr "" + +#: views.py:93 +#, python-format +msgid "Add comment to document: %s" +msgstr "" + +#: views.py:109 +#, python-format +msgid "comments: %s" +msgstr "" + + diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.mo b/apps/document_indexing/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0eb804bd170782f648845e1ba0dc2ee18f6e7c7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8fKp)BU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n27rlVJb= literal 0 HcmV?d00001 diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.po b/apps/document_indexing/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..063bc16e02 --- /dev/null +++ b/apps/document_indexing/locale/it/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: +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-09-30 04:42+0000\n" +"Last-Translator: FULL NAME \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:12 +msgid "View document indexes" +msgstr "" + +#: __init__.py:13 +msgid "Rebuild document indexes" +msgstr "" + +#: __init__.py:15 +msgid "Indexing" +msgstr "" + +#: __init__.py:19 +msgid "index list" +msgstr "" + +#: __init__.py:20 +msgid "go up one level" +msgstr "" + +#: __init__.py:21 __init__.py:23 models.py:26 +msgid "indexes" +msgstr "" + +#: __init__.py:25 +msgid "rebuild indexes" +msgstr "" + +#: __init__.py:25 +msgid "Deletes and creates from scratch all the document indexes." +msgstr "" + +#: __init__.py:27 +msgid "Indexes" +msgstr "" + +#: api.py:83 +msgid "root" +msgstr "" + +#: api.py:139 +#, python-format +msgid "Maximum suffix (%s) count reached." +msgstr "" + +#: api.py:175 +#, python-format +msgid "" +"Error in document indexing update expression: %(expression)s; %(exception)s" +msgstr "" + +#: api.py:178 +#, python-format +msgid "" +"Error updating document index, expression: %(expression)s; %(exception)s" +msgstr "" + +#: api.py:209 +#, python-format +msgid "Unable to delete document indexing node; %s" +msgstr "" + +#: filesystem.py:34 +#, python-format +msgid "Unable to create indexing directory; %s" +msgstr "" + +#: filesystem.py:52 +#, python-format +msgid "" +"Unable to create symbolic link, file exists and could not be deleted: " +"%(filepath)s; %(exc)s" +msgstr "" + +#: filesystem.py:54 +#, python-format +msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" +msgstr "" + +#: filesystem.py:71 +#, python-format +msgid "Unable to delete document symbolic link; %s" +msgstr "" + +#: filesystem.py:83 +#, python-format +msgid "Unable to delete indexing directory; %s" +msgstr "" + +#: models.py:11 +#, python-format +msgid "Available functions: %s" +msgstr "" + +#: models.py:16 +msgid "indexing expression" +msgstr "" + +#: models.py:16 +msgid "Enter a python string expression to be evaluated." +msgstr "" + +#: models.py:18 +msgid "enabled" +msgstr "" + +#: models.py:19 +msgid "link documents" +msgstr "" + +#: models.py:25 models.py:31 views.py:56 +msgid "index" +msgstr "" + +#: models.py:32 +msgid "value" +msgstr "" + +#: models.py:33 +msgid "documents" +msgstr "" + +#: models.py:46 models.py:51 +msgid "index instance" +msgstr "" + +#: models.py:47 +msgid "indexes instances" +msgstr "" + +#: models.py:52 +msgid "document" +msgstr "" + +#: models.py:59 +msgid "document rename count" +msgstr "" + +#: models.py:60 +msgid "documents rename count" +msgstr "" + +#: utils.py:19 +msgid "document indexes" +msgstr "" + +#: views.py:38 +#, python-format +msgid "contents for index: %s" +msgstr "" + +#: views.py:60 +msgid "items" +msgstr "" + +#: views.py:82 +msgid "Are you sure you wish to rebuild all indexes?" +msgstr "" + +#: views.py:83 +msgid "On large databases this operation may take some time to execute." +msgstr "" + +#: views.py:89 +msgid "Index rebuild completed successfully." +msgstr "" + +#: views.py:94 +#, python-format +msgid "Index rebuild error: %s" +msgstr "" + +#: views.py:109 +#, python-format +msgid "indexes containing: %s" +msgstr "" + +#: templates/indexing_help.html:3 +msgid "What are indexes?" +msgstr "" + +#: templates/indexing_help.html:4 +msgid "Indexes group documents into a tree like hierarchical structure." +msgstr "" + + diff --git a/apps/documents/locale/it/LC_MESSAGES/django.mo b/apps/documents/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e3790f11283091122005f747046decc0f1624b79 GIT binary patch literal 18570 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 literal 0 HcmV?d00001 diff --git a/apps/documents/locale/it/LC_MESSAGES/django.po b/apps/documents/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..ac50b2183a --- /dev/null +++ b/apps/documents/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,977 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-12-07 11:57+0000\n" +"Last-Translator: pippo64 \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:49 __init__.py:159 +msgid "Documents" +msgstr "Documenti" + +#: __init__.py:60 +msgid "Documents setup" +msgstr "Setup Documenti" + +#: __init__.py:70 +msgid "all documents" +msgstr "tutti i documenti" + +#: __init__.py:71 models.py:415 views.py:709 +msgid "recent documents" +msgstr "documenti recenti" + +#: __init__.py:72 +msgid "upload new documents" +msgstr "upload nuovi documenti" + +#: __init__.py:73 +msgid "clone metadata" +msgstr "clona i metadati" + +#: __init__.py:74 +msgid "details" +msgstr "dettagli" + +#: __init__.py:75 +msgid "properties" +msgstr "proprietà" + +#: __init__.py:76 __init__.py:77 __init__.py:92 __init__.py:114 +#: __init__.py:120 +msgid "delete" +msgstr "cancella" + +#: __init__.py:78 __init__.py:91 __init__.py:113 __init__.py:119 +msgid "edit" +msgstr "edita" + +#: __init__.py:79 +msgid "preview" +msgstr "anteprima" + +#: __init__.py:80 +msgid "download" +msgstr "scarica" + +#: __init__.py:81 +msgid "find duplicates" +msgstr "trova duplicati" + +#: __init__.py:82 +msgid "find all duplicates" +msgstr "trova tutti i duplicati" + +#: __init__.py:82 +msgid "" +"Search all the documents' checksums and return a list of the exact matches." +msgstr "" +"Cerca tutti i documenti con il checksum e restituisci una lista delle " +"corrispondenze esatte." + +#: __init__.py:83 +msgid "update office documents' page count" +msgstr "update documenti di office numero di pagine" + +#: __init__.py:83 +msgid "" +"Update the page count of the office type documents. This is useful when " +"enabling office document support after there were already office type " +"documents in the database." +msgstr "" +"Update the page count of the office type documents. This is useful when " +"enabling office document support after there were already office type " +"documents in the database." + +#: __init__.py:84 __init__.py:85 +msgid "clear transformations" +msgstr "ripulisci le trasformazioni" + +#: __init__.py:86 +msgid "print" +msgstr "stampa" + +#: __init__.py:87 +msgid "history" +msgstr "versioni" + +#: __init__.py:89 +msgid "page transformations" +msgstr "trasformazioni della pagina" + +#: __init__.py:90 +msgid "create new transformation" +msgstr "crea una nuova trasformazione" + +#: __init__.py:94 +msgid "page image" +msgstr "immagine della pagina" + +#: __init__.py:95 +msgid "page text" +msgstr "testo della pagina" + +#: __init__.py:96 +msgid "edit page text" +msgstr "modifica il testo nella pagina" + +#: __init__.py:97 +msgid "next page" +msgstr "pagina successiva" + +#: __init__.py:98 +msgid "previous page" +msgstr "pagina precedente" + +#: __init__.py:99 +msgid "first page" +msgstr "prima pagina" + +#: __init__.py:100 +msgid "last page" +msgstr "ultima pagina" + +#: __init__.py:101 +msgid "zoom in" +msgstr "zoom in" + +#: __init__.py:102 +msgid "zoom out" +msgstr "zoom out" + +#: __init__.py:103 +msgid "rotate right" +msgstr "ruotate a destra" + +#: __init__.py:104 +msgid "rotate left" +msgstr "ruotate a sinistra" + +#: __init__.py:105 +msgid "reset view" +msgstr "ripristino della vista" + +#: __init__.py:107 +msgid "Find missing document files" +msgstr "Trovare i file di documenti mancanti" + +#: __init__.py:110 +msgid "document type list" +msgstr "lista in base al tipo di documento" + +#: __init__.py:111 views.py:877 +msgid "document types" +msgstr "tipi di documenti" + +#: __init__.py:112 +msgid "documents of this type" +msgstr "documenti di questo tipo" + +#: __init__.py:115 views.py:990 +msgid "create document type" +msgstr "crea il tipo di documenti" + +#: __init__.py:117 +msgid "filenames" +msgstr "nome file" + +#: __init__.py:118 +msgid "add filename to document type" +msgstr "aggiungi il nome file al tipo di documento" + +#: __init__.py:161 __init__.py:186 models.py:101 views.py:69 +msgid "documents" +msgstr "documenti" + +#: __init__.py:173 +msgid "thumbnail" +msgstr "thumbnail" + +#: __init__.py:176 +msgid "tags" +msgstr "etichette" + +#: __init__.py:179 +msgid "metadata" +msgstr "metadata" + +#: forms.py:60 +msgid "Page image" +msgstr "Immagine della pagina" + +#: forms.py:70 forms.py:209 +msgid "Contents" +msgstr "Contenuti" + +#: forms.py:116 +msgid "Details" +msgstr "Dettagli" + +#: forms.py:121 +msgid "Click on the image for full size preview" +msgstr "Click sull'immagine per l'anteprima" + +#: forms.py:131 +#, python-format +msgid "Document pages (%s)" +msgstr "Pagine nel documento (%s)" + +#: forms.py:166 +msgid "Quick document rename" +msgstr "Rinomina del documento veloce" + +#: forms.py:169 +msgid "New document filename" +msgstr "Nuovo nome documento" + +#: forms.py:223 +msgid "Page size" +msgstr "Dimensioni di pagina" + +#: forms.py:224 +msgid "Custom page width" +msgstr "Personalizza larghezza pagina" + +#: forms.py:225 +msgid "Custom page height" +msgstr "Personalizza altezza pagina" + +#: forms.py:226 +msgid "Page orientation" +msgstr "Orientamento pagina" + +#: forms.py:227 +msgid "Page range" +msgstr "Intervallo pagina" + +#: literals.py:8 +msgid "Create documents" +msgstr "Crea documenti" + +#: literals.py:9 +msgid "Edit document properties" +msgstr "Modifica proprietà documento" + +#: literals.py:10 +msgid "Edit documents" +msgstr "Modifica documenti" + +#: literals.py:11 +msgid "View documents" +msgstr "Visualizza documenti" + +#: literals.py:12 +msgid "Delete documents" +msgstr "Cancella documenti" + +#: literals.py:13 +msgid "Download documents" +msgstr "Scarica documenti" + +#: literals.py:14 +msgid "Transform documents" +msgstr "Trasforma documenti" + +#: literals.py:15 +msgid "Execute document modifying tools" +msgstr "Esegui i tools per la modifica dei documenti" + +#: literals.py:17 +msgid "Edit document types" +msgstr "Modifica il tipo di documento" + +#: literals.py:18 +msgid "Delete document types" +msgstr "Cancella il tipo di documento" + +#: literals.py:19 +msgid "Create document types" +msgstr "Crea tipo di documento" + +#: literals.py:23 +msgid "Document creation" +msgstr "Creazione documento" + +#: literals.py:24 +#, python-format +msgid "Document \"%(content_object)s\" created by %(fullname)s." +msgstr "Documento \"%(content_object)s\" creato da by %(fullname)s." + +#: literals.py:25 +#, python-format +msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "Documento \"%(content_object)s\" creato il %(datetime)s da %(fullname)s." + +#: literals.py:31 +msgid "Document edited" +msgstr "Documento modificato" + +#: literals.py:32 +#, python-format +msgid "Document \"%(content_object)s\" edited by %(fullname)s." +msgstr "Documento \"%(content_object)s\" modificato da %(fullname)s." + +#: literals.py:33 +#, python-format +msgid "" +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." +" The following changes took place: %(changes)s." +msgstr "" +"Documento \"%(content_object)s\" è stato modificato il %(datetime)s da " +"%(fullname)s. Queste le seguenti modifiche: %(changes)s." + +#: literals.py:42 +msgid "Document deleted" +msgstr "Documento cancellato" + +#: literals.py:43 +#, python-format +msgid "Document \"%(document)s\" deleted by %(fullname)s." +msgstr "Documento \"%(document)s\" cancellato da %(fullname)s." + +#: literals.py:44 +#, python-format +msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." +msgstr "Documento \"%(document)s\" cancellato il %(datetime)s da %(fullname)s." + +#: models.py:63 +msgid "name" +msgstr "nome" + +#: models.py:69 models.py:78 models.py:315 views.py:896 views.py:926 +#: views.py:955 views.py:960 views.py:1003 views.py:1049 views.py:1083 +msgid "document type" +msgstr "tipo documento" + +#: models.py:70 +msgid "documents types" +msgstr "documenti tipo" + +#: models.py:79 +msgid "file" +msgstr "file" + +#: models.py:86 +msgid "added" +msgstr "ha aggiunto" + +#: models.py:87 +msgid "updated" +msgstr "updated" + +#: models.py:88 +msgid "checksum" +msgstr "checksum" + +#: models.py:89 +msgid "description" +msgstr "descrizione" + +#: models.py:100 models.py:332 models.py:404 models.py:419 views.py:209 +msgid "document" +msgstr "documento" + +#: models.py:181 +msgid "" +"This document's file format is not known, the page count has therefore " +"defaulted to 1." +msgstr "" +"Questo tipo di formato file è sconosciuto, per cui il numero di pagine sarà " +"1" + +#: models.py:316 +msgid "filename" +msgstr "nome file" + +#: models.py:317 views.py:1010 +msgid "enabled" +msgstr "abilitato" + +#: models.py:324 +msgid "document type quick rename filename" +msgstr "rinomina veloce del nome file del documento" + +#: models.py:325 +msgid "document types quick rename filenames" +msgstr "rinomina veloce del nome files del documento" + +#: models.py:333 +msgid "content" +msgstr "contenuto" + +#: models.py:334 +msgid "page label" +msgstr "etichetta di pagina" + +#: models.py:335 +msgid "page number" +msgstr "numero pagina" + +#: models.py:338 +#, python-format +msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" +msgstr "Pagina %(page_num)d di %(total_pages)d del %(document)s" + +#: models.py:346 models.py:383 +msgid "document page" +msgstr "pagina del documento" + +#: models.py:347 +msgid "document pages" +msgstr "pagine di documento" + +#: models.py:358 +msgid "Enter a valid value." +msgstr "Inserisci un valore valido" + +#: models.py:384 views.py:333 +msgid "order" +msgstr "ordina" + +#: models.py:385 views.py:334 views.py:389 views.py:418 +msgid "transformation" +msgstr "trasformazione" + +#: models.py:386 views.py:335 +msgid "arguments" +msgstr "argomenti" + +#: models.py:386 +#, python-format +msgid "Use dictionaries to indentify arguments, example: %s" +msgstr "Usa dizionari per identificare gli argomenti, esempio:%s" + +#: models.py:394 +msgid "document page transformation" +msgstr "trasformazione della pagina del documento" + +#: models.py:395 +msgid "document page transformations" +msgstr "trasformazioni della pagina del documento" + +#: models.py:403 +msgid "user" +msgstr "utente" + +#: models.py:405 +msgid "accessed" +msgstr "accessi" + +#: models.py:414 +msgid "recent document" +msgstr "documenti recenti" + +#: models.py:420 +msgid "Document type" +msgstr "Tipo documento" + +#: models.py:421 +msgid "MIME type" +msgstr "Tipo MIME" + +#: models.py:422 views.py:117 +msgid "Filename" +msgstr "Nome file" + +#: models.py:423 +msgid "Filename extension" +msgstr "Estensione del file" + +#: models.py:424 +msgid "Metadata value" +msgstr "Valore del Metadato" + +#: models.py:425 +msgid "Content" +msgstr "Contenuto" + +#: models.py:426 +msgid "Description" +msgstr "Descrizione" + +#: models.py:427 +msgid "Tags" +msgstr "Etichette" + +#: models.py:428 +msgid "Comments" +msgstr "Commenti" + +#: statistics.py:38 +#, python-format +msgid "Document types: %d" +msgstr "Tipi di documento: %d " + +#: statistics.py:39 +#, python-format +msgid "Documents in database: %d" +msgstr "Documenti nel database:%d" + +#: statistics.py:44 +#, python-format +msgid "Documents in storage: %d" +msgstr "Documenti nello storage:%d" + +#: statistics.py:46 +#, python-format +msgid "" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" +" bytes" +msgstr "" +"Spazio usato nello storage: %(base_2)s (base 2), %(base_10)s (base 10), " +"%(bytes)d bytes" + +#: statistics.py:56 +#, python-format +msgid "Document pages in database: %d" +msgstr "Pagine di documenti nel database:%d" + +#: statistics.py:57 +#, python-format +msgid "Minimum amount of pages per document: %(page_count__min)d" +msgstr "Numero minimo di pagine per documento:%(page_count__min)d" + +#: statistics.py:58 +#, python-format +msgid "Maximum amount of pages per document: %(page_count__max)d" +msgstr "Numero massimo di pagine per documento:%(page_count__max)d" + +#: statistics.py:59 +#, python-format +msgid "Average amount of pages per document: %(page_count__avg)f" +msgstr "Media di pagine per documento:%(page_count__avg)f" + +#: statistics.py:65 +msgid "Document statistics" +msgstr "Statistiche del documento" + +#: views.py:118 +msgid "File extension" +msgstr "Estensione del file" + +#: views.py:119 +msgid "File mimetype" +msgstr "File mimetype" + +#: views.py:120 +msgid "File mime encoding" +msgstr "File mime encoding" + +#: views.py:121 +msgid "File size" +msgstr "Dimensioni del file" + +#: views.py:122 +msgid "Exists in storage" +msgstr "Esiste nello storage" + +#: views.py:123 +msgid "File path in storage" +msgstr "File path in storage" + +#: views.py:124 +msgid "Date added" +msgstr "Inserimento data" + +#: views.py:125 +msgid "Time added" +msgstr "Inserimento orario" + +#: views.py:126 +msgid "Checksum" +msgstr "Checksum" + +#: views.py:127 +msgid "UUID" +msgstr "UUID" + +#: views.py:128 +msgid "Pages" +msgstr "Pagine" + +#: views.py:137 +#, python-format +msgid "document properties for: %s" +msgstr "Proprietà per il documento:%s" + +#: views.py:159 +msgid "document data" +msgstr "dati del documento" + +#: views.py:184 views.py:521 +msgid "Must provide at least one document." +msgstr "Devi indicare almeno un documento" + +#: views.py:200 +#, python-format +msgid "Document: %s deleted successfully." +msgstr "Il documento %s è stato cancellato con successo" + +#: views.py:202 +#, python-format +msgid "Document: %(document)s delete error: %(error)s" +msgstr "Documento:%(document)s errore cancellazione: %(error)s" + +#: views.py:217 +#, python-format +msgid "Are you sure you wish to delete the document: %s?" +msgstr "Sei sicuro di voler cancellare il documento: %s?" + +#: views.py:219 +#, python-format +msgid "Are you sure you wish to delete the documents: %s?" +msgstr "Sei sicuro di voler cancellare i documenti: %s?" + +#: views.py:256 +#, python-format +msgid "Document \"%s\" edited successfully." +msgstr "Il documento \"%s\" è ancora in modifica" + +#: views.py:329 +#, python-format +msgid "transformations for: %s" +msgstr "trasformazioni per:%s" + +#: views.py:353 +msgid "Document page transformation created successfully." +msgstr "Trasformazioni per la pagina del documento creata con successo" + +#: views.py:362 +#, python-format +msgid "Create new transformation for page: %(page)s of document: %(document)s" +msgstr "" +"Crea una nuova trasformazione per la pagina: %(page)s del documento: " +"%(document)s" + +#: views.py:378 +msgid "Document page transformation edited successfully." +msgstr "Document page trasformation edited successfully." + +#: views.py:391 +#, python-format +msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" +msgstr "Modifica la trasformazione \"%(transformation)s\" per: %(document_page)s" + +#: views.py:409 +msgid "Document page transformation deleted successfully." +msgstr "Trasformazione della pagina di documento cancellata con successo." + +#: views.py:420 +#, python-format +msgid "" +"Are you sure you wish to delete transformation \"%(transformation)s\" for: " +"%(document_page)s" +msgstr "" +"Sei sicuro di voler cancellare la trasformazione \"%(transformation)s\" per:" +" %(document_page)s" + +#: views.py:434 +#, python-format +msgid "duplicates of: %s" +msgstr "duplicati di:%s" + +#: views.py:446 +msgid "Are you sure you wish to find all duplicates?" +msgstr "Sei sicuro di voler trovare tutti i duplicati?" + +#: views.py:447 views.py:506 views.py:571 +msgid "On large databases this operation may take some time to execute." +msgstr "" +"In un grande database questa operazione potrebbe richiedere del tempo " + +#: views.py:462 +msgid "duplicated documents" +msgstr "documenti duplicati" + +#: views.py:497 +#, python-format +msgid "" +"Page count update complete. Documents processed: %(total)d, documents with " +"changed page count: %(change)d" +msgstr "" +"Update del numero di pagine completato. Il documenti processati " +"%(total)d, con il numero di pagine cambiate: %(change)d" + +#: views.py:505 +#, python-format +msgid "" +"Are you sure you wish to update the page count for the office documents " +"(%d)?" +msgstr "" +"Sei sicuro di voler cambiare il numero di pagine deil documenti office (%d)?" + +#: views.py:534 +#, python-format +msgid "" +"All the page transformations for document: %s, have been deleted " +"successfully." +msgstr "" +"Tutte le trasformazioni alle pagine del documento:%s, sono state cancellate " +"con successo." + +#: views.py:536 +#, python-format +msgid "" +"Error deleting the page transformations for document: %(document)s; " +"%(error)s." +msgstr "" +"Errore nella cancellazione della trasformazione della pagina per il " +"documento:%(document)s; %(error)s." + +#: views.py:542 +msgid "document transformation" +msgstr "trasformazione del documento" + +#: views.py:551 +#, python-format +msgid "" +"Are you sure you wish to clear all the page transformations for document: " +"%s?" +msgstr "Sei sicuro di voler cancellare le trasformazioni per il documento:%s?" + +#: views.py:553 +#, python-format +msgid "" +"Are you sure you wish to clear all the page transformations for documents: " +"%s?" +msgstr "Sei sicuro di voler cancellare le trasformazioni per il documenti:%s?" + +#: views.py:581 +msgid "missing documents" +msgstr "documenti mancanti" + +#: views.py:594 views.py:632 +#, python-format +msgid "details for: %s" +msgstr "dettagli per:%s" + +#: views.py:647 +msgid "Document page edited successfully." +msgstr "Pagina di documento modificata con successo." + +#: views.py:656 +#, python-format +msgid "edit: %s" +msgstr "modifica:%s" + +#: views.py:667 +msgid "There are no more pages in this document" +msgstr "Non ci sono più pagine in questo documento" + +#: views.py:680 +msgid "You are already at the first page of this document" +msgstr "Sei già alla prima pagina del documento" + +#: views.py:823 +#, python-format +msgid "print: %s" +msgstr "stampa:%s" + +#: views.py:894 +#, python-format +msgid "documents of type \"%s\"" +msgstr "documenti di tipo \"%s\"" + +#: views.py:914 +msgid "Document type edited successfully" +msgstr "Tipo di documento modificata con successo" + +#: views.py:917 +#, python-format +msgid "Error editing document type; %s" +msgstr "Errore nella modifica del tipo di documento;%s" + +#: views.py:922 +#, python-format +msgid "edit document type: %s" +msgstr "modifica tipo documento:%s" + +#: views.py:947 +#, python-format +msgid "Document type: %s deleted successfully." +msgstr "Tipo di documento: %s cancellata ." + +#: views.py:949 +#, python-format +msgid "Document type: %(document_type)s delete error: %(error)s" +msgstr "" +"Tipo di documento: %(document_type)s errore di cancellazione: %(error)s" + +#: views.py:964 +#, python-format +msgid "Are you sure you wish to delete the document type: %s?" +msgstr "Sei sicuro di cancellare questo tipo di documento:%s?" + +#: views.py:965 +msgid "" +"The document type of all documents using this document type will be set to " +"none." +msgstr "Il tipo di documento per tutti i documenti sarà messo a nullo" + +#: views.py:981 +msgid "Document type created successfully" +msgstr "Tipo di documento creato con successo" + +#: views.py:984 +#, python-format +msgid "Error creating document type; %(error)s" +msgstr "Errore nella creazione del tipo di documento;%(error)s" + +#: views.py:1002 +#, python-format +msgid "filenames for document type: %s" +msgstr "tipo di documento per il nome file: %s" + +#: views.py:1033 +msgid "Document type filename edited successfully" +msgstr "Tipo di documento per il nome file modificato con successo" + +#: views.py:1036 +#, python-format +msgid "Error editing document type filename; %s" +msgstr "Errore nella modifica del tipo di nome file;%s" + +#: views.py:1041 +#, python-format +msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" +msgstr "" +"modifica il nome file \"%(filename)s\" per il tipo di documento " +"\"%(document_type)s\"" + +#: views.py:1050 views.py:1076 views.py:1084 +msgid "document type filename" +msgstr "tipo di nome file per il documento" + +#: views.py:1068 +#, python-format +msgid "Document type filename: %s deleted successfully." +msgstr "Tipo di nome file per il documento: %s cancellato con successo." + +#: views.py:1070 +#, python-format +msgid "" +"Document type filename: %(document_type_filename)s delete error: %(error)s" +msgstr "" +"Tipo di nome file per il documento:%(document_type_filename)s errore di " +"cancellazione: %(error)s" + +#: views.py:1086 +#, python-format +msgid "" +"Are you sure you wish to delete the filename: %(filename)s, from document " +"type \"%(document_type)s\"?" +msgstr "" +"Sei sicuro che vuoi cancellare il nome file:%(filename)s, per il tipo di " +"documento\"%(document_type)s\"?" + +#: views.py:1111 +msgid "Document type filename created successfully" +msgstr "Tipo di nome file per nome file creato con successo" + +#: views.py:1114 +#, python-format +msgid "Error creating document type filename; %(error)s" +msgstr "Errore creando il tipo di nome file; %(error)s" + +#: views.py:1120 +#, python-format +msgid "create filename for document type: %s" +msgstr "crea il nome file per i documenti di tipo:%s" + +#: widgets.py:26 +msgid "document page image" +msgstr "immagine della pagina del documento" + +#: wizards.py:34 +msgid "step 1 of 3: Document type" +msgstr "step 1 of 3: Tipo documento" + +#: wizards.py:35 +msgid "step 2 of 3: Metadata selection" +msgstr "step 2 of 3: Selezione dei Metadata " + +#: wizards.py:36 +msgid "step 3 of 3: Document metadata" +msgstr "step 3 of 3: Metadata del documento" + +#: wizards.py:44 +msgid "Next step" +msgstr "Next step" + +#: conf/settings.py:38 +msgid "" +"Maximum number of recent (created, edited, viewed) documents to remember per" +" user." +msgstr "" +"Massimo numero recente (creazione, modifica, visualizzazione) di documenti " +"da ricordare per utente" + +#: conf/settings.py:39 +msgid "Amount in percent zoom in or out a document page per user interaction." +msgstr "" +"Importo in percentuale dello zoom o rimpicciolire una pagina del documento " +"per l'interazione dell'utente." + +#: conf/settings.py:40 +msgid "" +"Maximum amount in percent (%) to allow user to zoom in a document page " +"interactively." +msgstr "" +"Importo massimo in percentuale (%) per consentire all'utente di ingrandire " +"una pagina del documento in modo interattivo." + +#: conf/settings.py:41 +msgid "" +"Minimum amount in percent (%) to allow user to zoom out a document page " +"interactively." +msgstr "" +"Quantità minima in percentuale (%) per consentire all'utente di ingrandire " +"una pagina di documento in modo interattivo." + +#: conf/settings.py:42 +msgid "Amount in degrees to rotate a document page per user interaction." +msgstr "Quantità di gradi per la rotazione della pagina del documento" + +#: templates/document_types_help.html:3 +msgid "What are document types?" +msgstr "Che tipo di documenti sono ?" + +#: templates/document_types_help.html:4 +msgid "" +"Document types define a class that represents a broard group of documents, " +"such as: invoices, regulations or manuals. The advantage of using document " +"types are: assigning a list of typical filenames for quick renaming during " +"creation, as well as assigning default metadata types and sets to it." +msgstr "" +"Il tipo di documento definisce una raggruppamento di documenti, come : " +"fatture, regolamenti, manuali. Il vantaggio dell'uso di tale classificazione" +" permette di rinominare,aggiungere metadati e rinominare i file più " +"velocemente." + +#: templates/recent_document_list_help.html:3 +msgid "What are recent documents?" +msgstr "Quali sono i documenti recenti ?" + +#: templates/recent_document_list_help.html:4 +#, python-format +msgid "" +"Here you will find the latest %(recent_count)s documents you have either " +"created or edited in any way." +msgstr "" +"qui troverete gli ultimi %(recent_count)s documenti da voi creati o " +"modificati" + + diff --git a/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0eb804bd170782f648845e1ba0dc2ee18f6e7c7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8fKp)BU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n27rlVJb= literal 0 HcmV?d00001 diff --git a/apps/dynamic_search/locale/it/LC_MESSAGES/django.po b/apps/dynamic_search/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..1cb017c45b --- /dev/null +++ b/apps/dynamic_search/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,116 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:42+0000\n" +"Last-Translator: FULL NAME \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:5 +msgid "search" +msgstr "" + +#: __init__.py:6 views.py:72 +msgid "advanced search" +msgstr "" + +#: __init__.py:7 +msgid "search again" +msgstr "" + +#: forms.py:8 +msgid "Search terms" +msgstr "" + +#: models.py:20 +msgid "user" +msgstr "" + +#: models.py:21 +msgid "query" +msgstr "" + +#: models.py:22 +msgid "datetime created" +msgstr "" + +#: models.py:23 +msgid "hits" +msgstr "" + +#: models.py:61 +msgid "recent search" +msgstr "" + +#: models.py:62 +msgid "recent searches" +msgstr "" + +#: views.py:33 +#, python-format +msgid "results, (showing only %(shown_result_count)s out of %(result_count)s)" +msgstr "" + +#: views.py:37 +msgid "results" +msgstr "" + +#: views.py:56 +#, python-format +msgid "Search error: %s" +msgstr "" + +#: views.py:60 +msgid "type" +msgstr "" + +#: views.py:76 views.py:86 views.py:88 templatetags/search_tags.py:19 +#: templatetags/search_tags.py:20 +msgid "Search" +msgstr "" + +#: conf/settings.py:12 +msgid "Maximum amount search hits to fetch and display." +msgstr "" + +#: conf/settings.py:13 +msgid "Maximum number of search queries to remember per user." +msgstr "" + +#: templates/search_help.html:3 +msgid "Help" +msgstr "" + +#: templates/search_help.html:4 +#, python-format +msgid "" +"Enter the desired search keywords separated by space. Only the top " +"%(search_results_limit)s results will be available." +msgstr "" + +#: templates/search_results.html:3 +msgid "Search results" +msgstr "" + +#: templates/search_results.html:19 +#, python-format +msgid "Elapsed time: %(time_delta)s seconds" +msgstr "" + +#: templatetags/search_tags.py:33 +#, python-format +msgid "recent searches (maximum of %d)" +msgstr "" + + diff --git a/apps/folders/locale/it/LC_MESSAGES/django.mo b/apps/folders/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..72cbfdd28e96e44641807cba5841648db40f9397 GIT binary patch literal 501 zcmYjNO-~y!5T$BQd+fP~sl)-)PV8Nv3Z|(@$wrElg(z8iH;LJ}+O=2qYy&@pU&DXt zZ|Q7PL7)6&kNoE2&F}Z`o(>pqm>-yj%(u+X%pODLGk>1*-D_U32>z#86V5jH!-QzP zQ&8wf?I52Nt7K_f9|((B*$sa0s)(gmuqA4h5S68EcQ;u3Mg$*qus(>U&lNVt&ctMK zQ{q)Hnz$@ZG#Le%OjG2OWss&S`-1XRN*3bM{IY%f|8?>lPbA1wb$0eiGLpHDgk{h! z)|z}!Fuk46;d)%;@HH>Sv-#zCGFj%U)i;*9s?(Lh(&$FPjC5_;)zQD%ce~wy`a<^J zJPe#6(e5`9MY}hFX46DLoGmPg&Kg06AuLlYIa_HP(R*#+#Mqaz0&N01&T G2Y&#?){|ub literal 0 HcmV?d00001 diff --git a/apps/folders/locale/it/LC_MESSAGES/django.po b/apps/folders/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..6fccff809c --- /dev/null +++ b/apps/folders/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: +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-09-30 04:55+0000\n" +"Last-Translator: FULL NAME \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:10 +msgid "folder list" +msgstr "" + +#: __init__.py:11 views.py:53 +msgid "create folder" +msgstr "" + +#: __init__.py:12 +msgid "edit" +msgstr "" + +#: __init__.py:13 +msgid "delete" +msgstr "" + +#: __init__.py:14 +msgid "remove from folder" +msgstr "" + +#: __init__.py:15 +msgid "folder documents" +msgstr "" + +#: __init__.py:16 +msgid "add to a folder" +msgstr "" + +#: __init__.py:17 __init__.py:25 models.py:31 views.py:21 +msgid "folders" +msgstr "" + +#: forms.py:20 +msgid "Existing folders" +msgstr "" + +#: forms.py:22 +msgid "New folder" +msgstr "" + +#: models.py:11 +msgid "title" +msgstr "" + +#: models.py:12 +msgid "user" +msgstr "" + +#: models.py:13 +msgid "datetime created" +msgstr "" + +#: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 +msgid "folder" +msgstr "" + +#: models.py:36 +msgid "document" +msgstr "" + +#: models.py:42 views.py:257 +msgid "folder document" +msgstr "" + +#: models.py:43 +msgid "folders documents" +msgstr "" + +#: views.py:24 +msgid "created" +msgstr "" + +#: views.py:25 +msgid "documents" +msgstr "" + +#: views.py:45 views.py:152 +msgid "Folder created successfully" +msgstr "" + +#: views.py:48 views.py:154 views.py:188 +#, python-format +msgid "A folder named: %s, already exists." +msgstr "" + +#: views.py:71 +msgid "Folder edited successfully" +msgstr "" + +#: views.py:74 +#, python-format +msgid "Error editing folder; %s" +msgstr "" + +#: views.py:79 +#, python-format +msgid "edit folder: %s" +msgstr "" + +#: views.py:101 +#, python-format +msgid "Folder: %s deleted successfully." +msgstr "" + +#: views.py:103 +#, python-format +msgid "Folder: %(folder)s delete error: %(error)s" +msgstr "" + +#: views.py:114 +#, python-format +msgid "Are you sure you with to delete the folder: %s?" +msgstr "" + +#: views.py:131 +#, python-format +msgid "documents in folder: %s" +msgstr "" + +#: views.py:157 views.py:191 +msgid "Must specify a new folder or an existing one." +msgstr "" + +#: views.py:162 views.py:196 +#, python-format +msgid "Document: %(document)s added to folder: %(folder)s successfully." +msgstr "" + +#: views.py:165 views.py:199 +#, python-format +msgid "Document: %(document)s is already in folder: %(folder)s." +msgstr "" + +#: views.py:186 +#, python-format +msgid "Folder \"%s\" created successfully" +msgstr "" + +#: views.py:207 +#, python-format +msgid "add document \"%s\" to a folder" +msgstr "" + +#: views.py:223 +#, python-format +msgid "folders containing: %s" +msgstr "" + +#: views.py:239 +msgid "Must provide at least one folder document." +msgstr "" + +#: views.py:249 +#, python-format +msgid "Document: %s removed successfully." +msgstr "" + +#: views.py:251 +#, python-format +msgid "Document: %(document)s delete error: %(error)s" +msgstr "" + +#: views.py:265 +#, python-format +msgid "" +"Are you sure you wish to remove the document: %(document)s from the folder " +"\"%(folder)s\"?" +msgstr "" + +#: views.py:268 +#, python-format +msgid "" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" +msgstr "" + +#: templates/folders_help.html:3 +msgid "What are folders?" +msgstr "" + +#: templates/folders_help.html:4 +msgid "" +"These folders can also be described as user folders. They are a way to let " +"individual users create their own document organization methods. Folders " +"created by one user and the documents contained by them don't affect any " +"other user folders or documents." +msgstr "" + +#: templatetags/folder_tags.py:17 +msgid "Add document to a folder" +msgstr "" + + diff --git a/apps/history/locale/it/LC_MESSAGES/django.mo b/apps/history/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2ee6d674a1b50e1bb980d92bcbf06dea702c38ce GIT binary patch literal 501 zcmYjNO-~y!5T$BQd+fP~sl)-)PV8MM3Z|(@$wrElg(z8iH;LJ}+O=2qYy&@pU&DXt zZ|Q7PL7)6&kNoE2&F}Z`o(>pqm>-yj%(u+X%pODLGk>1*-D_U32>z#86V5jH!-QzP zQ&8wf?I52Nt7K_f9|((B*$sa0s)(gmuqA4h5S68EcQ;u3Mg$*qus(>U&lNVt&ctMK zQ{q)Hnz$@ZG#Le%OjG2OWss&SJ41OYB@1zBe%ZeL|2lb&ClchT`f~P3GLpHDgk{h! z)|z}!Fuk46;d)%;@HH>Sv-#zCGFj%U)i;*9s?(Lh(&$FPjC5_;)zQD%ce~wy`a<^J zJPe#6(e5`9MY}hFX46DLoGmPg&Kg06AuLlYIa_HP(R*#+#Mqaz0&N01&T G2Y&#@>yu^x literal 0 HcmV?d00001 diff --git a/apps/history/locale/it/LC_MESSAGES/django.po b/apps/history/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..a7bf81f372 --- /dev/null +++ b/apps/history/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,106 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:56+0000\n" +"Last-Translator: FULL NAME \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:6 +msgid "Access the history app" +msgstr "" + +#: __init__.py:8 +msgid "History" +msgstr "" + +#: __init__.py:12 models.py:69 +msgid "history" +msgstr "" + +#: models.py:16 +msgid "namespace" +msgstr "" + +#: models.py:17 +msgid "name" +msgstr "" + +#: models.py:25 models.py:34 +msgid "history type" +msgstr "" + +#: models.py:26 +msgid "history types" +msgstr "" + +#: models.py:30 +msgid "date time" +msgstr "" + +#: models.py:35 +msgid "dictionary" +msgstr "" + +#: models.py:70 +msgid "histories" +msgstr "" + +#: views.py:23 +msgid "history events" +msgstr "" + +#: views.py:26 views.py:60 +msgid "date and time" +msgstr "" + +#: views.py:30 +msgid "object" +msgstr "" + +#: views.py:34 views.py:64 +msgid "summary" +msgstr "" + +#: views.py:56 +#, python-format +msgid "history events for: %s" +msgstr "" + +#: views.py:81 +msgid "Date" +msgstr "" + +#: views.py:82 +msgid "Time" +msgstr "" + +#: views.py:83 +msgid "Object" +msgstr "" + +#: views.py:84 +msgid "Event type" +msgstr "" + +#: views.py:85 +msgid "Event details" +msgstr "" + +#: views.py:89 +#, python-format +msgid "details for: %s" +msgstr "" + + diff --git a/apps/linking/locale/it/LC_MESSAGES/django.mo b/apps/linking/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 diff --git a/apps/linking/locale/it/LC_MESSAGES/django.po b/apps/linking/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..e5b46e064b --- /dev/null +++ b/apps/linking/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,331 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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:11 +msgid "View existing smart links" +msgstr "" + +#: __init__.py:12 +msgid "Create new smart links" +msgstr "" + +#: __init__.py:13 +msgid "Delete smart links" +msgstr "" + +#: __init__.py:14 +msgid "Edit smart links" +msgstr "" + +#: __init__.py:16 +msgid "Smart links" +msgstr "" + +#: __init__.py:22 +msgid "smart links actions" +msgstr "" + +#: __init__.py:23 __init__.py:25 models.py:21 views.py:105 +msgid "smart links" +msgstr "" + +#: __init__.py:26 +msgid "smart links list" +msgstr "" + +#: __init__.py:27 +msgid "create new smart link" +msgstr "" + +#: __init__.py:28 __init__.py:33 +msgid "edit" +msgstr "" + +#: __init__.py:29 __init__.py:34 +msgid "delete" +msgstr "" + +#: __init__.py:31 +msgid "conditions" +msgstr "" + +#: __init__.py:32 +msgid "create condition" +msgstr "" + +#: forms.py:48 +msgid "Pages" +msgstr "" + +#: forms.py:54 +msgid "Select" +msgstr "" + +#: forms.py:61 +msgid "Click on the image for full size view of the first page." +msgstr "" + +#: literals.py:7 +msgid "and" +msgstr "" + +#: literals.py:8 +msgid "or" +msgstr "" + +#: literals.py:12 +msgid "is equal to" +msgstr "" + +#: literals.py:13 +msgid "is equal to (case insensitive)" +msgstr "" + +#: literals.py:14 +msgid "contains" +msgstr "" + +#: literals.py:15 +msgid "contains (case insensitive)" +msgstr "" + +#: literals.py:16 +msgid "is in" +msgstr "" + +#: literals.py:17 +msgid "is greater than" +msgstr "" + +#: literals.py:18 +msgid "is greater than or equal to" +msgstr "" + +#: literals.py:19 +msgid "is less than" +msgstr "" + +#: literals.py:20 +msgid "is less than or equal to" +msgstr "" + +#: literals.py:21 +msgid "starts with" +msgstr "" + +#: literals.py:22 +msgid "starts with (case insensitive)" +msgstr "" + +#: literals.py:23 +msgid "ends with" +msgstr "" + +#: literals.py:24 +msgid "ends with (case insensitive)" +msgstr "" + +#: literals.py:25 +msgid "is in regular expression" +msgstr "" + +#: literals.py:26 +msgid "is in regular expression (case insensitive)" +msgstr "" + +#: models.py:10 +msgid "title" +msgstr "" + +#: models.py:11 views.py:108 +msgid "dynamic title" +msgstr "" + +#: models.py:11 models.py:29 +msgid "" +"This expression will be evaluated against the current selected document. " +"The document metadata is available as variables `metadata` and document " +"properties under the variable `document`." +msgstr "" + +#: models.py:12 models.py:31 views.py:109 views.py:196 +msgid "enabled" +msgstr "" + +#: models.py:20 models.py:25 views.py:256 views.py:287 +msgid "smart link" +msgstr "" + +#: models.py:26 +msgid "The inclusion is ignored for the first item." +msgstr "" + +#: models.py:27 +msgid "foreign document data" +msgstr "" + +#: models.py:27 +msgid "" +"This represents the metadata of all other documents. Available objects: " +"`document.` and `metadata.`." +msgstr "" + +#: models.py:29 +msgid "expression" +msgstr "" + +#: models.py:30 +msgid "negated" +msgstr "" + +#: models.py:30 +msgid "Inverts the logic of the operator." +msgstr "" + +#: models.py:34 +msgid "not" +msgstr "" + +#: models.py:37 +msgid "link condition" +msgstr "" + +#: models.py:38 +msgid "link conditions" +msgstr "" + +#: views.py:32 +msgid "No action selected." +msgstr "" + +#: views.py:47 +#, python-format +msgid "documents in smart link: %(group)s" +msgstr "" + +#: views.py:65 +#, python-format +msgid "Smart link query error: %s" +msgstr "" + +#: views.py:76 +#, python-format +msgid "smart links (%s)" +msgstr "" + +#: views.py:90 +msgid "There no defined smart links for the current document." +msgstr "" + +#: views.py:124 +#, python-format +msgid "Smart link: %s created successfully." +msgstr "" + +#: views.py:131 +msgid "Create new smart link" +msgstr "" + +#: views.py:144 +#, python-format +msgid "Smart link: %s edited successfully." +msgstr "" + +#: views.py:153 +#, python-format +msgid "Edit smart link: %s" +msgstr "" + +#: views.py:168 +#, python-format +msgid "Smart link: %s deleted successfully." +msgstr "" + +#: views.py:170 +#, python-format +msgid "Error deleting smart link: %(smart_link)s; %(error)s." +msgstr "" + +#: views.py:180 +#, python-format +msgid "Are you sure you wish to delete smart link: %s?" +msgstr "" + +#: views.py:193 +#, python-format +msgid "conditions for smart link: %s" +msgstr "" + +#: views.py:216 +#, python-format +msgid "Smart link condition: \"%s\" created successfully." +msgstr "" + +#: views.py:223 +#, python-format +msgid "Add new conditions to smart link: \"%s\"" +msgstr "" + +#: views.py:243 +#, python-format +msgid "Smart link condition: \"%s\" edited successfully." +msgstr "" + +#: views.py:250 +msgid "Edit smart link condition" +msgstr "" + +#: views.py:257 views.py:288 +msgid "condition" +msgstr "" + +#: views.py:274 +#, python-format +msgid "Smart link condition: \"%s\" deleted successfully." +msgstr "" + +#: views.py:276 +#, python-format +msgid "" +"Error deleting smart link condition: %(smart_link_condition)s; %(error)s." +msgstr "" + +#: views.py:290 +#, python-format +msgid "Are you sure you wish to delete smart link condition: \"%s\"?" +msgstr "" + +#: conf/settings.py:11 +msgid "Show smart link that don't return any documents." +msgstr "" + +#: templates/smart_links_help.html:3 +msgid "What are smart links?" +msgstr "" + +#: templates/smart_links_help.html:4 +msgid "" +"Smart links are a set of conditional statements that are used to query the " +"database using the current document the user is accessing as the data " +"source, the results of these queries are a list of documents that relate in " +"some manner to the document being displayed and allow users the ability to " +"jump to and from linked documents very easily." +msgstr "" + + diff --git a/apps/main/locale/it/LC_MESSAGES/django.mo b/apps/main/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 diff --git a/apps/main/locale/it/LC_MESSAGES/django.po b/apps/main/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..5fbd304397 --- /dev/null +++ b/apps/main/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,143 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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:15 +msgid "maintenance" +msgstr "" + +#: __init__.py:16 +msgid "statistics" +msgstr "" + +#: __init__.py:17 +msgid "diagnostics" +msgstr "" + +#: __init__.py:18 +msgid "sentry" +msgstr "" + +#: __init__.py:19 +msgid "admin site" +msgstr "" + +#: __init__.py:30 +msgid "home" +msgstr "" + +#: __init__.py:32 +msgid "search" +msgstr "" + +#: views.py:41 +msgid "maintenance menu" +msgstr "" + +#: views.py:53 +msgid "Statistics" +msgstr "" + +#: views.py:61 +msgid "Diagnostics" +msgstr "" + +#: conf/settings.py:12 +msgid "" +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." +msgstr "" + +#: templates/about.html:5 +msgid "About this program" +msgstr "" + +#: templates/about.html:9 templates/verbose_login.html:4 +msgid "Version" +msgstr "" + +#: templates/base.html:28 +msgid "(DEBUG)" +msgstr "" + +#: templates/base.html:183 +msgid "User" +msgstr "" + +#: templates/base.html:185 +msgid "Anonymous" +msgstr "" + +#: templates/base.html:188 +msgid "User details" +msgstr "" + +#: templates/base.html:205 +msgid "Login" +msgstr "" + +#: templates/base.html:205 +msgid "Logout" +msgstr "" + +#: templates/base.html:285 +msgid "Secondary menu" +msgstr "" + +#: templates/base.html:302 +#, python-format +msgid "Actions for %(name)s: %(navigation_object)s" +msgstr "" + +#: templates/base.html:304 templates/base.html.py:336 +#, python-format +msgid "Actions for: %(navigation_object)s" +msgstr "" + +#: templates/base.html:307 +msgid "Available actions" +msgstr "" + +#: templates/base.html:319 templates/base.html.py:351 +msgid "Related actions" +msgstr "" + +#: templates/base.html:334 +#, python-format +msgid "Actions for %(object_name)s: %(navigation_object)s" +msgstr "" + +#: templates/base.html:339 +msgid "Actions" +msgstr "" + +#: templates/base.html:364 +msgid "Other available actions" +msgstr "" + +#: templates/project_description.html:6 +msgid "" +"Open source, Django based electronic document manager with custom metadata, " +"indexing, tagging, file serving integration and OCR capabilities" +msgstr "" + +#: templates/project_description.html:15 +msgid "Released under the GPL V3 License" +msgstr "" + + 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 0000000000000000000000000000000000000000..2ee6d674a1b50e1bb980d92bcbf06dea702c38ce GIT binary patch literal 501 zcmYjNO-~y!5T$BQd+fP~sl)-)PV8MM3Z|(@$wrElg(z8iH;LJ}+O=2qYy&@pU&DXt zZ|Q7PL7)6&kNoE2&F}Z`o(>pqm>-yj%(u+X%pODLGk>1*-D_U32>z#86V5jH!-QzP zQ&8wf?I52Nt7K_f9|((B*$sa0s)(gmuqA4h5S68EcQ;u3Mg$*qus(>U&lNVt&ctMK zQ{q)Hnz$@ZG#Le%OjG2OWss&SJ41OYB@1zBe%ZeL|2lb&ClchT`f~P3GLpHDgk{h! z)|z}!Fuk46;d)%;@HH>Sv-#zCGFj%U)i;*9s?(Lh(&$FPjC5_;)zQD%ce~wy`a<^J zJPe#6(e5`9MY}hFX46DLoGmPg&Kg06AuLlYIa_HP(R*#+#Mqaz0&N01&T G2Y&#@>yu^x literal 0 HcmV?d00001 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..cf409ec798 --- /dev/null +++ b/apps/metadata/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,452 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:56+0000\n" +"Last-Translator: FULL NAME \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: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 +msgid "edit metadata" +msgstr "" + +#: __init__.py:45 +msgid "metadata" +msgstr "" + +#: __init__.py:47 __init__.py:48 +msgid "add metadata" +msgstr "" + +#: __init__.py:49 __init__.py:50 +msgid "remove metadata" +msgstr "" + +#: __init__.py:52 models.py:33 views.py:294 +msgid "metadata types" +msgstr "" + +#: __init__.py:53 __init__.py:58 +msgid "edit" +msgstr "" + +#: __init__.py:54 __init__.py:59 +msgid "delete" +msgstr "" + +#: __init__.py:55 __init__.py:60 +msgid "create new" +msgstr "" + +#: __init__.py:57 views.py:394 +msgid "metadata sets" +msgstr "" + +#: __init__.py:62 models.py:92 +msgid "default metadata" +msgstr "" + +#: classes.py:12 +#, python-format +msgid "'metadata' object has no attribute '%s'" +msgstr "" + +#: forms.py:28 +msgid "required" +msgstr "" + +#: forms.py:54 +msgid "id" +msgstr "" + +#: forms.py:55 +msgid "Name" +msgstr "" + +#: forms.py:57 +msgid "Value" +msgstr "" + +#: forms.py:58 +msgid "Update" +msgstr "" + +#: forms.py:64 +msgid "Metadata type" +msgstr "" + +#: forms.py:68 +msgid "Remove" +msgstr "" + +#: forms.py:86 +msgid "Metadata sets" +msgstr "" + +#: models.py:9 +#, python-format +msgid " Available models: %s" +msgstr "" + +#: models.py:10 +#, python-format +msgid " Available functions: %s" +msgstr "" + +#: models.py:17 +msgid "name" +msgstr "" + +#: models.py:17 +msgid "Do not use python reserved words, or spaces." +msgstr "" + +#: models.py:18 models.py:40 +msgid "title" +msgstr "" + +#: models.py:20 +msgid "default" +msgstr "" + +#: models.py:21 +#, python-format +msgid "Enter a string to be evaluated.%s" +msgstr "" + +#: models.py:23 +msgid "lookup" +msgstr "" + +#: models.py:24 +#, 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 +msgid "metadata type" +msgstr "" + +#: models.py:47 models.py:48 models.py:56 views.py:446 views.py:491 +msgid "metadata set" +msgstr "" + +#: models.py:64 +msgid "metadata set item" +msgstr "" + +#: models.py:65 +msgid "metadata set items" +msgstr "" + +#: models.py:73 +msgid "document" +msgstr "" + +#: models.py:74 +msgid "type" +msgstr "" + +#: models.py:75 views.py:283 +msgid "value" +msgstr "" + +#: models.py:81 models.py:82 +msgid "document metadata" +msgstr "" + +#: models.py:90 views.py:559 +msgid "document type" +msgstr "" + +#: models.py:91 +msgid "default metadata sets" +msgstr "" + +#: models.py:98 +msgid "document type defaults" +msgstr "" + +#: models.py:99 +msgid "document types defaults" +msgstr "" + +#: views.py:38 views.py:193 +msgid "The selected document doesn't have any metadata." +msgstr "" + +#: views.py:43 views.py:131 views.py:199 +msgid "Must provide at least one document." +msgstr "" + +#: views.py:78 views.py:234 +#, python-format +msgid "Error deleting document indexes; %s" +msgstr "" + +#: views.py:90 +#, python-format +msgid "Error editing metadata for document %(document)s; %(error)s." +msgstr "" + +#: views.py:93 +#, python-format +msgid "Metadata for document %s edited successfully." +msgstr "" + +#: views.py:98 views.py:251 +#, python-format +msgid "Error updating document indexes; %s" +msgstr "" + +#: views.py:100 views.py:253 +msgid "Document indexes updated successfully." +msgstr "" + +#: views.py:111 +#, python-format +msgid "Edit metadata for document: %s" +msgstr "" + +#: views.py:113 +#, python-format +msgid "Edit metadata for documents: %s" +msgstr "" + +#: views.py:148 +#, python-format +msgid "" +"Metadata type: %(metadata_type)s successfully added to document " +"%(document)s." +msgstr "" + +#: views.py:151 +#, python-format +msgid "" +"Metadata type: %(metadata_type)s already present in document %(document)s." +msgstr "" + +#: views.py:175 +#, python-format +msgid "Add metadata type to document: %s" +msgstr "" + +#: views.py:177 +#, python-format +msgid "Add metadata type to documents: %s" +msgstr "" + +#: views.py:242 +#, python-format +msgid "" +"Successfully remove metadata type: %(metadata_type)s from document: " +"%(document)s." +msgstr "" + +#: views.py:245 +#, python-format +msgid "" +"Error removing metadata type: %(metadata_type)s from document: %(document)s." +msgstr "" + +#: views.py:264 +#, python-format +msgid "Remove metadata types from document: %s" +msgstr "" + +#: views.py:266 +#, python-format +msgid "Remove metadata types from documents: %s" +msgstr "" + +#: views.py:281 +#, python-format +msgid "metadata for: %s" +msgstr "" + +#: views.py:298 +msgid "internal name" +msgstr "" + +#: views.py:319 +msgid "Metadata type edited successfully" +msgstr "" + +#: views.py:322 +#, python-format +msgid "Error editing metadata type; %s" +msgstr "" + +#: views.py:328 +#, python-format +msgid "edit metadata type: %s" +msgstr "" + +#: views.py:343 +msgid "Metadata type created successfully" +msgstr "" + +#: views.py:349 +msgid "create metadata type" +msgstr "" + +#: views.py:368 +#, python-format +msgid "Metadata type: %s deleted successfully." +msgstr "" + +#: views.py:370 +#, python-format +msgid "Metadata type: %(metadata_type)s delete error: %(error)s" +msgstr "" + +#: views.py:381 +#, python-format +msgid "Are you sure you wish to delete the metadata type: %s?" +msgstr "" + +#: views.py:398 +msgid "members" +msgstr "" + +#: views.py:442 +#, python-format +msgid "non members of metadata set: %s" +msgstr "" + +#: views.py:443 +#, python-format +msgid "members of metadata set: %s" +msgstr "" + +#: views.py:458 +msgid "Metadata set created successfully" +msgstr "" + +#: views.py:464 +msgid "create metadata set" +msgstr "" + +#: views.py:483 +#, python-format +msgid "Metadata set: %s deleted successfully." +msgstr "" + +#: views.py:485 +#, python-format +msgid "Metadata set: %(metadata_set)s delete error: %(error)s" +msgstr "" + +#: views.py:496 +#, python-format +msgid "Are you sure you wish to delete the metadata set: %s?" +msgstr "" + +#: views.py:554 +#, python-format +msgid "non members of document type: %s" +msgstr "" + +#: views.py:555 +#, 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/navigation/locale/it/LC_MESSAGES/django.mo b/apps/navigation/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..086ca792fb --- /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: +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-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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" + +#: forms.py:14 +msgid "Multi item action" +msgstr "" + +#: widgets.py:28 +msgid "icon" +msgstr "" + +#: templatetags/navigation_tags.py:275 +msgid "Selected item actions:" +msgstr "" + + 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 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..dd3f06215a --- /dev/null +++ b/apps/ocr/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,448 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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: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 +msgid "submit to OCR queue" +msgstr "" + +#: __init__.py:45 __init__.py:46 +msgid "re-queue" +msgstr "" + +#: __init__.py:47 __init__.py:48 __init__.py:63 +msgid "delete" +msgstr "" + +#: __init__.py:50 +msgid "stop queue" +msgstr "" + +#: __init__.py:51 +msgid "activate queue" +msgstr "" + +#: __init__.py:53 +msgid "clean up pages content" +msgstr "" + +#: __init__.py:53 +msgid "" +"Runs a language filter to remove common OCR mistakes from document pages " +"content." +msgstr "" + +#: __init__.py:55 +msgid "queue document list" +msgstr "" + +#: __init__.py:58 views.py:316 +msgid "active tasks" +msgstr "" + +#: __init__.py:60 +msgid "transformations" +msgstr "" + +#: __init__.py:61 +msgid "add transformation" +msgstr "" + +#: __init__.py:62 +msgid "edit" +msgstr "" + +#: __init__.py:82 +msgid "Default" +msgstr "" + +#: __init__.py:104 +msgid "Checks the OCR queue for pending documents." +msgstr "" + +#: api.py:119 +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:22 +msgid "name" +msgstr "" + +#: models.py:23 +msgid "label" +msgstr "" + +#: models.py:27 models.py:47 +msgid "state" +msgstr "" + +#: models.py:32 models.py:40 views.py:44 views.py:337 views.py:378 +#: views.py:408 views.py:444 +msgid "document queue" +msgstr "" + +#: models.py:33 +msgid "document queues" +msgstr "" + +#: models.py:41 +msgid "document" +msgstr "" + +#: models.py:42 +msgid "date time submitted" +msgstr "" + +#: models.py:43 +msgid "delay ocr" +msgstr "" + +#: models.py:48 +msgid "result" +msgstr "" + +#: models.py:49 +msgid "node name" +msgstr "" + +#: models.py:53 +msgid "queue document" +msgstr "" + +#: models.py:54 +msgid "queue documents" +msgstr "" + +#: models.py:63 views.py:48 +msgid "Missing document." +msgstr "" + +#: models.py:67 +msgid "Enter a valid value." +msgstr "" + +#: models.py:95 views.py:341 +msgid "order" +msgstr "" + +#: models.py:96 views.py:342 views.py:379 views.py:409 +msgid "transformation" +msgstr "" + +#: models.py:97 views.py:343 +msgid "arguments" +msgstr "" + +#: models.py:97 +#, python-format +msgid "Use dictionaries to indentify arguments, example: %s" +msgstr "" + +#: models.py:107 +msgid "document queue transformation" +msgstr "" + +#: models.py:108 +msgid "document queue transformations" +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:41 +#, python-format +msgid "documents in queue: %s" +msgstr "" + +#: views.py:49 +msgid "thumbnail" +msgstr "" + +#: views.py:62 +msgid "document queue properties" +msgstr "" + +#: views.py:63 +#, python-format +msgid "Current state: %s" +msgstr "" + +#: views.py:79 views.py:154 +msgid "Must provide at least one queue document." +msgstr "" + +#: views.py:89 +#, python-format +msgid "Document: %s is being processed and can't be deleted." +msgstr "" + +#: views.py:92 +#, python-format +msgid "Queue document: %(document)s deleted successfully." +msgstr "" + +#: views.py:96 +#, python-format +msgid "Error deleting document: %(document)s; %(error)s" +msgstr "" + +#: views.py:109 +#, python-format +msgid "Are you sure you wish to delete queue document: %s?" +msgstr "" + +#: views.py:111 +#, python-format +msgid "Are you sure you wish to delete queue documents: %s?" +msgstr "" + +#: views.py:134 +#, python-format +msgid "Document: %(document)s was added to the OCR queue: %(queue)s." +msgstr "" + +#: views.py:137 +#, 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 +#, python-format +msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s" +msgstr "" + +#: views.py:176 +#, python-format +msgid "Document id#: %d, no longer exists." +msgstr "" + +#: views.py:189 +#, python-format +msgid "Are you sure you wish to re-queue document: %s?" +msgstr "" + +#: views.py:191 +#, python-format +msgid "Are you sure you wish to re-queue documents: %s?" +msgstr "" + +#: views.py:209 +#, python-format +msgid "Document queue: %s, already stopped." +msgstr "" + +#: views.py:215 +#, python-format +msgid "Document queue: %s, stopped successfully." +msgstr "" + +#: views.py:221 +#, python-format +msgid "Are you sure you wish to disable document queue: %s" +msgstr "" + +#: views.py:236 +#, python-format +msgid "Document queue: %s, already active." +msgstr "" + +#: views.py:242 +#, python-format +msgid "Document queue: %s, activated successfully." +msgstr "" + +#: views.py:248 +#, python-format +msgid "Are you sure you wish to activate document queue: %s" +msgstr "" + +#: views.py:265 +msgid "Are you sure you wish to clean up all the pages content?" +msgstr "" + +#: views.py:266 +msgid "On large databases this operation may take some time to execute." +msgstr "" + +#: views.py:272 +msgid "Document pages content clean up complete." +msgstr "" + +#: views.py:274 +#, 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 +#, python-format +msgid "transformations for: %s" +msgstr "" + +#: views.py:365 +msgid "Queue transformation edited successfully" +msgstr "" + +#: views.py:368 +#, python-format +msgid "Error editing queue transformation; %s" +msgstr "" + +#: views.py:373 +#, python-format +msgid "Edit transformation: %s" +msgstr "" + +#: views.py:396 +msgid "Queue transformation deleted successfully." +msgstr "" + +#: views.py:398 +#, python-format +msgid "Error deleting queue transformation; %(error)s" +msgstr "" + +#: views.py:411 +#, python-format +msgid "" +"Are you sure you wish to delete queue transformation \"%(transformation)s\"" +msgstr "" + +#: views.py:434 +msgid "Queue transformation created successfully" +msgstr "" + +#: views.py:437 +#, python-format +msgid "Error creating queue transformation; %s" +msgstr "" + +#: views.py:446 +#, 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 "" +"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 +msgid "Text extracted from PDF" +msgstr "" + + 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 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..11a0b7b7f7 --- /dev/null +++ b/apps/permissions/locale/it/LC_MESSAGES/django.po @@ -0,0 +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: +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-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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: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 +msgid "roles" +msgstr "" + +#: __init__.py:20 +msgid "create new role" +msgstr "" + +#: __init__.py:21 +msgid "edit" +msgstr "" + +#: __init__.py:22 +msgid "members" +msgstr "" + +#: __init__.py:23 +msgid "role permissions" +msgstr "" + +#: __init__.py:24 +msgid "delete" +msgstr "" + +#: __init__.py:26 +msgid "grant" +msgstr "" + +#: __init__.py:27 +msgid "revoke" +msgstr "" + +#: api.py:22 +msgid "Permissions" +msgstr "" + +#: api.py:55 +msgid "Insufficient permissions." +msgstr "" + +#: models.py:11 views.py:58 +msgid "namespace" +msgstr "" + +#: models.py:12 views.py:59 +msgid "name" +msgstr "" + +#: models.py:13 models.py:82 +msgid "label" +msgstr "" + +#: models.py:20 models.py:65 views.py:145 views.py:204 +msgid "permission" +msgstr "" + +#: models.py:21 views.py:55 views.py:147 views.py:206 +msgid "permissions" +msgstr "" + +#: models.py:73 +msgid "permission holder" +msgstr "" + +#: models.py:74 +msgid "permission holders" +msgstr "" + +#: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115 +#: views.py:282 +msgid "role" +msgstr "" + +#: models.py:115 +msgid "role member" +msgstr "" + +#: models.py:116 +msgid "role members" +msgstr "" + +#: views.py:61 +msgid "has permission" +msgstr "" + +#: views.py:142 views.py:201 +msgid " and " +msgstr "" + +#: views.py:142 views.py:201 +#, python-format +msgid "%(permissions)s to %(requester)s" +msgstr "" + +#: views.py:152 +#, python-format +msgid "Permission \"%(permission)s\" granted to: %(requester)s." +msgstr "" + +#: views.py:155 +#, python-format +msgid "%(requester)s, already had the permission \"%(permission)s\" granted." +msgstr "" + +#: views.py:167 +#, python-format +msgid "" +"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" +msgstr "" + +#: views.py:211 +#, python-format +msgid "Permission \"%(permission)s\" revoked from: %(requester)s." +msgstr "" + +#: views.py:214 +#, python-format +msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." +msgstr "" + +#: views.py:226 +#, python-format +msgid "" +"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" +msgstr "" + +#: views.py:278 +#, python-format +msgid "non members of role: %s" +msgstr "" + +#: views.py:279 +#, python-format +msgid "members of role: %s" +msgstr "" + +#: widgets.py:16 +msgid "Revoke" +msgstr "" + +#: 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/project_setup/locale/it/LC_MESSAGES/django.mo b/apps/project_setup/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0eb804bd170782f648845e1ba0dc2ee18f6e7c7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8fKp)BU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n27rlVJb= literal 0 HcmV?d00001 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..966177ce1a --- /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: +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-09-30 04:42+0000\n" +"Last-Translator: FULL NAME \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:6 +msgid "setup" +msgstr "" + +#: views.py:13 +msgid "setup items" +msgstr "" + + 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 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..086a78ab58 --- /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: +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-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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:7 views.py:13 +msgid "tools" +msgstr "" + + 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 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..c6838fcd25 --- /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: +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-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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:8 views.py:26 +msgid "settings" +msgstr "" + +#: views.py:31 +msgid "name" +msgstr "" + +#: views.py:32 +msgid "default" +msgstr "" + +#: views.py:33 +msgid "value" +msgstr "" + + 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 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..a03efbdf8a --- /dev/null +++ b/apps/sources/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,462 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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: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 +msgid "delete" +msgstr "" + +#: __init__.py:28 +msgid "sources" +msgstr "" + +#: __init__.py:29 literals.py:53 models.py:159 +msgid "web forms" +msgstr "" + +#: __init__.py:30 models.py:130 +msgid "staging folders" +msgstr "" + +#: __init__.py:31 models.py:194 +msgid "watch folders" +msgstr "" + +#: __init__.py:33 __init__.py:39 +msgid "edit" +msgstr "" + +#: __init__.py:35 +msgid "add new source" +msgstr "" + +#: __init__.py:37 +msgid "transformations" +msgstr "" + +#: __init__.py:38 +msgid "add transformation" +msgstr "" + +#: __init__.py:42 +msgid "Document sources" +msgstr "" + +#: __init__.py:69 widgets.py:39 +msgid "thumbnail" +msgstr "" + +#: forms.py:32 forms.py:55 +msgid "Expand compressed files" +msgstr "" + +#: forms.py:33 forms.py:56 +msgid "Upload a compressed file's contained files as individual documents" +msgstr "" + +#: forms.py:41 +msgid "Staging file" +msgstr "" + +#: literals.py:8 literals.py:13 +msgid "Always" +msgstr "" + +#: literals.py:9 literals.py:14 +msgid "Never" +msgstr "" + +#: literals.py:15 +msgid "Ask user" +msgstr "" + +#: literals.py:30 +msgid "Disk" +msgstr "" + +#: literals.py:31 +msgid "Database" +msgstr "" + +#: literals.py:32 +msgid "Drive" +msgstr "" + +#: literals.py:33 +msgid "Network drive" +msgstr "" + +#: literals.py:34 +msgid "User drive" +msgstr "" + +#: literals.py:35 +msgid "Envelope" +msgstr "" + +#: literals.py:36 +msgid "Folder" +msgstr "" + +#: literals.py:37 +msgid "World" +msgstr "" + +#: literals.py:38 +msgid "Printer" +msgstr "" + +#: literals.py:39 +msgid "Empty printer" +msgstr "" + +#: literals.py:47 models.py:158 +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:29 +msgid "title" +msgstr "" + +#: models.py:30 +msgid "enabled" +msgstr "" + +#: models.py:31 +msgid "whitelist" +msgstr "" + +#: models.py:32 +msgid "blacklist" +msgstr "" + +#: models.py:98 +msgid "icon" +msgstr "" + +#: models.py:98 +msgid "An icon to visually distinguish this source." +msgstr "" + +#: models.py:114 models.py:166 +msgid "folder path" +msgstr "" + +#: models.py:114 models.py:166 +msgid "Server side filesystem path." +msgstr "" + +#: models.py:115 +msgid "preview width" +msgstr "" + +#: models.py:115 +msgid "Width value to be passed to the converter backend." +msgstr "" + +#: models.py:116 +msgid "preview height" +msgstr "" + +#: models.py:116 +msgid "Height value to be passed to the converter backend." +msgstr "" + +#: models.py:117 models.py:154 models.py:167 +msgid "uncompress" +msgstr "" + +#: models.py:117 models.py:154 models.py:167 +msgid "Whether to expand or not compressed archives." +msgstr "" + +#: models.py:118 models.py:168 +msgid "delete after upload" +msgstr "" + +#: models.py:118 models.py:168 +msgid "Delete the file after is has been successfully uploaded." +msgstr "" + +#: models.py:129 +msgid "staging folder" +msgstr "" + +#: models.py:169 +msgid "interval" +msgstr "" + +#: models.py:169 +msgid "" +"Inverval in seconds where the watch folder path is checked for new " +"documents." +msgstr "" + +#: models.py:193 +msgid "watch folder" +msgstr "" + +#: models.py:198 +msgid "Enter a valid value." +msgstr "" + +#: models.py:226 views.py:487 +msgid "order" +msgstr "" + +#: models.py:227 views.py:488 views.py:525 views.py:555 +msgid "transformation" +msgstr "" + +#: models.py:228 views.py:489 +msgid "arguments" +msgstr "" + +#: models.py:228 +#, python-format +msgid "Use dictionaries to indentify arguments, example: %s" +msgstr "" + +#: models.py:239 +msgid "document source transformation" +msgstr "" + +#: models.py:240 +msgid "document source transformations" +msgstr "" + +#: staging.py:42 +#, python-format +msgid "Unable get list of staging files: %s" +msgstr "" + +#: staging.py:127 +#, python-format +msgid "Unable to upload staging file: %s" +msgstr "" + +#: staging.py:137 +#, python-format +msgid "Unable to delete staging file: %s" +msgstr "" + +#: utils.py:40 +msgid "Whitelist Blacklist validation error." +msgstr "" + +#: views.py:80 +msgid "here" +msgstr "" + +#: views.py:85 +msgid "Upload sources" +msgstr "" + +#: views.py:87 +msgid "" +"No interactive document sources have been defined or none have been enabled." +msgstr "" + +#: views.py:88 +#, python-format +msgid "Click %(setup_link)s to add or enable some document sources." +msgstr "" + +#: views.py:136 +msgid "Document uploaded successfully." +msgstr "" + +#: views.py:152 +#, python-format +msgid "upload a local document from source: %s" +msgstr "" + +#: views.py:182 +#, python-format +msgid "Staging file: %s, uploaded successfully." +msgstr "" + +#: views.py:187 +#, python-format +msgid "Staging file: %s, deleted successfully." +msgstr "" + +#: views.py:209 +#, python-format +msgid "upload a document from staging source: %s" +msgstr "" + +#: views.py:215 +msgid "files in staging path" +msgstr "" + +#: views.py:229 +msgid "Current metadata" +msgstr "" + +#: views.py:265 views.py:284 +#, python-format +msgid "Staging file transformation error: %(error)s" +msgstr "" + +#: views.py:307 +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 "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 editing source transformation; %s" +msgstr "" + +#: views.py:519 +#, python-format +msgid "Edit transformation: %s" +msgstr "" + +#: views.py:542 +msgid "Source transformation deleted successfully." +msgstr "" + +#: views.py:544 +#, python-format +msgid "Error deleting source transformation; %(error)s" +msgstr "" + +#: views.py:557 +#, python-format +msgid "" +"Are you sure you wish to delete source transformation \"%(transformation)s\"" +msgstr "" + +#: views.py:587 +msgid "Source transformation created successfully" +msgstr "" + +#: views.py:590 +#, python-format +msgid "Error creating source transformation; %s" +msgstr "" + +#: views.py:599 +#, python-format +msgid "Create new transformation for source: %s" +msgstr "" + + 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 0000000000000000000000000000000000000000..34e8cee481a6504dbbaf0d0a1d235e31ce9135f7 GIT binary patch literal 501 zcmYjN%Wm5+5KPdXbnLl@Ezm=Pc1=n(0*9%KIDT06 z@-11#MbZHWU&lNVt&ctN- zv&5@lG;vv+YBCBknWo4m%OFivc7}2&B@1z7{@A|#|2lb&UnIz(8m6BlBU$K3SO)E4 zt;q)kv+KnIeoTrSzUIYbzW6?wPFMMQ{f(ur>U3qWG`dkRCtX{1b@Ffa{eC~7zL32& zcLQfgw1-VZ(H=~o*)~xSXA4W>G%4mq{<@=dAd@Ta$T%M8zGY`*?zl*;t-FBDPKRh{ zd|l3P^s4Lo-I{>8+xV?@m4eZYrI%3^aImbqplh7@&_o5UeGcO|yMV)UeB$847}C?^ F=n24VlVAV< literal 0 HcmV?d00001 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..d1a19e1f40 --- /dev/null +++ b/apps/tags/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,267 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:41+0000\n" +"Last-Translator: FULL NAME \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: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 +msgid "create new tag" +msgstr "" + +#: __init__.py:30 +msgid "attach tag" +msgstr "" + +#: __init__.py:31 __init__.py:32 +msgid "remove" +msgstr "" + +#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 +msgid "tags" +msgstr "" + +#: __init__.py:34 __init__.py:37 +msgid "delete" +msgstr "" + +#: __init__.py:35 +msgid "edit" +msgstr "" + +#: __init__.py:36 +msgid "tagged documents" +msgstr "" + +#: __init__.py:41 models.py:46 +msgid "color" +msgstr "" + +#: __init__.py:45 +msgid "color name" +msgstr "" + +#: forms.py:14 +msgid "New tag" +msgstr "" + +#: forms.py:15 forms.py:24 +msgid "Color" +msgstr "" + +#: forms.py:16 +msgid "Existing tags" +msgstr "" + +#: forms.py:23 +msgid "Name" +msgstr "" + +#: models.py:18 +msgid "Blue" +msgstr "" + +#: models.py:19 +msgid "Cyan" +msgstr "" + +#: models.py:20 +msgid "Coral" +msgstr "" + +#: models.py:21 +msgid "Green-Yellow" +msgstr "" + +#: models.py:22 +msgid "Khaki" +msgstr "" + +#: models.py:23 +msgid "LightGrey" +msgstr "" + +#: models.py:24 +msgid "Magenta" +msgstr "" + +#: models.py:25 +msgid "Red" +msgstr "" + +#: models.py:26 +msgid "Orange" +msgstr "" + +#: models.py:27 +msgid "Yellow" +msgstr "" + +#: models.py:45 views.py:185 views.py:233 views.py:248 +msgid "tag" +msgstr "" + +#: models.py:49 +msgid "tag properties" +msgstr "" + +#: models.py:50 +msgid "tags properties" +msgstr "" + +#: views.py:33 +msgid "Tag already exists." +msgstr "" + +#: views.py:40 +msgid "Tag created succesfully." +msgstr "" + +#: views.py:46 +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 +#, 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 +#, python-format +msgid "Tag \"%s\" attached successfully." +msgstr "" + +#: views.py:133 +#, python-format +msgid "attach tag to: %s" +msgstr "" + +#: views.py:149 +msgid "tagged items" +msgstr "" + +#: views.py:166 views.py:280 +msgid "Must provide at least one tag." +msgstr "" + +#: views.py:176 +#, python-format +msgid "Tag \"%s\" deleted successfully." +msgstr "" + +#: views.py:178 views.py:294 +#, python-format +msgid "Error deleting tag \"%(tag)s\": %(error)s" +msgstr "" + +#: views.py:193 +#, python-format +msgid "Are you sure you wish to delete the tag: %s?" +msgstr "" + +#: views.py:194 views.py:197 +msgid "Will be removed from all documents." +msgstr "" + +#: views.py:196 +#, python-format +msgid "Are you sure you wish to delete the tags: %s?" +msgstr "" + +#: views.py:221 +msgid "Tag updated succesfully." +msgstr "" + +#: views.py:230 +#, python-format +msgid "edit tag: %s" +msgstr "" + +#: views.py:245 +#, python-format +msgid "documents with the tag \"%s\"" +msgstr "" + +#: views.py:258 +#, python-format +msgid "tags for: %s" +msgstr "" + +#: views.py:292 +#, python-format +msgid "Tag \"%s\" removed successfully." +msgstr "" + +#: views.py:308 +#, python-format +msgid "Are you sure you wish to remove the tag: %s?" +msgstr "" + +#: views.py:310 +#, 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/user_management/locale/it/LC_MESSAGES/django.mo b/apps/user_management/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..72cbfdd28e96e44641807cba5841648db40f9397 GIT binary patch literal 501 zcmYjNO-~y!5T$BQd+fP~sl)-)PV8Nv3Z|(@$wrElg(z8iH;LJ}+O=2qYy&@pU&DXt zZ|Q7PL7)6&kNoE2&F}Z`o(>pqm>-yj%(u+X%pODLGk>1*-D_U32>z#86V5jH!-QzP zQ&8wf?I52Nt7K_f9|((B*$sa0s)(gmuqA4h5S68EcQ;u3Mg$*qus(>U&lNVt&ctMK zQ{q)Hnz$@ZG#Le%OjG2OWss&S`-1XRN*3bM{IY%f|8?>lPbA1wb$0eiGLpHDgk{h! z)|z}!Fuk46;d)%;@HH>Sv-#zCGFj%U)i;*9s?(Lh(&$FPjC5_;)zQD%ce~wy`a<^J zJPe#6(e5`9MY}hFX46DLoGmPg&Kg06AuLlYIa_HP(R*#+#Mqaz0&N01&T G2Y&#?){|ub literal 0 HcmV?d00001 diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.po b/apps/user_management/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..5e5ae7a353 --- /dev/null +++ b/apps/user_management/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,254 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-09-30 04:55+0000\n" +"Last-Translator: FULL NAME \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:8 +msgid "Create new users" +msgstr "" + +#: __init__.py:9 +msgid "Edit existing users" +msgstr "" + +#: __init__.py:10 +msgid "View existing users" +msgstr "" + +#: __init__.py:11 +msgid "Delete existing users" +msgstr "" + +#: __init__.py:13 +msgid "Create new groups" +msgstr "" + +#: __init__.py:14 +msgid "Edit existing groups" +msgstr "" + +#: __init__.py:15 +msgid "View existing groups" +msgstr "" + +#: __init__.py:16 +msgid "Delete existing groups" +msgstr "" + +#: __init__.py:18 +msgid "User management" +msgstr "" + +#: __init__.py:28 +msgid "user list" +msgstr "" + +#: __init__.py:29 views.py:31 +msgid "users" +msgstr "" + +#: __init__.py:30 __init__.py:39 +msgid "edit" +msgstr "" + +#: __init__.py:31 views.py:92 +msgid "create new user" +msgstr "" + +#: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 +msgid "delete" +msgstr "" + +#: __init__.py:34 __init__.py:35 +msgid "reset password" +msgstr "" + +#: __init__.py:37 +msgid "group list" +msgstr "" + +#: __init__.py:38 views.py:222 +msgid "groups" +msgstr "" + +#: __init__.py:40 views.py:270 +msgid "create new group" +msgstr "" + +#: __init__.py:43 views.py:226 +msgid "members" +msgstr "" + +#: forms.py:13 +msgid "New password" +msgstr "" + +#: forms.py:14 +msgid "Confirm password" +msgstr "" + +#: views.py:35 +msgid "full name" +msgstr "" + +#: views.py:39 +msgid "email" +msgstr "" + +#: views.py:43 +msgid "active" +msgstr "" + +#: views.py:58 +msgid "" +"Super user and staff user editing is not allowed, use the admin interface " +"for these cases." +msgstr "" + +#: views.py:65 +#, python-format +msgid "User \"%s\" updated successfully." +msgstr "" + +#: views.py:71 +#, python-format +msgid "edit user: %s" +msgstr "" + +#: views.py:74 views.py:130 views.py:193 +msgid "user" +msgstr "" + +#: views.py:86 +#, python-format +msgid "User \"%s\" created successfully." +msgstr "" + +#: views.py:108 views.py:162 +msgid "Must provide at least one user." +msgstr "" + +#: views.py:118 +msgid "" +"Super user and staff user deleting is not allowed, use the admin interface " +"for these cases." +msgstr "" + +#: views.py:121 +#, python-format +msgid "User \"%s\" deleted successfully." +msgstr "" + +#: views.py:123 +#, python-format +msgid "Error deleting user \"%(user)s\": %(error)s" +msgstr "" + +#: views.py:138 +#, python-format +msgid "Are you sure you wish to delete the user: %s?" +msgstr "" + +#: views.py:140 +#, python-format +msgid "Are you sure you wish to delete the users: %s?" +msgstr "" + +#: views.py:173 +msgid "Passwords do not match, try again." +msgstr "" + +#: views.py:178 +msgid "" +"Super user and staff user password reseting is not allowed, use the admin " +"interface for these cases." +msgstr "" + +#: views.py:182 +#, python-format +msgid "Successfull password reset for user: %s." +msgstr "" + +#: views.py:184 +#, python-format +msgid "Error reseting password for user \"%(user)s\": %(error)s" +msgstr "" + +#: views.py:200 +#, python-format +msgid "Reseting password for user: %s" +msgstr "" + +#: views.py:202 +#, python-format +msgid "Reseting password for users: %s" +msgstr "" + +#: views.py:243 +#, python-format +msgid "Group \"%s\" updated successfully." +msgstr "" + +#: views.py:249 +#, python-format +msgid "edit group: %s" +msgstr "" + +#: views.py:252 views.py:305 views.py:350 +msgid "group" +msgstr "" + +#: views.py:264 +#, python-format +msgid "Group \"%s\" created successfully." +msgstr "" + +#: views.py:286 +msgid "Must provide at least one group." +msgstr "" + +#: views.py:296 +#, python-format +msgid "Group \"%s\" deleted successfully." +msgstr "" + +#: views.py:298 +#, python-format +msgid "Error deleting group \"%(group)s\": %(error)s" +msgstr "" + +#: views.py:313 +#, python-format +msgid "Are you sure you wish to delete the group: %s?" +msgstr "" + +#: views.py:315 +#, python-format +msgid "Are you sure you wish to delete the groups: %s?" +msgstr "" + +#: views.py:345 +#, python-format +msgid "non members of group: %s" +msgstr "" + +#: views.py:346 +#, python-format +msgid "members of group: %s" +msgstr "" + + diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.mo b/apps/web_theme/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..dec8509d2476cd85c7d29c827507779e32e37d0f GIT binary patch literal 501 zcmZ8d%TB{E5Cp*~N6s7;i312+C!s>cP(*1{sZs+~n{qd;NsSUavNseygs@ zKr%>Y!Bkb&AxnL(m+ZFAJ<$JWA@+*vQ3wvLxgF4x}I$_JDCjP;$8 zNM+eTq7o2?QN-xPF+`Dw&so?GLlUy7deKe$f4cAt;z+dPlaLUMrAL-IX?!8kIswD^ zcno*FG=Zxm?TyAay}@9b%x2dlHF+&_#WE#J0V9-!CRay4v#;0d7B+?SlX`6#g}mBq z!t-ilf~jTcIZ`&)$d7|`lqP>WidtdNw+5A=f!-=|hU%4y6jGZ@SgfS;3cK@c$U1+z zrr(otEHMka)Fv0udDQqjssIWmMeSt4hSrr{fT_Mi-;FO}^XwiOIOsxj9Bh37xR;Yz literal 0 HcmV?d00001 diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.po b/apps/web_theme/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..69086d2e50 --- /dev/null +++ b/apps/web_theme/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,76 @@ +# 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: 2011-11-22 11:26-0400\n" +"PO-Revision-Date: 2011-11-03 21:42+0000\n" +"Last-Translator: FULL NAME \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" + +#: conf/settings.py:10 +msgid "" +"CSS theme to apply, options are: amro, bec, bec-green, blue, default, djime-" +"cerulean, drastic-dark, kathleene, olive, orange, red, reidb-greenish and " +"warehouse." +msgstr "" + +#: conf/settings.py:12 +msgid "Display extra information in the login screen." +msgstr "" + +#: templates/web_theme_base.html:101 +msgid "dismiss all notifications" +msgstr "" + +#: templates/web_theme_base.html:101 +msgid "close all" +msgstr "" + +#: templates/web_theme_base.html:102 +msgid "dismiss this notification" +msgstr "" + +#: templates/web_theme_base.html:102 +msgid "close" +msgstr "" + +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 +msgid "Login" +msgstr "" + +#: templates/web_theme_login.html:17 +msgid "You are already logged in" +msgstr "" + +#: templates/web_theme_login.html:20 +msgid "Redirecting you to the website entry point in 5 seconds." +msgstr "" + +#: templates/web_theme_login.html:23 +#, python-format +msgid "" +"Or click here if redirection doesn't " +"work." +msgstr "" + +#: templates/pagination/pagination.html:6 +#: templates/pagination/pagination.html:8 +msgid "Previous" +msgstr "" + +#: templates/pagination/pagination.html:26 +#: templates/pagination/pagination.html:28 +msgid "Next" +msgstr "" + + From 18cc876da8e871afa79aed97d45fb6ba43b0735b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 7 Dec 2011 15:54:53 -0400 Subject: [PATCH 029/484] Add Pierpaolo Baldan to the contributors file, sort translator by language --- docs/contributors.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/contributors.rst b/docs/contributors.rst index cae85f3c13..45689b59da 100644 --- a/docs/contributors.rst +++ b/docs/contributors.rst @@ -38,6 +38,10 @@ Suggestions Translations ------------ -* Emerson Soares (http://emersonsoares.com) -* Renata Oliveira (https://twitter.com/#!/rnataoliveira) -* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) +* Portuguese + * Emerson Soares (http://emersonsoares.com) + * Renata Oliveira (https://twitter.com/#!/rnataoliveira) +* Russian + * Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) +* Italian + * Pierpaolo Baldan From 563a1d176fb08d8b18a738ba8ebad9c438cb0c79 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:35:26 -0400 Subject: [PATCH 030/484] Update permission app to the new class based permissions --- apps/permissions/__init__.py | 16 +++-- apps/permissions/admin.py | 4 +- apps/permissions/api.py | 68 ------------------ apps/permissions/managers.py | 25 +++---- apps/permissions/models.py | 129 +++++++++++++++++++++++++++++++---- apps/permissions/runtime.py | 7 -- apps/permissions/views.py | 41 ++++++----- 7 files changed, 161 insertions(+), 129 deletions(-) diff --git a/apps/permissions/__init__.py b/apps/permissions/__init__.py index e143c8bbb8..8099230638 100644 --- a/apps/permissions/__init__.py +++ b/apps/permissions/__init__.py @@ -7,14 +7,16 @@ 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 permissions.models import Role, Permission, PermissionNamespace -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')} +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')) role_list = {'text': _(u'roles'), 'view': 'role_list', 'famfam': 'medal_gold_1', 'icon': 'medal_gold_1.png', 'permissions': [PERMISSION_ROLE_VIEW]} role_create = {'text': _(u'create new role'), 'view': 'role_create', 'famfam': 'medal_gold_add', 'permissions': [PERMISSION_ROLE_CREATE]} diff --git a/apps/permissions/admin.py b/apps/permissions/admin.py index 1728199d71..b370b77498 100644 --- a/apps/permissions/admin.py +++ b/apps/permissions/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from permissions.models import Permission, PermissionHolder, Role, RoleMember +from permissions.models import StoredPermission, PermissionHolder, Role, RoleMember class PermissionHolderInline(admin.StackedInline): @@ -27,5 +27,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 4b469d092d..8b13789179 100644 --- a/apps/permissions/api.py +++ b/apps/permissions/api.py @@ -1,69 +1 @@ -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 -from permissions.runtime import namespace_titles, permission_titles - - -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() - permission_titles['%s.%s' % (permission['namespace'], permission['name'])] = permission['label'] - 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.')) - - -def get_permission_label(permission): - return unicode(permission_titles.get('%s.%s' % (permission.namespace, permission.name), permission.label)) - - -def get_permission_namespace_label(permission): - return namespace_titles[permission.namespace] if permission.namespace in namespace_titles else permission.namespace - - -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/managers.py b/apps/permissions/managers.py index 919bb720bd..a6d5cc4722 100644 --- a/apps/permissions/managers.py +++ b/apps/permissions/managers.py @@ -1,7 +1,14 @@ +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 permissions.runtime import permission_titles +logger = logging.getLogger(__name__) class RoleMemberManager(models.Manager): @@ -10,19 +17,7 @@ class RoleMemberManager(models.Manager): 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.active_only().filter(permissionholder__holder_type=ct).filter(permissionholder__holder_id=holder.pk) - - def active_only(self): - namespaces = [] - names = [] - for key in permission_titles: - namespace, name = key.split(u'.') - if namespace: - namespaces.append(namespace) - if name: - names.append(name) - - return super(PermissionManager, self).get_query_set().filter(namespace__in=namespaces).filter(name__in=names).exclude(label=u'') + return self.model.objects.filter(permissionholder__holder_type=ct).filter(permissionholder__holder_id=holder.pk) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 8cc7c2f354..1cbbc51a2a 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -1,33 +1,140 @@ +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.contrib.auth.models import User +from django.core.exceptions import PermissionDenied -from permissions.managers import RoleMemberManager, PermissionManager -from permissions.runtime import namespace_titles, permission_titles +from permissions.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 LazyQuerySet(list): +# def __init__(self, model, items): +# self.model = model +# self.items = items +# +# def get(self, *args, **kwargs): +# print args +# print kwargs + +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 + + 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 cls._permissions.values() + #return LazyQuerySet(cls, cls._permissions) + + @classmethod + def get(cls, get_dict): + if 'pk' in get_dict: + try: + 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) + + @property + def uuid(self): + return u'%s.%s' % (self.namespace.name, self.name) + + def get_stored_permission(self): + stored_permission, created = StoredPermission.objects.get_or_create( + namespace=self.namespace.name, + name=self.name, + defaults={ + 'label': self.label + } + ) + 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') unique_together = ('namespace', 'name') verbose_name = _(u'permission') verbose_name_plural = _(u'permissions') - + def __unicode__(self): - return u'%s: %s' % (self.get_namespace_label(), self.get_label()) + return unicode(self.volatile_permission) def get_holders(self): return [holder.holder_object for holder in self.permissionholder_set.all()] - def has_permission(self, requester): + def requester_has_this(self, requester): if isinstance(requester, User): if requester.is_superuser or requester.is_staff: return True @@ -60,16 +167,10 @@ class Permission(models.Model): return True except PermissionHolder.DoesNotExist: return False - - def get_label(self): - return unicode(permission_titles.get('%s.%s' % (self.namespace, self.name), self.label)) - - def get_namespace_label(self): - return unicode(namespace_titles[self.namespace]) if self.namespace in namespace_titles else self.namespace 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')}) diff --git a/apps/permissions/runtime.py b/apps/permissions/runtime.py index a56d8cfeb4..8b13789179 100644 --- a/apps/permissions/runtime.py +++ b/apps/permissions/runtime.py @@ -1,8 +1 @@ -from django.utils.translation import ugettext_lazy as _ - -namespace_titles = { - 'permissions': _(u'Permissions') -} - -permission_titles = {} diff --git a/apps/permissions/views.py b/apps/permissions/views.py index 643fe8a50f..3e4cbd4e74 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -2,7 +2,7 @@ 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 @@ -22,12 +22,11 @@ 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, get_permission_label, get_permission_namespace_label from permissions.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, @@ -41,7 +40,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) @@ -52,13 +51,13 @@ def role_permissions(request, role_id): 'name': u'generic_list_subtemplate.html', 'context': { 'title': _(u'permissions'), - 'object_list': Permission.objects.active_only(), + 'object_list': Permission.objects.all(), 'extra_columns': [ - {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: get_permission_namespace_label(x))}, - {'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))}, + {'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, @@ -83,7 +82,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={ @@ -91,7 +90,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', @@ -99,7 +98,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', '/'))) @@ -117,7 +116,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 @@ -126,7 +125,12 @@ 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']) @@ -176,7 +180,7 @@ def permission_grant(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 @@ -185,7 +189,12 @@ 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']) @@ -265,7 +274,7 @@ def remove_role_member(role, selection): 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( From e5e21177719e0dc0a022c234ec7f1f506f425e96 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:36:09 -0400 Subject: [PATCH 031/484] Update document indexing app to the new class based permissions --- apps/document_indexing/__init__.py | 11 +++++------ apps/document_indexing/views.py | 16 ++++++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 5351f8a782..8199bc862a 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -2,19 +2,18 @@ from django.utils.translation import ugettext_lazy as _ from navigation.api import register_top_menu, register_sidebar_template, \ register_links -from permissions.api import register_permission, set_namespace_title +from permissions.models import PermissionNamespace, Permission + from main.api import register_maintenance_links from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document from document_indexing.models import IndexInstance -PERMISSION_DOCUMENT_INDEXING_VIEW = {'namespace': 'document_indexing', 'name': 'document_index_view', 'label': _(u'View document indexes')} -PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES = {'namespace': 'document_indexing', 'name': 'document_rebuild_indexes', 'label': _(u'Rebuild document indexes')} +document_indexing_namespace = PermissionNamespace('document_indexing', _(u'Indexing')) -set_namespace_title('document_indexing', _(u'Indexing')) -register_permission(PERMISSION_DOCUMENT_INDEXING_VIEW) -register_permission(PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) +PERMISSION_DOCUMENT_INDEXING_VIEW = Permission.objects.register(document_indexing_namespace, 'document_index_view', _(u'View document indexes')) +PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES = Permission.objects.register(document_indexing_namespace, 'document_rebuild_indexes', _(u'Rebuild document indexes')) index_list = {'text': _(u'index list'), 'view': 'index_instance_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True} diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index a344093e6e..b79f1ad8ee 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -5,23 +5,23 @@ from django.template import RequestContext from django.contrib import messages from django.utils.safestring import mark_safe -from permissions.api import check_permissions +from permissions.models import Permission from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list from common.utils import encapsulate -from document_indexing import PERMISSION_DOCUMENT_INDEXING_VIEW, \ - PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES +from document_indexing import (PERMISSION_DOCUMENT_INDEXING_VIEW, + PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) from document_indexing.models import IndexInstance -from document_indexing.api import get_breadcrumbs, get_instance_link, \ - do_rebuild_all_indexes +from document_indexing.api import (get_breadcrumbs, get_instance_link, + do_rebuild_all_indexes) from document_indexing.widgets import index_instance_item_link def index_instance_list(request, index_id=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) if index_id: index_instance = get_object_or_404(IndexInstance, pk=index_id) @@ -70,7 +70,7 @@ def index_instance_list(request, index_id=None): def rebuild_index_instances(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES]) 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))) @@ -97,7 +97,7 @@ def rebuild_index_instances(request): def document_index_list(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW]) document = get_object_or_404(Document, pk=document_id) object_list = [] From 3ec2c05f250ff42f323d97399315492195fb8adf Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:36:39 -0400 Subject: [PATCH 032/484] Convert history app to use the new class based permissions --- apps/history/__init__.py | 8 ++++---- apps/history/views.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/history/__init__.py b/apps/history/__init__.py index c2fa615250..5ae801fa03 100644 --- a/apps/history/__init__.py +++ b/apps/history/__init__.py @@ -1,14 +1,14 @@ from django.utils.translation import ugettext_lazy as _ -from permissions.api import register_permission, set_namespace_title from project_tools.api import register_tool +from permissions.models import PermissionNamespace, Permission -PERMISSION_HISTORY_VIEW = {'namespace': 'history', 'name': u'history_view', 'label': _(u'Access the history app')} +history_namespace = PermissionNamespace('history', _(u'History')) -set_namespace_title('history', _(u'History')) -register_permission(PERMISSION_HISTORY_VIEW) +PERMISSION_HISTORY_VIEW = Permission.objects.register(history_namespace, 'history_view', _(u'Access the history app')) # TODO: support permissions AND operand +# encapsulate into document_history_list and require DOCUMENT_VIEW and HISTORY_VIEW history_list = {'text': _(u'history'), 'view': 'history_list', 'famfam': 'book', 'icon': 'book.png', 'permissions': [PERMISSION_HISTORY_VIEW], 'children_views': ['history_view']} register_tool(history_list) diff --git a/apps/history/views.py b/apps/history/views.py index c344bf0d45..dd78079e69 100644 --- a/apps/history/views.py +++ b/apps/history/views.py @@ -6,7 +6,7 @@ from django.contrib.contenttypes.models import ContentType from django.db.models.loading import get_model from django.http import Http404 -from permissions.api import check_permissions +from permissions.models import Permission from common.utils import encapsulate from history.models import History @@ -16,7 +16,7 @@ from history.widgets import history_entry_object_link, history_entry_summary def history_list(request): - check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) context = { 'object_list': History.objects.all(), @@ -43,7 +43,7 @@ def history_list(request): def history_for_object(request, app_label, module_name, object_id): - check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) model = get_model(app_label, module_name) if not model: @@ -73,7 +73,7 @@ def history_for_object(request, app_label, module_name, object_id): def history_view(request, object_id): - check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) history = get_object_or_404(History, pk=object_id) From 7de54a8102d9ad4c85fa3eb9ad8ba6362d516c14 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:37:11 -0400 Subject: [PATCH 033/484] Update metadata app to use the new class based permissions --- apps/metadata/__init__.py | 45 +++++++++++++-------------------------- apps/metadata/views.py | 28 ++++++++++++------------ 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index b61556e268..80ab8afe6a 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -2,44 +2,29 @@ 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 permissions.models import Permission, PermissionNamespace from documents.models import Document, DocumentType from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT from project_setup.api import register_setup 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')} +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')) -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')} +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 = {'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) +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')) 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']} diff --git a/apps/metadata/views.py b/apps/metadata/views.py index 028700a46d..11aa0a6b87 100644 --- a/apps/metadata/views.py +++ b/apps/metadata/views.py @@ -9,7 +9,7 @@ from django.utils.http import urlencode from documents.literals 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 common.utils import generate_choices_w_labels, encapsulate @@ -30,7 +30,7 @@ from metadata.models import DocumentMetadata, MetadataType, MetadataSet, \ def metadata_edit(request, document_id=None, document_id_list=None): - check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_EDIT]) if document_id: documents = [get_object_or_404(Document, pk=document_id)] @@ -121,7 +121,7 @@ def metadata_multiple_edit(request): def metadata_add(request, document_id=None, document_id_list=None): - check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_ADD]) + Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_ADD]) if document_id: documents = [get_object_or_404(Document, pk=document_id)] @@ -185,7 +185,7 @@ def metadata_multiple_add(request): def metadata_remove(request, document_id=None, document_id_list=None): - check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_REMOVE]) + Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_REMOVE]) if document_id: documents = [get_object_or_404(Document, pk=document_id)] @@ -274,7 +274,7 @@ def metadata_multiple_remove(request): def metadata_view(request, document_id): - check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) return render_to_response('generic_list.html', { @@ -287,7 +287,7 @@ def metadata_view(request, document_id): 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(), @@ -306,7 +306,7 @@ def setup_metadata_type_list(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) @@ -334,7 +334,7 @@ def setup_metadata_type_edit(request, metadatatype_id): 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) @@ -353,7 +353,7 @@ 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) @@ -387,7 +387,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(), @@ -429,7 +429,7 @@ 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) @@ -449,7 +449,7 @@ 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) @@ -468,7 +468,7 @@ 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) @@ -539,7 +539,7 @@ def remove_document_type_metadata(document_type, selection): 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) From bf7dea399f6d22b6f4eb9851d27919d24e76ffed Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:37:39 -0400 Subject: [PATCH 034/484] Update sources app to use the new class based permissions --- apps/sources/__init__.py | 17 ++++++----------- apps/sources/views.py | 26 +++++++++++++------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index faca4f075c..5d69ae8c1f 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -2,7 +2,7 @@ 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 permissions.models import Permission, PermissionNamespace from common.utils import encapsulate from project_setup.api import register_setup from documents.models import Document @@ -13,16 +13,11 @@ 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) +sources_namespace = PermissionNamespace('sources_setup', _(u'Sources setup')) +PERMISSION_SOURCES_SETUP_VIEW = Permission.objects.register(sources_namespace, 'sources_setup_view', _(u'View existing document sources')) +PERMISSION_SOURCES_SETUP_EDIT = Permission.objects.register(sources_namespace, 'sources_setup_edit', _(u'Edit document sources')) +PERMISSION_SOURCES_SETUP_DELETE = Permission.objects.register(sources_namespace, 'sources_setup_delete', _(u'Delete document sources')) +PERMISSION_SOURCES_SETUP_CREATE = Permission.objects.register(sources_namespace, 'sources_setup_create', _(u'Create new document sources')) 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} diff --git a/apps/sources/views.py b/apps/sources/views.py index 17e8c380a6..55c2f6829c 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -11,7 +11,7 @@ from documents.literals import PERMISSION_DOCUMENT_CREATE 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 @@ -71,7 +71,7 @@ def get_active_tab_links(document=None): } def upload_interactive(request, source_type=None, source_id=None, document_pk=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) subtemplates_list = [] @@ -315,7 +315,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 +334,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 +353,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) @@ -387,7 +387,7 @@ def staging_file_delete(request, source_type, source_id, staging_file_id): 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 @@ -409,7 +409,7 @@ def setup_source_list(request, source_type): 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 @@ -449,7 +449,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' @@ -495,7 +495,7 @@ 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 @@ -529,7 +529,7 @@ 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 @@ -561,7 +561,7 @@ def setup_source_transformation_list(request, source_type, source_id): 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]) @@ -594,7 +594,7 @@ def setup_source_transformation_edit(request, transformation_id): 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]) @@ -628,7 +628,7 @@ def setup_source_transformation_delete(request, transformation_id): 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 From 6bf9b83412d6d065e7712495433119a05c8b0edd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:42:58 -0400 Subject: [PATCH 035/484] Update the folders app to the new class based permissions --- apps/folders/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/folders/views.py b/apps/folders/views.py index b6495ffb05..567114a430 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -9,7 +9,7 @@ from django.core.exceptions import PermissionDenied from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document -from permissions.api import check_permissions +from permissions.models import Permission from common.utils import encapsulate from folders.models import Folder, FolderDocument @@ -136,7 +136,7 @@ def folder_view(request, folder_id): def folder_add_document_sidebar(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) previous = request.META.get('HTTP_REFERER', '/') @@ -170,7 +170,7 @@ def folder_add_document_sidebar(request, document_id): def folder_add_document(request, document_id): # TODO: merge with folder_add_document_sidebar - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/')))#reverse('document_tags', args=[document.pk])))) @@ -213,7 +213,7 @@ def folder_add_document(request, document_id): def document_folder_list(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) return folder_list( From 43cf4b37b0ec60401cc9fdcf082a622f22625760 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:43:30 -0400 Subject: [PATCH 036/484] Update the linking app to the new class based permissions --- apps/linking/__init__.py | 16 ++++++---------- apps/linking/views.py | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index ab1bdc616a..f64337045e 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -1,23 +1,19 @@ from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_sidebar_template -from permissions.api import register_permission, set_namespace_title +from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document from linking.models import SmartLink, SmartLinkCondition -PERMISSION_SMART_LINK_VIEW = {'namespace': 'linking', 'name': 'smart_link_view', 'label': _(u'View existing smart links')} -PERMISSION_SMART_LINK_CREATE = {'namespace': 'linking', 'name': 'smart_link_create', 'label': _(u'Create new smart links')} -PERMISSION_SMART_LINK_DELETE = {'namespace': 'linking', 'name': 'smart_link_delete', 'label': _(u'Delete smart links')} -PERMISSION_SMART_LINK_EDIT = {'namespace': 'linking', 'name': 'smart_link_edit', 'label': _(u'Edit smart links')} +linking_namespace = PermissionNamespace('linking', _(u'Smart links')) -set_namespace_title('linking', _(u'Smart links')) -register_permission(PERMISSION_SMART_LINK_VIEW) -register_permission(PERMISSION_SMART_LINK_CREATE) -register_permission(PERMISSION_SMART_LINK_DELETE) -register_permission(PERMISSION_SMART_LINK_EDIT) +PERMISSION_SMART_LINK_VIEW = Permission.objects.register(linking_namespace, 'smart_link_view', _(u'View existing smart links')) +PERMISSION_SMART_LINK_CREATE = Permission.objects.register(linking_namespace, 'smart_link_create', _(u'Create new smart links')) +PERMISSION_SMART_LINK_DELETE = Permission.objects.register(linking_namespace, 'smart_link_delete', _(u'Delete smart links')) +PERMISSION_SMART_LINK_EDIT = Permission.objects.register(linking_namespace, 'smart_link_edit', _(u'Edit smart links')) smart_link_instance_view_link = {'text': _(u'smart links actions'), 'view': 'smart_link_instance_view', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} smart_link_instances_for_document = {'text': _(u'smart links'), 'view': 'smart_link_instances_for_document', 'args': 'object.pk', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} diff --git a/apps/linking/views.py b/apps/linking/views.py index 2b1770cb12..559f4dcea7 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -11,7 +11,7 @@ from common.widgets import two_state_template from documents.models import Document from documents.views import document_list -from permissions.api import check_permissions +from permissions.models import Permission from linking.models import SmartLink, SmartLinkCondition from linking.conf.settings import SHOW_EMPTY_SMART_LINKS @@ -24,7 +24,7 @@ from linking import (PERMISSION_SMART_LINK_VIEW, def smart_link_action(request): - check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) action = request.GET.get('action', None) @@ -36,7 +36,7 @@ def smart_link_action(request): def smart_link_instance_view(request, document_id, smart_link_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) document = get_object_or_404(Document, pk=document_id) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) @@ -55,7 +55,7 @@ def smart_link_instance_view(request, document_id, smart_link_pk): def smart_link_instances_for_document(request, document_id): - check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) subtemplates_list = [] document = get_object_or_404(Document, pk=document_id) @@ -99,7 +99,7 @@ def smart_link_instances_for_document(request, document_id): def smart_link_list(request): - check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE]) return render_to_response('generic_list.html', { 'title': _(u'smart links'), @@ -115,7 +115,7 @@ def smart_link_list(request): def smart_link_create(request): - check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE]) if request.method == 'POST': form = SmartLinkForm(request.POST) @@ -133,7 +133,7 @@ def smart_link_create(request): def smart_link_edit(request, smart_link_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT]) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) @@ -155,7 +155,7 @@ def smart_link_edit(request, smart_link_pk): def smart_link_delete(request, smart_link_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_DELETE]) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) @@ -185,7 +185,7 @@ def smart_link_delete(request, smart_link_pk): def smart_link_condition_list(request, smart_link_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) @@ -203,7 +203,7 @@ def smart_link_condition_list(request, smart_link_pk): def smart_link_condition_create(request, smart_link_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) @@ -227,7 +227,7 @@ def smart_link_condition_create(request, smart_link_pk): def smart_link_condition_edit(request, smart_link_condition_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk) @@ -261,7 +261,7 @@ def smart_link_condition_edit(request, smart_link_condition_pk): def smart_link_condition_delete(request, smart_link_condition_pk): - check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk) From c000eade4f3464628468ea9a1e374d0759c2af0d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:44:54 -0400 Subject: [PATCH 037/484] Update the document comments app to use the new class based permissions --- apps/document_comments/__init__.py | 20 +++++++------------- apps/document_comments/views.py | 8 ++++---- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/document_comments/__init__.py b/apps/document_comments/__init__.py index 01619af003..895d96e1ed 100644 --- a/apps/document_comments/__init__.py +++ b/apps/document_comments/__init__.py @@ -2,9 +2,8 @@ from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.contrib.comments.models import Comment -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 permissions.models import PermissionNamespace, Permission from common.utils import encapsulate from documents.models import Document @@ -12,16 +11,12 @@ from documents.models import Document if 'django.contrib.comments' not in settings.INSTALLED_APPS: raise Exception('This app depends on the django.contrib.comments app.') -PERMISSION_COMMENT_CREATE = {'namespace': 'comments', 'name': 'comment_create', 'label': _(u'Create new comments')} -PERMISSION_COMMENT_DELETE = {'namespace': 'comments', 'name': 'comment_delete', 'label': _(u'Delete comments')} -PERMISSION_COMMENT_EDIT = {'namespace': 'comments', 'name': 'comment_edit', 'label': _(u'Edit comments')} -PERMISSION_COMMENT_VIEW = {'namespace': 'comments', 'name': 'comment_view', 'label': _(u'View comments')} +comments_namespace = PermissionNamespace('comments', _(u'Comments')) -set_namespace_title('comments', _(u'Comments')) -register_permission(PERMISSION_COMMENT_CREATE) -register_permission(PERMISSION_COMMENT_DELETE) -register_permission(PERMISSION_COMMENT_EDIT) -register_permission(PERMISSION_COMMENT_VIEW) +PERMISSION_COMMENT_CREATE = Permission.objects.register(comments_namespace, 'comment_create', _(u'Create new comments')) +PERMISSION_COMMENT_DELETE = Permission.objects.register(comments_namespace, 'comment_delete', _(u'Delete comments')) +PERMISSION_COMMENT_EDIT = Permission.objects.register(comments_namespace, 'comment_edit', _(u'Edit comments')) +PERMISSION_COMMENT_VIEW = Permission.objects.register(comments_namespace, 'comment_view', _(u'View comments')) comment_delete = {'text': _('delete'), 'view': 'comment_delete', 'args': 'object.pk', 'famfam': 'comment_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_multiple_delete = {'text': _('delete'), 'view': 'comment_multiple_delete', 'args': 'object.pk', 'famfam': 'comments_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} @@ -45,5 +40,4 @@ register_model_list_columns(Comment, [ register_links(['comments_for_object', 'comment_add', 'comment_delete', 'comment_multiple_delete'], [comment_add], menu_name='sidebar') register_links(Comment, [comment_delete]) - register_links(Document, [comments_for_object], menu_name='form_header') diff --git a/apps/document_comments/views.py b/apps/document_comments/views.py index 1e11c6e1dd..e2a57f17b8 100644 --- a/apps/document_comments/views.py +++ b/apps/document_comments/views.py @@ -7,7 +7,7 @@ from django.contrib import messages from django.contrib.contenttypes.models import ContentType from django.contrib.sites.models import Site -from permissions.api import check_permissions +from permissions.models import Permission from documents.models import Document from document_comments import PERMISSION_COMMENT_DELETE, \ @@ -16,7 +16,7 @@ from document_comments.forms import CommentForm def comment_delete(request, comment_id=None, comment_id_list=None): - check_permissions(request.user, [PERMISSION_COMMENT_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_DELETE]) post_action_redirect = None if comment_id: @@ -66,7 +66,7 @@ def comment_multiple_delete(request): def comment_add(request, document_id): - check_permissions(request.user, [PERMISSION_COMMENT_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_CREATE]) document = get_object_or_404(Document, pk=document_id) post_action_redirect = None @@ -100,7 +100,7 @@ def comments_for_object(request, document_id): """ Show a list of all the comments related to the passed object """ - check_permissions(request.user, [PERMISSION_COMMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) From 314029fe3d48c6cc151b71fb0cdbdc23aa578dca Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:46:25 -0400 Subject: [PATCH 038/484] Update the ocr app to use the new class based permissions and remove initialization hack --- apps/ocr/__init__.py | 51 +++++++++++--------------------------------- apps/ocr/views.py | 26 +++++++++++----------- 2 files changed, 25 insertions(+), 52 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index b07fa07d72..052b228821 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -1,21 +1,13 @@ -try: - from psycopg2 import OperationalError -except ImportError: - class OperationalError(Exception): - pass - 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 from django.dispatch import receiver from navigation.api import register_links, register_top_menu, register_multi_item_links -from permissions.api import register_permission, set_namespace_title +from permissions.models import Permission, PermissionNamespace from documents.models import Document from main.api import register_maintenance_links from project_tools.api import register_tool @@ -29,21 +21,13 @@ from ocr.tasks import task_process_document_queues 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')} +ocr_namespace = PermissionNamespace('ocr', _(u'OCR')) -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) +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')) #Links submit_document = {'text': _('submit to OCR queue'), 'view': 'submit_document', 'args': 'object.id', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]} @@ -82,23 +66,12 @@ register_links(['setup_queue_transformation_edit', 'setup_queue_transformation_d register_maintenance_links([all_document_ocr_cleanup], namespace='ocr', title=_(u'OCR')) -@transaction.commit_manually +@transaction.commit_on_success def create_default_queue(): - try: - default_queue, created = DocumentQueue.objects.get_or_create(name='default') - if created: - default_queue.label = ugettext(u'Default') - default_queue.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() - + default_queue, created = DocumentQueue.objects.get_or_create(name='default') + if created: + default_queue.label = ugettext(u'Default') + default_queue.save() def document_post_save(sender, instance, **kwargs): if kwargs.get('created', False): diff --git a/apps/ocr/views.py b/apps/ocr/views.py index 8fbc40d444..26c030970f 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -9,7 +9,7 @@ from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse 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 @@ -28,7 +28,7 @@ from ocr.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)] @@ -125,7 +125,7 @@ def submit_document_multiple(request): def submit_document(request, document_id): - check_permissions(request.user, [PERMISSION_OCR_DOCUMENT]) + Permission.objects.check_permissions(request.user, [PERMISSION_OCR_DOCUMENT]) document = get_object_or_404(Document, pk=document_id) return submit_document_to_queue(request, document=document, @@ -150,7 +150,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 +204,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 +231,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 +258,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))) @@ -295,7 +295,7 @@ def display_link(obj): def node_active_list(request): - check_permissions(request.user, [PERMISSION_OCR_DOCUMENT]) + Permission.objects.check_permissions(request.user, [PERMISSION_OCR_DOCUMENT]) i = inspect() active_tasks = [] @@ -331,7 +331,7 @@ def node_active_list(request): 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 +356,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 +389,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 +423,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) From 4474069f0133ca64f8749f23a53adb76492b1ba8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:47:06 -0400 Subject: [PATCH 039/484] Update the tagging app to use the new class based permissions --- apps/tags/__init__.py | 22 ++++++++-------------- apps/tags/views.py | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 4b349e012e..6e8df5bc15 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -2,7 +2,7 @@ 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 permissions.models import PermissionNamespace, Permission from common.utils import encapsulate from documents.models import Document @@ -10,20 +10,14 @@ from taggit.models import Tag 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')} +tags_namespace = PermissionNamespace('tags', _(u'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) +PERMISSION_TAG_CREATE = Permission.objects.register(tags_namespace, 'tag_create', _(u'Create new tags')) +PERMISSION_TAG_ATTACH = Permission.objects.register(tags_namespace, 'tag_attach', _(u'Attach exising tags')) +PERMISSION_TAG_REMOVE = Permission.objects.register(tags_namespace, 'tag_remove', _(u'Remove tags from documents')) +PERMISSION_TAG_DELETE = Permission.objects.register(tags_namespace, 'tag_delete', _(u'Delete global tags')) +PERMISSION_TAG_EDIT = Permission.objects.register(tags_namespace, 'tag_edit', _(u'Edit global tags')) +PERMISSION_TAG_VIEW = Permission.objects.register(tags_namespace, 'tag_view', _(u'View a document\'s tags')) 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'} diff --git a/apps/tags/views.py b/apps/tags/views.py index 45d91c1921..94fd2ff170 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -5,7 +5,7 @@ from django.contrib import messages from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ -from permissions.api import check_permissions +from permissions.models import Permission from taggit.models import Tag from documents.models import Document from documents.views import document_list @@ -20,7 +20,7 @@ from tags import tag_tagged_item_list as tag_tagged_item_list_link def tag_create(request): - #check_permissions(request.user, [PERMISSION_TAG_EDIT]) + #Permission.objects.check_permissions(request.user, [PERMISSION_TAG_EDIT]) redirect_url = reverse('tag_list') previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_url))) @@ -59,14 +59,14 @@ def tag_add_sidebar(request, document_id): form = AddTagForm(request.POST) if form.is_valid(): if form.cleaned_data['new_tag']: - check_permissions(request.user, [PERMISSION_TAG_CREATE]) + Permission.objects.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]) + Permission.objects.check_permissions(request.user, [PERMISSION_TAG_ATTACH]) tag_name = form.cleaned_data['existing_tags'] is_new = False else: @@ -98,14 +98,14 @@ def tag_add_attach(request, document_id): form = AddTagForm(request.POST) if form.is_valid(): if form.cleaned_data['new_tag']: - check_permissions(request.user, [PERMISSION_TAG_CREATE]) + Permission.objects.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]) + Permission.objects.check_permissions(request.user, [PERMISSION_TAG_ATTACH]) tag_name = form.cleaned_data['existing_tags'] is_new = False else: @@ -154,7 +154,7 @@ def tag_list(request): def tag_delete(request, tag_id=None, tag_id_list=None): - check_permissions(request.user, [PERMISSION_TAG_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_TAG_DELETE]) post_action_redirect = None if tag_id: @@ -207,7 +207,7 @@ def tag_multiple_delete(request): def tag_edit(request, tag_id): - check_permissions(request.user, [PERMISSION_TAG_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_TAG_EDIT]) tag = get_object_or_404(Tag, pk=tag_id) if request.method == 'POST': @@ -251,7 +251,7 @@ def tag_tagged_item_list(request, tag_id): def document_tags(request, document_id): - check_permissions(request.user, [PERMISSION_TAG_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_TAG_VIEW]) document = get_object_or_404(Document, pk=document_id) return render_to_response('generic_list.html', { @@ -268,7 +268,7 @@ def document_tags(request, document_id): def tag_remove(request, document_id, tag_id=None, tag_id_list=None): - check_permissions(request.user, [PERMISSION_TAG_REMOVE]) + Permission.objects.check_permissions(request.user, [PERMISSION_TAG_REMOVE]) post_action_redirect = None From 24c6f60caf1b608f940d7472d1a59fe509fc970b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:47:35 -0400 Subject: [PATCH 040/484] Update the user management app to use the new class based permissions --- apps/user_management/__init__.py | 29 +++++++++++------------------ apps/user_management/views.py | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/apps/user_management/__init__.py b/apps/user_management/__init__.py index 6b2bc6aa82..e5dbf82d51 100644 --- a/apps/user_management/__init__.py +++ b/apps/user_management/__init__.py @@ -2,28 +2,21 @@ from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group from navigation.api import register_links, register_multi_item_links -from permissions.api import register_permission, set_namespace_title +from permissions.models import PermissionNamespace, Permission + from project_setup.api import register_setup -PERMISSION_USER_CREATE = {'namespace': 'user_management', 'name': 'user_create', 'label': _(u'Create new users')} -PERMISSION_USER_EDIT = {'namespace': 'user_management', 'name': 'user_edit', 'label': _(u'Edit existing users')} -PERMISSION_USER_VIEW = {'namespace': 'user_management', 'name': 'user_view', 'label': _(u'View existing users')} -PERMISSION_USER_DELETE = {'namespace': 'user_management', 'name': 'user_delete', 'label': _(u'Delete existing users')} +user_management_namespace = PermissionNamespace('user_management', _(u'User management')) -PERMISSION_GROUP_CREATE = {'namespace': 'user_management', 'name': 'group_create', 'label': _(u'Create new groups')} -PERMISSION_GROUP_EDIT = {'namespace': 'user_management', 'name': 'group_edit', 'label': _(u'Edit existing groups')} -PERMISSION_GROUP_VIEW = {'namespace': 'user_management', 'name': 'group_view', 'label': _(u'View existing groups')} -PERMISSION_GROUP_DELETE = {'namespace': 'user_management', 'name': 'group_delete', 'label': _(u'Delete existing groups')} +PERMISSION_USER_CREATE = Permission.objects.register(user_management_namespace, 'user_create', _(u'Create new users')) +PERMISSION_USER_EDIT = Permission.objects.register(user_management_namespace, 'user_edit', _(u'Edit existing users')) +PERMISSION_USER_VIEW = Permission.objects.register(user_management_namespace, 'user_view', _(u'View existing users')) +PERMISSION_USER_DELETE = Permission.objects.register(user_management_namespace, 'user_delete', _(u'Delete existing users')) -set_namespace_title('user_management', _(u'User management')) -register_permission(PERMISSION_USER_CREATE) -register_permission(PERMISSION_USER_EDIT) -register_permission(PERMISSION_USER_VIEW) -register_permission(PERMISSION_USER_DELETE) -register_permission(PERMISSION_GROUP_CREATE) -register_permission(PERMISSION_GROUP_EDIT) -register_permission(PERMISSION_GROUP_VIEW) -register_permission(PERMISSION_GROUP_DELETE) +PERMISSION_GROUP_CREATE = Permission.objects.register(user_management_namespace, 'group_create', _(u'Create new groups')) +PERMISSION_GROUP_EDIT = Permission.objects.register(user_management_namespace, 'group_edit', _(u'Edit existing groups')) +PERMISSION_GROUP_VIEW = Permission.objects.register(user_management_namespace, 'group_view', _(u'View existing groups')) +PERMISSION_GROUP_DELETE = Permission.objects.register(user_management_namespace, 'group_delete', _(u'Delete existing groups')) user_list = {'text': _(u'user list'), 'view': 'user_list', 'famfam': 'user', 'permissions': [PERMISSION_USER_VIEW]} user_setup = {'text': _(u'users'), 'view': 'user_list', 'famfam': 'user', 'icon': 'user.png', 'permissions': [PERMISSION_USER_VIEW]} diff --git a/apps/user_management/views.py b/apps/user_management/views.py index 7fc5eee7ae..e5167dfef5 100644 --- a/apps/user_management/views.py +++ b/apps/user_management/views.py @@ -7,7 +7,7 @@ from django.views.generic.list_detail import object_list from django.core.urlresolvers import reverse from django.contrib.auth.models import User, Group -from permissions.api import check_permissions +from permissions.models import Permission from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template from common.views import assign_remove @@ -21,7 +21,7 @@ from user_management.forms import UserForm, PasswordForm, GroupForm def user_list(request): - check_permissions(request.user, [PERMISSION_USER_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_USER_VIEW]) return object_list( request, @@ -51,7 +51,7 @@ def user_list(request): def user_edit(request, user_id): - check_permissions(request.user, [PERMISSION_USER_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_USER_EDIT]) user = get_object_or_404(User, pk=user_id) if user.is_superuser or user.is_staff: @@ -77,7 +77,7 @@ def user_edit(request, user_id): def user_add(request): - check_permissions(request.user, [PERMISSION_USER_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_USER_CREATE]) if request.method == 'POST': form = UserForm(request.POST) @@ -96,7 +96,7 @@ def user_add(request): def user_delete(request, user_id=None, user_id_list=None): - check_permissions(request.user, [PERMISSION_USER_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_USER_DELETE]) post_action_redirect = None if user_id: @@ -150,7 +150,7 @@ def user_multiple_delete(request): def user_set_password(request, user_id=None, user_id_list=None): - check_permissions(request.user, [PERMISSION_USER_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_USER_EDIT]) post_action_redirect = None if user_id: @@ -212,7 +212,7 @@ def user_multiple_set_password(request): def group_list(request): - check_permissions(request.user, [PERMISSION_GROUP_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_GROUP_VIEW]) return object_list( request, @@ -233,7 +233,7 @@ def group_list(request): def group_edit(request, group_id): - check_permissions(request.user, [PERMISSION_GROUP_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_GROUP_EDIT]) group = get_object_or_404(Group, pk=group_id) if request.method == 'POST': @@ -255,7 +255,7 @@ def group_edit(request, group_id): def group_add(request): - check_permissions(request.user, [PERMISSION_GROUP_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_GROUP_CREATE]) if request.method == 'POST': form = GroupForm(request.POST) @@ -274,7 +274,7 @@ def group_add(request): def group_delete(request, group_id=None, group_id_list=None): - check_permissions(request.user, [PERMISSION_GROUP_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_GROUP_DELETE]) post_action_redirect = None if group_id: @@ -333,7 +333,7 @@ def get_non_group_members(group): def group_members(request, group_id): - check_permissions(request.user, [PERMISSION_GROUP_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_GROUP_EDIT]) group = get_object_or_404(Group, pk=group_id) return assign_remove( From c5518c222aac779a1d5503ecfd5fa7d10b95d3a1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:49:11 -0400 Subject: [PATCH 041/484] Update the documents app to use the new class based permissions --- apps/documents/__init__.py | 25 ++---------- apps/documents/literals.py | 32 +++++++++------ apps/documents/views.py | 80 +++++++++++++++++++------------------- 3 files changed, 63 insertions(+), 74 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 26c3e9852d..b0754b8846 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -7,7 +7,6 @@ from navigation.api import register_links, register_top_menu, \ register_model_list_columns, register_multi_item_links, \ register_sidebar_template from main.api import register_diagnostic, register_maintenance_links -from permissions.api import register_permission, set_namespace_title from tags.widgets import get_tags_inline_widget_simple from history.api import register_history_type from metadata.api import get_metadata_string @@ -20,9 +19,9 @@ from documents.literals import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS, - PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT) -from documents.literals import (PERMISSION_DOCUMENT_TYPE_EDIT, - PERMISSION_DOCUMENT_TYPE_DELETE, PERMISSION_DOCUMENT_TYPE_CREATE) + PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT, + PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE, + PERMISSION_DOCUMENT_TYPE_CREATE) from documents.literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) from documents.conf.settings import ZOOM_MAX_LEVEL @@ -50,24 +49,6 @@ def is_max_zoom(context): def is_current_version(context): return context['object'].document.latest_version.timestamp == context['object'].timestamp -# Permission setup -set_namespace_title('documents', _(u'Documents')) -register_permission(PERMISSION_DOCUMENT_CREATE) -register_permission(PERMISSION_DOCUMENT_PROPERTIES_EDIT) -register_permission(PERMISSION_DOCUMENT_EDIT) -register_permission(PERMISSION_DOCUMENT_VIEW) -register_permission(PERMISSION_DOCUMENT_DELETE) -register_permission(PERMISSION_DOCUMENT_DOWNLOAD) -register_permission(PERMISSION_DOCUMENT_TRANSFORM) -register_permission(PERMISSION_DOCUMENT_TOOLS) -register_permission(PERMISSION_DOCUMENT_VERSION_REVERT) - -# Document type permissions -set_namespace_title('documents_setup', _(u'Documents setup')) -register_permission(PERMISSION_DOCUMENT_TYPE_EDIT) -register_permission(PERMISSION_DOCUMENT_TYPE_DELETE) -register_permission(PERMISSION_DOCUMENT_TYPE_CREATE) - # History setup register_history_type(HISTORY_DOCUMENT_CREATED) register_history_type(HISTORY_DOCUMENT_EDITED) diff --git a/apps/documents/literals.py b/apps/documents/literals.py index 54df1d03d2..ad9c9c7a88 100644 --- a/apps/documents/literals.py +++ b/apps/documents/literals.py @@ -1,23 +1,31 @@ from django.utils.translation import ugettext_lazy as _ +from permissions.models import PermissionNamespace, Permission + + PICTURE_ERROR_SMALL = u'picture_error.png' PICTURE_ERROR_MEDIUM = u'1297211435_error.png' PICTURE_UNKNOWN_SMALL = u'1299549572_unknown2.png' PICTURE_UNKNOWN_MEDIUM = u'1299549805_unknown.png' -PERMISSION_DOCUMENT_CREATE = {'namespace': 'documents', 'name': 'document_create', 'label': _(u'Create documents')} -PERMISSION_DOCUMENT_PROPERTIES_EDIT = {'namespace': 'documents', 'name': 'document_properties_edit', 'label': _(u'Edit document properties')} -PERMISSION_DOCUMENT_EDIT = {'namespace': 'documents', 'name': 'document_edit', 'label': _(u'Edit documents')} -PERMISSION_DOCUMENT_VIEW = {'namespace': 'documents', 'name': 'document_view', 'label': _(u'View documents')} -PERMISSION_DOCUMENT_DELETE = {'namespace': 'documents', 'name': 'document_delete', 'label': _(u'Delete documents')} -PERMISSION_DOCUMENT_DOWNLOAD = {'namespace': 'documents', 'name': 'document_download', 'label': _(u'Download documents')} -PERMISSION_DOCUMENT_TRANSFORM = {'namespace': 'documents', 'name': 'document_transform', 'label': _(u'Transform documents')} -PERMISSION_DOCUMENT_TOOLS = {'namespace': 'documents', 'name': 'document_tools', 'label': _(u'Execute document modifying tools')} -PERMISSION_DOCUMENT_VERSION_REVERT = {'namespace': 'documents', 'name': 'document_version_revert', 'label': _(u'Revert documents to a previous version')} +document_namespace = PermissionNamespace('documents', _(u'Documents')) + +PERMISSION_DOCUMENT_CREATE = Permission.objects.register(document_namespace, 'document_create', _(u'Create documents')) +PERMISSION_DOCUMENT_PROPERTIES_EDIT = Permission.objects.register(document_namespace, 'document_properties_edit', _(u'Edit document properties')) +PERMISSION_DOCUMENT_EDIT = Permission.objects.register(document_namespace, 'document_edit', _(u'Edit documents')) +PERMISSION_DOCUMENT_VIEW = Permission.objects.register(document_namespace, 'document_view', _(u'View documents')) +PERMISSION_DOCUMENT_DELETE = Permission.objects.register(document_namespace, 'document_delete', _(u'Delete documents')) +PERMISSION_DOCUMENT_DOWNLOAD = Permission.objects.register(document_namespace, 'document_download', _(u'Download documents')) +PERMISSION_DOCUMENT_TRANSFORM = Permission.objects.register(document_namespace, 'document_transform', _(u'Transform documents')) +PERMISSION_DOCUMENT_TOOLS = Permission.objects.register(document_namespace, 'document_tools', _(u'Execute document modifying tools')) +PERMISSION_DOCUMENT_VERSION_REVERT = Permission.objects.register(document_namespace, 'document_version_revert', _(u'Revert documents to a previous version')) + +documents_setup_namespace = PermissionNamespace('documents_setup', _(u'Documents setup')) + +PERMISSION_DOCUMENT_TYPE_EDIT = Permission.objects.register(documents_setup_namespace, 'document_type_edit', _(u'Edit document types')) +PERMISSION_DOCUMENT_TYPE_DELETE = Permission.objects.register(documents_setup_namespace, 'document_type_delete', _(u'Delete document types')) +PERMISSION_DOCUMENT_TYPE_CREATE = Permission.objects.register(documents_setup_namespace, 'document_type_create', _(u'Create document types')) -PERMISSION_DOCUMENT_TYPE_EDIT = {'namespace': 'documents_setup', 'name': 'document_type_edit', 'label': _(u'Edit document types')} -PERMISSION_DOCUMENT_TYPE_DELETE = {'namespace': 'documents_setup', 'name': 'document_type_delete', 'label': _(u'Delete document types')} -PERMISSION_DOCUMENT_TYPE_CREATE = {'namespace': 'documents_setup', 'name': 'document_type_create', 'label': _(u'Create document types')} HISTORY_DOCUMENT_CREATED = { 'namespace': 'documents', 'name': 'document_created', diff --git a/apps/documents/views.py b/apps/documents/views.py index d7ab3701f3..9a34963aaf 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -23,7 +23,7 @@ from converter.office_converter import OfficeConverter from filetransfers.api import serve_file from metadata.forms import MetadataFormSet, MetadataSelectionForm from navigation.utils import resolve_to_name -from permissions.api import check_permissions +from permissions.models import Permission from document_indexing.api import update_indexes, delete_indexes from history.api import create_history @@ -64,7 +64,7 @@ from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT, \ def document_list(request, object_list=None, title=None, extra_context=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) context = { 'object_list': object_list if not (object_list is None) else Document.objects.all(), @@ -80,7 +80,7 @@ def document_list(request, object_list=None, title=None, extra_context=None): def document_create(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) wizard = DocumentCreateWizard(form_list=[DocumentTypeSelectForm, MetadataSelectionForm, MetadataFormSet]) @@ -88,7 +88,7 @@ def document_create(request): def document_create_siblings(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) document = get_object_or_404(Document, pk=document_id) query_dict = {} @@ -104,7 +104,7 @@ def document_create_siblings(request, document_id): def document_view(request, document_id, advanced=False): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) #document = get_object_or_404(Document.objects.select_related(), pk=document_id) # Triggers a 404 error on documents uploaded via local upload # TODO: investigate @@ -173,7 +173,7 @@ def document_view(request, document_id, advanced=False): def document_delete(request, document_id=None, document_id_list=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DELETE]) post_action_redirect = None if document_id: @@ -230,7 +230,7 @@ def document_multiple_delete(request): def document_edit(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_PROPERTIES_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_PROPERTIES_EDIT]) document = get_object_or_404(Document, pk=document_id) @@ -273,7 +273,7 @@ def document_edit(request, document_id): def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=False): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) @@ -299,7 +299,7 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F def document_download(request, document_id=None, document_version_pk=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) if document_version_pk: document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) @@ -322,7 +322,7 @@ def document_download(request, document_id=None, document_version_pk=None): def document_page_transformation_list(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -348,7 +348,7 @@ def document_page_transformation_list(request, document_page_id): def document_page_transformation_create(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -373,7 +373,7 @@ def document_page_transformation_create(request, document_page_id): def document_page_transformation_edit(request, document_page_transformation_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) document_page_transformation = get_object_or_404(DocumentPageTransformation, pk=document_page_transformation_id) @@ -403,7 +403,7 @@ def document_page_transformation_edit(request, document_page_transformation_id): def document_page_transformation_delete(request, document_page_transformation_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) document_page_transformation = get_object_or_404(DocumentPageTransformation, pk=document_page_transformation_id) @@ -434,7 +434,7 @@ def document_page_transformation_delete(request, document_page_transformation_id def document_find_duplicates(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) extra_context = { @@ -478,13 +478,13 @@ def _find_duplicate_list(request, source_document_list=Document.objects.all(), i def document_find_all_duplicates(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) return _find_duplicate_list(request, include_source=True) def document_update_page_count(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) office_converter = OfficeConverter() @@ -515,7 +515,7 @@ def document_update_page_count(request): def document_clear_transformations(request, document_id=None, document_id_list=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) if document_id: documents = [get_object_or_404(Document.objects, pk=document_id)] @@ -567,7 +567,7 @@ def document_multiple_clear_transformations(request): def document_missing_list(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None))) @@ -589,7 +589,7 @@ def document_missing_list(request): def document_page_view(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -625,7 +625,7 @@ def document_page_view_reset(request, document_page_id): def document_page_text(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document_page = get_object_or_404(DocumentPage, pk=document_page_id) document_page_form = DocumentPageForm_text(instance=document_page) @@ -640,7 +640,7 @@ def document_page_text(request, document_page_id): def document_page_edit(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_EDIT]) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -665,7 +665,7 @@ def document_page_edit(request, document_page_id): def document_page_navigation_next(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -678,7 +678,7 @@ def document_page_navigation_next(request, document_page_id): def document_page_navigation_previous(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -691,7 +691,7 @@ def document_page_navigation_previous(request, document_page_id): def document_page_navigation_first(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -700,7 +700,7 @@ def document_page_navigation_first(request, document_page_id): def document_page_navigation_last(request, document_page_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -720,7 +720,7 @@ def document_list_recent(request): def transform_page(request, document_page_id, zoom_function=None, rotation_function=None): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) @@ -778,7 +778,7 @@ def document_page_rotate_left(request, document_page_id): def document_print(request, document_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) @@ -835,7 +835,7 @@ def document_print(request, document_id): def document_hard_copy(request, document_id): #TODO: FIXME - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) @@ -876,7 +876,7 @@ def document_hard_copy(request, document_id): def document_type_list(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) context = { 'object_list': DocumentType.objects.all(), @@ -890,7 +890,7 @@ def document_type_list(request): def document_type_document_list(request, document_type_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document_type = get_object_or_404(DocumentType, pk=document_type_id) @@ -907,7 +907,7 @@ def document_type_document_list(request, document_type_id): def document_type_edit(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) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('document_type_list')))) @@ -938,7 +938,7 @@ def document_type_edit(request, document_type_id): def document_type_delete(request, document_type_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_DELETE]) document_type = get_object_or_404(DocumentType, pk=document_type_id) post_action_redirect = reverse('document_type_list') @@ -977,7 +977,7 @@ def document_type_delete(request, document_type_id): def document_type_create(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_CREATE]) if request.method == 'POST': form = DocumentTypeForm(request.POST) @@ -1000,7 +1000,7 @@ def document_type_create(request): def document_type_filename_list(request, document_type_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document_type = get_object_or_404(DocumentType, pk=document_type_id) context = { @@ -1024,7 +1024,7 @@ def document_type_filename_list(request, document_type_id): def document_type_filename_edit(request, document_type_filename_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT]) document_type_filename = get_object_or_404(DocumentTypeFilename, pk=document_type_filename_id) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('document_type_filename_list', args=[document_type_filename.document_type_id])))) @@ -1060,7 +1060,7 @@ def document_type_filename_edit(request, document_type_filename_id): def document_type_filename_delete(request, document_type_filename_id): - check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_EDIT]) document_type_filename = get_object_or_404(DocumentTypeFilename, pk=document_type_filename_id) post_action_redirect = reverse('document_type_filename_list', args=[document_type_filename.document_type_id]) @@ -1100,7 +1100,7 @@ def document_type_filename_delete(request, document_type_filename_id): def document_type_filename_create(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) @@ -1131,7 +1131,7 @@ def document_type_filename_create(request, document_type_id): def document_clear_image_cache(request): - check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) @@ -1152,7 +1152,7 @@ def document_clear_image_cache(request): def document_version_list(request, document_pk): - check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) @@ -1195,7 +1195,7 @@ def document_version_list(request, document_pk): def document_version_revert(request, document_version_pk): - check_permissions(request.user, [PERMISSION_DOCUMENT_VERSION_REVERT]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERSION_REVERT]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) From c9b6d8411c8f376b0cbb482f7ae3df1b4e8e91f4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:50:33 -0400 Subject: [PATCH 042/484] Update the main app to use the new class based permissions --- apps/main/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/main/views.py b/apps/main/views.py index f4ff678e46..e4205b5f38 100644 --- a/apps/main/views.py +++ b/apps/main/views.py @@ -7,7 +7,7 @@ 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 @@ -31,7 +31,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 From c9bf9a4d6edfec6f8930ad766304f9f3069976d8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:50:56 -0400 Subject: [PATCH 043/484] Update the navigation widget to use the new class based permissions --- apps/navigation/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index 949fae4dd3..57934c7909 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -5,13 +5,13 @@ from django.core.urlresolvers import reverse from django.template.defaultfilters import capfirst from django.core.exceptions import PermissionDenied -from permissions.api import check_permissions +from permissions.models import Permission def button_navigation_widget(request, link): if 'permissions' in link: try: - check_permissions(request.user, link['permissions']) + Permission.objects.check_permissions(request.user, link['permissions']) return render_widget(link) except PermissionDenied: return u'' From f4a7a350b8c2eea06e3258e1f298b29835690cb3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:51:24 -0400 Subject: [PATCH 044/484] Update the permissions tag to the new class based permissions --- apps/permissions/templatetags/permission_tags.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/permissions/templatetags/permission_tags.py b/apps/permissions/templatetags/permission_tags.py index fecffa2796..18e161bdd7 100644 --- a/apps/permissions/templatetags/permission_tags.py +++ b/apps/permissions/templatetags/permission_tags.py @@ -2,7 +2,7 @@ from django.core.exceptions import PermissionDenied 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 +21,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: From 974802035b8f9135a653819e76703f4a5d0f98bb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 8 Dec 2011 16:52:39 -0400 Subject: [PATCH 045/484] Update the django gpg app to the new class based permissions --- apps/django_gpg/__init__.py | 29 +++++++++-------------------- apps/django_gpg/views.py | 16 ++++++++-------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index e45ae78165..3d703f21d6 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -5,29 +5,21 @@ from navigation.api import register_links, register_top_menu, \ register_model_list_columns, register_multi_item_links, \ register_sidebar_template from main.api import register_diagnostic, register_maintenance_links -from permissions.api import register_permission, set_namespace_title +from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup from hkp import Key as KeyServerKey from django_gpg.api import Key -PERMISSION_DOCUMENT_VERIFY = {'namespace': 'django_gpg', 'name': 'document_verify', 'label': _(u'Verify document signatures')} -PERMISSION_KEY_VIEW = {'namespace': 'django_gpg', 'name': 'key_view', 'label': _(u'View keys')} -PERMISSION_KEY_DELETE = {'namespace': 'django_gpg', 'name': 'key_delete', 'label': _(u'Delete keys')} -PERMISSION_KEYSERVER_QUERY = {'namespace': 'django_gpg', 'name': 'keyserver_query', 'label': _(u'Query keyservers')} -PERMISSION_KEY_RECEIVE = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Import key from keyservers')} -PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'django_gpg', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} -PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Download detached signatures')} +django_gpg_namespace = PermissionNamespace('django_gpg', _(u'Signatures')) -# Permission setup -set_namespace_title('django_gpg', _(u'Signatures')) -register_permission(PERMISSION_DOCUMENT_VERIFY) -register_permission(PERMISSION_KEY_VIEW) -register_permission(PERMISSION_KEY_DELETE) -register_permission(PERMISSION_KEYSERVER_QUERY) -register_permission(PERMISSION_KEY_RECEIVE) -register_permission(PERMISSION_SIGNATURE_UPLOAD) -register_permission(PERMISSION_SIGNATURE_DOWNLOAD) +PERMISSION_DOCUMENT_VERIFY = Permission.objects.register(django_gpg_namespace, 'document_verify', _(u'Verify document signatures')) +PERMISSION_KEY_VIEW = Permission.objects.register(django_gpg_namespace, 'key_view', _(u'View keys')) +PERMISSION_KEY_DELETE = Permission.objects.register(django_gpg_namespace, 'key_delete', _(u'Delete keys')) +PERMISSION_KEYSERVER_QUERY = Permission.objects.register(django_gpg_namespace, 'keyserver_query', _(u'Query keyservers')) +PERMISSION_KEY_RECEIVE = Permission.objects.register(django_gpg_namespace, 'key_receive', _(u'Import keys from keyservers')) +PERMISSION_SIGNATURE_UPLOAD = Permission.objects.register(django_gpg_namespace, 'signature_upload', _(u'Upload detached signatures')) +PERMISSION_SIGNATURE_DOWNLOAD = Permission.objects.register(django_gpg_namespace, 'signature_download', _(u'Download detached signatures')) def has_embedded_signature(context): return context['object'].signature_state @@ -59,6 +51,3 @@ register_links(Key, [key_delete]) register_links(KeyServerKey, [key_receive]) register_setup(key_setup) - - - diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index 6fe629dbe8..6a1a334a25 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -12,7 +12,7 @@ from django.conf import settings from django.template.defaultfilters import force_escape from documents.models import Document, RecentDocument -from permissions.api import check_permissions +from permissions.models import Permission from common.utils import pretty_size, parse_range, urlquote, \ return_diff, encapsulate from filetransfers.api import serve_file @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) def key_receive(request, key_id): - check_permissions(request.user, [PERMISSION_KEY_RECEIVE]) + Permission.objects.check_permissions(request.user, [PERMISSION_KEY_RECEIVE]) post_action_redirect = None previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) @@ -61,7 +61,7 @@ def key_receive(request, key_id): def key_list(request, secret=True): - check_permissions(request.user, [PERMISSION_KEY_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_KEY_VIEW]) if secret: object_list = Key.get_all(gpg, secret=True) @@ -88,7 +88,7 @@ def key_list(request, secret=True): def key_delete(request, fingerprint, key_type): - check_permissions(request.user, [PERMISSION_KEY_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_KEY_DELETE]) secret = key_type == 'sec' key = Key.get(gpg, fingerprint, secret=secret) @@ -117,7 +117,7 @@ def key_delete(request, fingerprint, key_type): def key_query(request): - check_permissions(request.user, [PERMISSION_KEYSERVER_QUERY]) + Permission.objects.check_permissions(request.user, [PERMISSION_KEYSERVER_QUERY]) subtemplates_list = [] term = request.GET.get('term') @@ -192,7 +192,7 @@ def key_query(request): def document_verify(request, document_pk): - check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) @@ -234,7 +234,7 @@ def document_verify(request, document_pk): def document_signature_upload(request, document_pk): - check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) + Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) @@ -267,7 +267,7 @@ def document_signature_upload(request, document_pk): def document_signature_download(request, document_pk): - check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) + Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) document = get_object_or_404(Document, pk=document_pk) try: From 357d1b7430d9c524e18edd065d4daea5c322f1c1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 10:57:39 -0400 Subject: [PATCH 046/484] Improve the linking between the volatile permission and the stored permission classes --- apps/permissions/models.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 1cbbc51a2a..fdcd26b45c 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -20,14 +20,6 @@ class PermissionNamespace(object): def __unicode__(self): return unicode(self.label) -#class LazyQuerySet(list): -# def __init__(self, model, items): -# self.model = model -# self.items = items -# -# def get(self, *args, **kwargs): -# print args -# print kwargs class PermissionDoesNotExists(Exception): pass @@ -58,13 +50,15 @@ class PermissionManager(object): @classmethod def all(cls): return cls._permissions.values() - #return LazyQuerySet(cls, cls._permissions) @classmethod - def get(cls, get_dict): + def get(cls, get_dict, proxy_only=False): if 'pk' in get_dict: try: - return cls._permissions[get_dict['pk']].get_stored_permission() + if proxy_only: + return cls._permissions[get_dict['pk']] + else: + return cls._permissions[get_dict['pk']].get_stored_permission() except KeyError: raise Permission.DoesNotExist @@ -118,18 +112,22 @@ 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')) + #label = models.CharField(max_length=96, verbose_name=_(u'label')) 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 unicode(self.volatile_permission) + return unicode(getattr(self, 'volatile_permission', self.name)) def get_holders(self): return [holder.holder_object for holder in self.permissionholder_set.all()] From ab79b3f729fe801355a222d690a28af19b38c8c5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 10:58:13 -0400 Subject: [PATCH 047/484] Removed the label field from the admin interface view --- apps/permissions/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/permissions/admin.py b/apps/permissions/admin.py index b370b77498..b20d75331c 100644 --- a/apps/permissions/admin.py +++ b/apps/permissions/admin.py @@ -12,7 +12,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 From c1fadd08403d1473598fa5f81725735de0fc8a12 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 10:58:49 -0400 Subject: [PATCH 048/484] Converted the acls app to the new class based permission system --- apps/acls/__init__.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 6406ea087a..283a75c662 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -1,17 +1,14 @@ from django.utils.translation import ugettext_lazy as _ -from permissions.api import register_permission, set_namespace_title from navigation.api import register_links, register_multi_item_links +from permissions.models import PermissionNamespace, Permission from acls.models import AccessHolder +acls_namespace = PermissionNamespace('acls', _(u'Access control lists')) -ACLS_EDIT_ACL = {'namespace': 'acls', 'name': 'acl_edit', 'label': _(u'Edit ACLs')} -ACLS_VIEW_ACL = {'namespace': 'acls', 'name': 'acl_view', 'label': _(u'View ACLs')} - -set_namespace_title('acls', _(u'Access control lists')) -register_permission(ACLS_EDIT_ACL) -register_permission(ACLS_VIEW_ACL) +ACLS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit ACLs')) +ACLS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View ACLs')) acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} From 2f803174b14d48f56ba74aafdb76b1780f0f684b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:34:39 -0400 Subject: [PATCH 049/484] Update acls models to the new class based permissions --- apps/acls/models.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index 8d1c343b0a..d1186c9218 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -12,19 +12,21 @@ from django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import get_object_or_404 -from permissions.models import Permission +from permissions.models import StoredPermission _cache = {} +_class_permissions = {} + +def class_permissions(cls, permission_list): + stored_permissions = _class_permissions.setdefault(cls, []) + stored_permissions.extend(permission_list) + + class EncapsulatedObject(object): source_object_name = u'source_object' - #@classmethod - #def __new__(cls, *args, **kwargs): - # cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) - # return super(EncapsulatedObject, cls).__new__(*args, **kwargs) - @classmethod def add_to_class(cls, name, value): if hasattr(value, 'contribute_to_class'): @@ -73,8 +75,8 @@ class EncapsulatedObject(object): return cls.encapsulate(app_label=app_label, model=model, pk=pk) def __init__(self, source_object): - content_type = ContentType.objects.get_for_model(source_object) - self.gid = '%s.%s.%s' % (content_type.app_label, content_type.name, source_object.pk) + self.content_type = ContentType.objects.get_for_model(source_object) + self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.name, source_object.pk) setattr(self, self.__class__.source_object_name, source_object) def __unicode__(self): @@ -87,6 +89,9 @@ class EncapsulatedObject(object): def source_object(self): return getattr(self, self.__class__.source_object_name, None) + def get_class_permissions(self): + return _class_permissions.get(self.content_type.model_class(), []) + class AccessHolder(EncapsulatedObject): source_object_name = u'holder_object' @@ -131,7 +136,7 @@ class AccessEntryManager(models.Manager): try: access_entry = self.model.objects.get( - permission=permission, + permission=permission.get_stored_permission(), holder_type=ContentType.objects.get_for_model(requester), holder_id=requester.pk, content_type=ContentType.objects.get_for_model(obj), @@ -142,7 +147,7 @@ class AccessEntryManager(models.Manager): return False def check_access(self, permission, requester, obj): - if has_accesses(permission, requester, obj): + if self.has_accesses(permission, requester, obj): return True else: raise PermissionDenied(ugettext(u'Insufficient permissions.')) @@ -150,6 +155,10 @@ class AccessEntryManager(models.Manager): def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) + + def get_new_holder_url(self, obj): + content_type = ContentType.objects.get_for_model(obj) + return reverse('acl_new_holder_for', args=[content_type.app_label, content_type.model, obj.pk]) def get_holders_for(self, obj): content_type = ContentType.objects.get_for_model(obj) @@ -162,10 +171,10 @@ class AccessEntryManager(models.Manager): return holder_list - def get_permissions_for_holder(self, obj, holder): + def get_holder_permissions_for(self, obj, holder): if isinstance(holder, User): if holder.is_superuser or holder.is_staff: - return Permission.objects.active_only() + return Permission.objects.all() holder_type = ContentType.objects.get_for_model(holder) content_type = ContentType.objects.get_for_model(obj) @@ -173,7 +182,7 @@ class AccessEntryManager(models.Manager): class AccessEntry(models.Model): - permission = models.ForeignKey(Permission, verbose_name=_(u'permission')) + permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) holder_type = models.ForeignKey( ContentType, From 418312bc8abfc8ddfcc40a6e0eb1de9bf1d750e9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:35:14 -0400 Subject: [PATCH 050/484] Add new acl holder selector form --- apps/acls/forms.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 apps/acls/forms.py diff --git a/apps/acls/forms.py b/apps/acls/forms.py new file mode 100644 index 0000000000..49a995c4e0 --- /dev/null +++ b/apps/acls/forms.py @@ -0,0 +1,30 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import User, Group + +from permissions.models import Permission, Role +from common.utils import generate_choices_w_labels, encapsulate, get_object_name + +from acls.models import AccessHolder + + +class HolderSelectionForm(forms.Form): + holder_gid = forms.ChoiceField( + label=_(u'Holder') + ) + + def __init__(self, *args, **kwargs): + 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) + users = set(User.objects.filter(is_active=True)) - set(staff_users) - set(super_users) + roles = set(Role.objects.all()) + #groups = set(Group.objects.exclude(pk__in=[member.pk for member in get_role_members(role)])) + groups = set(Group.objects.all()) + holder_list = list(users | groups | roles) + + #holder_list = kwargs.pop('holder_list', None) + super(HolderSelectionForm, self).__init__(*args, **kwargs) + #if holder_list: + self.fields['holder_gid'].choices = [(AccessHolder.encapsulate(holder).gid, get_object_name(holder)) for holder in holder_list] + From 796a8fbdb5ac52d14d895e4986a824658f4a3562 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:45:49 -0400 Subject: [PATCH 051/484] Add acl revokation view --- apps/acls/__init__.py | 3 +- apps/acls/urls.py | 12 +- apps/acls/views.py | 280 +++++++++++++++++++++++++++++++----------- 3 files changed, 216 insertions(+), 79 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 283a75c662..6753b2779b 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -13,6 +13,7 @@ ACLS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} +acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} register_links(AccessHolder, [acl_detail]) -register_multi_item_links(['acl_detail'], [acl_grant])#, permission_revoke]) +register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) diff --git a/apps/acls/urls.py b/apps/acls/urls.py index 1570140c5e..2f70970766 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -1,17 +1,11 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('acls.views', + url(r'^new_holder_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_new_holder_for', (), 'acl_new_holder_for'), url(r'^list_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_list', (), 'acl_list'), #url(r'^object/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/holder/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_detail', (), 'acl_detail'), url(r'^details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acl_detail', (), 'acl_detail'), - -# url(r'^role/list/$', 'role_list', (), 'role_list'), -# url(r'^role/create/$', 'role_create', (), 'role_create'), -# url(r'^role/(?P\d+)/permissions/$', 'role_permissions', (), 'role_permissions'), -# 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'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), -# url(r'^permissions/multiple/revoke/$', 'permission_revoke', (), 'permission_multiple_revoke'), + url(r'^multiple/revoke/$', 'acl_revoke', (), 'acl_multiple_revoke'), ) diff --git a/apps/acls/views.py b/apps/acls/views.py index eab8f25f73..6bad2858c7 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -1,3 +1,4 @@ +import logging import operator import itertools @@ -14,41 +15,36 @@ from django.contrib.auth.models import User, Group from django.core.exceptions import ObjectDoesNotExist from django.utils.simplejson import loads -from permissions.api import check_permissions, namespace_titles, get_permission_label, get_permission_namespace_label -from permissions.models import Permission +from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL from acls.models import AccessEntry, AccessObject, AccessHolder from acls.widgets import object_w_content_type_icon +from acls.forms import HolderSelectionForm + +logger = logging.getLogger(__name__) def _permission_titles(permission_list): - return u', '.join([get_permission_label(permission) for permission in permission_list]) + return u', '.join([unicode(permission) for permission in permission_list]) def acl_list_for(request, obj, extra_context=None): - #check_permissions(request.user, [ACLS_VIEW_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) ct = ContentType.objects.get_for_model(obj) context = { - #'app_label': ct.app_label, - #'model_name': ct.model, 'object_list': AccessEntry.objects.get_holders_for(obj), 'title': _(u'access control lists for: %s' % obj), #'multi_select_as_buttons': True, #'hide_links': True, 'extra_columns': [ - #{'name': _(u'holder'), 'attribute': 'label'}, - #{'name': _(u'obj'), 'attribute': 'holder_object'}, - #{'name': _(u'gid'), 'attribute': 'gid'}, {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, - {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_permissions_for_holder(obj, x.source_object)))}, - #{'name': _(u'arguments'), 'attribute': 'arguments'} + {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, ], - #'hide_link': True, 'hide_object': True, 'access_object': AccessObject.encapsulate(obj) } @@ -67,7 +63,7 @@ def acl_list(request, app_label, model_name, object_id): def acl_detail(request, access_object_gid, holder_object_gid): - #check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) try: holder = AccessHolder.get(gid=holder_object_gid) @@ -75,7 +71,7 @@ def acl_detail(request, access_object_gid, holder_object_gid): except ObjectDoesNotExist: raise Http404 - permission_list = list(set(AccessEntry.objects.get_permissions_for_holder(access_object.source_object, request.user))) + permission_list = list(access_object.get_class_permissions()) #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { @@ -84,8 +80,8 @@ def acl_detail(request, access_object_gid, holder_object_gid): 'title': _(u'permissions held by: %s for %s' % (holder, access_object)), 'object_list': permission_list, 'extra_columns': [ - {'name': _(u'namespace'), 'attribute': encapsulate(lambda x: get_permission_namespace_label(x))}, - {'name': _(u'name'), 'attribute': encapsulate(lambda x: get_permission_label(x))}, + {'name': _(u'namespace'), 'attribute': 'namespace'}, + {'name': _(u'label'), 'attribute': 'label'}, { 'name':_(u'has permission'), 'attribute': encapsulate(lambda x: two_state_template(AccessEntry.objects.has_accesses(x, holder.source_object, access_object.source_object))) @@ -98,7 +94,6 @@ def acl_detail(request, access_object_gid, holder_object_gid): ] return render_to_response('generic_detail.html', { - #'form': form, 'object': access_object.obj, 'subtemplates_list': subtemplates_list, 'multi_select_as_buttons': True, @@ -106,15 +101,12 @@ def acl_detail(request, access_object_gid, holder_object_gid): 'permission_pk': lambda x: x.pk, 'holder_gid': lambda x: holder.gid, 'object_gid': lambda x: access_object.gid, - #'requester_id': lambda x: role.pk, - #'requester_app_label': lambda x: ContentType.objects.get_for_model(role).app_label, - #'requester_model': lambda x: ContentType.objects.get_for_model(role).model, }, }, context_instance=RequestContext(request)) def acl_grant(request): - check_permissions(request.user, [ACLS_EDIT_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) post_action_redirect = None @@ -122,8 +114,15 @@ def acl_grant(request): previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None))) items = {} + title_suffix = [] + navigation_object = None + navigation_object_count = 0 + for item_properties in items_property_list: - permission = get_object_or_404(Permission, pk=item_properties['permission_pk']) + try: + permission = Permission.objects.get({'pk': item_properties['permission_pk']}) + except Permission.DoesNotExist: + raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) @@ -133,52 +132,36 @@ def acl_grant(request): items.setdefault(requester, {}) items[requester].setdefault(access_object, []) items[requester][access_object].append(permission) + navigation_object = access_object + navigation_object_count += 1 - title_suffix = [] - for requester, access_objects_dict in items.items(): - title_suffix.append(unicode(requester)) - for access_object, permissions in access_objects_dict.items(): - if len(permissions) == 1: - permissions_label = _(u'permission') - else: - permissions_label = _(u'permissions') - - title_suffix.append(permission for permission in permissions) - - - title_suffix.append(unicode(access_object)) - #title_suffix.append(_(u'the permissions')) + for requester, obj_ps in items.items(): + for obj, ps in obj_ps.items(): + title_suffix.append(_(u' and ').join([u'"%s"' % unicode(p) for p in ps])) + title_suffix.append(_(u' for %s') % obj) + title_suffix.append(_(u' to %s') % requester) - - #items = access_objects[access_object] - #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] - - #title_suffix - # Warning: trial and error black magic ahead - #title_suffix.append(_(u' and ').join([_(u'%s to %s') % (', '.join(['"%s"' % unicode(ps) for ps in p]), 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: - # permissions_label = _(u'permissions') - #title_suffix.append(_(t - - print title_suffix - #title_suffix = _(u' and ').join(title_suffix) - permissions_label = _(u'permissions') + if len(items_property_list) == 1: + title_prefix = _(u'Are you sure you wish to grant the permission %(title_suffix)s?') + else: + title_prefix = _(u'Are you sure you wish to grant the permissions %(title_suffix)s?') if request.method == 'POST': - for item in items: - if item['permission'].grant_to(item['requester']): - messages.success(request, _(u'Permission "%(permission)s" granted to: %(requester)s.') % { - 'permission': item['permission'], 'requester': item['requester']}) - else: - messages.warning(request, _(u'%(requester)s, already had the permission "%(permission)s" granted.') % { - 'requester': item['requester'], 'permission': item['permission']}) + for requester, object_permissions in items.items(): + for obj, permissions in object_permissions.items(): + for permission in permissions: + if AccessEntry.objects.grant(permission, requester.source_object, obj.source_object): + messages.success(request, _(u'Permission "%(permission)s" granted to %(requester)s for %(object)s.') % { + 'permission': permission, + 'requester': requester, + 'object': obj + }) + else: + messages.warning(request, _(u'%(requester)s, already had the permission "%(permission)s" granted for %(object)s.') % { + 'requester': requester, + 'permission': permission, + 'object': obj, + }) return HttpResponseRedirect(next) @@ -189,13 +172,172 @@ def acl_grant(request): 'form_icon': u'key_add.png', } - context['title'] = _(u'Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?') % { - 'permissions_label': permissions_label, - 'title_suffix': title_suffix, + context['title'] = title_prefix % { + 'title_suffix': u''.join(title_suffix), } - if len(grouped_items) == 1: - context['object'] = grouped_items[0][0] + logger.debug('navigation_object_count: %d' % navigation_object_count) + logger.debug('navigation_object: %s' % navigation_object) + if navigation_object_count == 1: + context['object'] = navigation_object.source_object return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) + + +def acl_revoke(request): + Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + items_property_list = loads(request.GET.get('items_property_list', [])) + post_action_redirect = None + + 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))) + + items = {} + title_suffix = [] + navigation_object = None + navigation_object_count = 0 + + for item_properties in items_property_list: + try: + permission = Permission.objects.get({'pk': item_properties['permission_pk']}) + except Permission.DoesNotExist: + raise Http404 + try: + requester = AccessHolder.get(gid=item_properties['holder_gid']) + access_object = AccessObject.get(gid=item_properties['object_gid']) + except ObjectDoesNotExist: + raise Http404 + + items.setdefault(requester, {}) + items[requester].setdefault(access_object, []) + items[requester][access_object].append(permission) + navigation_object = access_object + navigation_object_count += 1 + + for requester, obj_ps in items.items(): + for obj, ps in obj_ps.items(): + title_suffix.append(_(u' and ').join([u'"%s"' % unicode(p) for p in ps])) + title_suffix.append(_(u' for %s') % obj) + title_suffix.append(_(u' from %s') % requester) + + if len(items_property_list) == 1: + title_prefix = _(u'Are you sure you wish to revoke the permission %(title_suffix)s?') + else: + title_prefix = _(u'Are you sure you wish to revoke the permissions %(title_suffix)s?') + + if request.method == 'POST': + for requester, object_permissions in items.items(): + for obj, permissions in object_permissions.items(): + for permission in permissions: + if AccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): + messages.success(request, _(u'Permission "%(permission)s" revoked of %(requester)s for %(object)s.') % { + 'permission': permission, + 'requester': requester, + 'object': obj + }) + else: + messages.warning(request, _(u'%(requester)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { + 'requester': requester, + 'permission': permission, + 'object': obj, + }) + + return HttpResponseRedirect(next) + + context = { + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'key_delete.png', + } + + context['title'] = title_prefix % { + 'title_suffix': u''.join(title_suffix), + } + + logger.debug('navigation_object_count: %d' % navigation_object_count) + logger.debug('navigation_object: %s' % navigation_object) + if navigation_object_count == 1: + context['object'] = navigation_object.source_object + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + +''' +def get_role_members(role): + 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])] + + +def get_non_role_members(role): + #non members = all users - members - staff - super users + 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) + + +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 + + +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() + +def role_members(request, role_id): + 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)), + 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, + right_list_title=_(u'members of role: %s') % role, + extra_context={ + 'object': role, + 'object_name': _(u'role'), + } + ) +''' + + +def acl_new_holder_for(request, obj, extra_context=None): + Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + + if request.method == 'POST': + form = HolderSelectionForm(request.POST) + if form.is_valid(): + try: + access_object = AccessObject.encapsulate(obj) + access_holder = AccessHolder.get(form.cleaned_data['holder_gid']) + + return HttpResponseRedirect(reverse('acl_detail', args=[access_object.gid, access_holder.gid])) + except ObjectDoesNotExist: + raise Http404 + else: + form = HolderSelectionForm() + + context = { + 'form': form, + 'title': _(u'add new holder for: %s') % obj, + } + + if extra_context: + context.update(extra_context) + + return render_to_response('generic_form.html', context, + context_instance=RequestContext(request)) + From 14f53d539718c840b85de3a6094f0d83988d14d9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:46:08 -0400 Subject: [PATCH 052/484] Add get_object_name function used by the acl new holder form --- apps/common/utils.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/common/utils.py b/apps/common/utils.py index 67db70c942..3ff3bf9677 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -326,6 +326,19 @@ def generate_choices_w_labels(choices, display_object_type=True): return sorted(results, key=lambda x: x[1]) +def get_object_name(obj, display_object_type=True): + ct_label = ContentType.objects.get_for_model(obj).name + label = unicode(obj) + if isinstance(obj, User): + label = obj.get_full_name() if obj.get_full_name() else obj + + if display_object_type: + verbose_name = unicode(getattr(obj._meta, u'verbose_name', ct_label)) + return u'%s: %s' % (verbose_name, label) + else: + return u'%s' % (label) + + def return_diff(old_obj, new_obj, attrib_list=None): diff_dict = {} if not attrib_list: From b2097eeb7566303ed6f6e62de9e2baa7cd57ce44 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:48:58 -0400 Subject: [PATCH 053/484] Updated document_acl app --- apps/document_acls/__init__.py | 7 +++++-- apps/document_acls/urls.py | 3 ++- apps/document_acls/views.py | 13 ++++++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index ec449dac37..dc89ed3174 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -3,8 +3,11 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import Document from navigation.api import register_links, register_multi_item_links from project_setup.api import register_setup +from acls import ACLS_VIEW_ACL -#from acls import ACLS_VIEW_ACL -acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} +acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +document_new_holder = {'text': _(u'New holder'), 'view': 'document_new_holder', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} register_links(Document, [acl_list], menu_name='form_header') + +register_links(['document_acl_list', 'document_new_holder'], [document_new_holder], menu_name='sidebar') diff --git a/apps/document_acls/urls.py b/apps/document_acls/urls.py index ed86e90c81..e86dc9d4fc 100644 --- a/apps/document_acls/urls.py +++ b/apps/document_acls/urls.py @@ -1,5 +1,6 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('document_acls.views', - url(r'^list_for/(?P\d+)/$', 'document_acl_list', (), 'document_acl_list'), + url(r'^list_for/document/(?P\d+)/$', 'document_acl_list', (), 'document_acl_list'), + url(r'^new_holder_for/document/(?P\d+)/$', 'document_new_holder', (), 'document_new_holder'), ) diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 4b20a038ee..505770fa99 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -2,7 +2,7 @@ from django.shortcuts import render_to_response, get_object_or_404 from django.utils.translation import ugettext_lazy as _ from documents.models import Document -from acls.views import acl_list_for +from acls.views import acl_list_for, acl_new_holder_for from acls.models import AccessEntry @@ -15,3 +15,14 @@ def document_acl_list(request, document_id): 'object': document, } ) + + +def document_new_holder(request, document_id): + document = get_object_or_404(Document, pk=document_id) + return acl_new_holder_for( + request, + document, + extra_context={ + 'object': document, + } + ) From 4c57c788f5c0d9ae708a954f9857f083448ac3f4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:49:21 -0400 Subject: [PATCH 054/484] Add documents app class_permissions for Document class --- apps/documents/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index b0754b8846..d9f4da730d 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -11,6 +11,7 @@ from tags.widgets import get_tags_inline_widget_simple from history.api import register_history_type from metadata.api import get_metadata_string from project_setup.api import register_setup +from acls.models import class_permissions from documents.models import (Document, DocumentPage, DocumentPageTransformation, DocumentType, DocumentTypeFilename, @@ -202,3 +203,13 @@ if (validate_path(document_settings.CACHE_PATH) == False) or (not document_setti setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp()) register_setup(document_type_setup) + +class_permissions(Document, [ + PERMISSION_DOCUMENT_PROPERTIES_EDIT, + PERMISSION_DOCUMENT_EDIT, + PERMISSION_DOCUMENT_VIEW, + PERMISSION_DOCUMENT_DELETE, + PERMISSION_DOCUMENT_DOWNLOAD, + PERMISSION_DOCUMENT_TRANSFORM, + PERMISSION_DOCUMENT_VERSION_REVERT +]) From 0ac79b633ab697ff596955f4ab7e7033252ae201 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:49:44 -0400 Subject: [PATCH 055/484] Add metadata class_permissions permissions for the Document class --- apps/metadata/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index 80ab8afe6a..af514ca648 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -6,6 +6,7 @@ from permissions.models import Permission, PermissionNamespace from documents.models import Document, DocumentType from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT from project_setup.api import register_setup +from acls.models import class_permissions from metadata.models import MetadataType, MetadataSet @@ -68,3 +69,10 @@ 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, +]) From 1c91bfd0013e86b6aaf768af531c59900ebbaeee Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 11:50:25 -0400 Subject: [PATCH 056/484] Disable document signature verification until circular import is found --- apps/django_gpg/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index 3d703f21d6..3cebb1c5ad 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -1,6 +1,6 @@ from django.utils.translation import ugettext_lazy as _ -from documents.models import Document +#from documents.models import Document from navigation.api import register_links, register_top_menu, \ register_model_list_columns, register_multi_item_links, \ register_sidebar_template @@ -40,7 +40,7 @@ key_setup = {'text': _(u'key management'), 'view': 'key_public_list', 'args': 'o # Document views document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} -register_links(Document, [document_verify], menu_name='form_header') +#register_links(Document, [document_verify], menu_name='form_header') register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') From 15e935173e615b6f000989c5feff1d70023944a2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 12:01:59 -0400 Subject: [PATCH 057/484] Update complete Italian translation --- .../converter/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 19010 bytes .../converter/locale/it/LC_MESSAGES/django.po | 453 +++++++++--------- .../locale/it/LC_MESSAGES/django.mo | Bin 521 -> 4723 bytes .../locale/it/LC_MESSAGES/django.po | 134 +++--- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 1791 bytes .../locale/it/LC_MESSAGES/django.po | 43 +- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 4162 bytes .../locale/it/LC_MESSAGES/django.po | 89 ++-- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 2118 bytes .../locale/it/LC_MESSAGES/django.po | 49 +- apps/folders/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 4333 bytes apps/folders/locale/it/LC_MESSAGES/django.po | 91 ++-- apps/history/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 1478 bytes apps/history/locale/it/LC_MESSAGES/django.po | 47 +- apps/linking/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 7140 bytes apps/linking/locale/it/LC_MESSAGES/django.po | 152 +++--- apps/main/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 2531 bytes apps/main/locale/it/LC_MESSAGES/django.po | 64 +-- apps/metadata/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 9782 bytes apps/metadata/locale/it/LC_MESSAGES/django.po | 203 ++++---- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 682 bytes .../locale/it/LC_MESSAGES/django.po | 11 +- apps/ocr/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 9009 bytes apps/ocr/locale/it/LC_MESSAGES/django.po | 198 ++++---- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 3264 bytes .../locale/it/LC_MESSAGES/django.po | 85 ++-- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 617 bytes .../locale/it/LC_MESSAGES/django.po | 9 +- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 561 bytes .../locale/it/LC_MESSAGES/django.po | 7 +- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 664 bytes .../locale/it/LC_MESSAGES/django.po | 13 +- apps/sources/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 8598 bytes apps/sources/locale/it/LC_MESSAGES/django.po | 208 ++++---- apps/tags/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 4271 bytes apps/tags/locale/it/LC_MESSAGES/django.po | 122 ++--- .../locale/it/LC_MESSAGES/django.mo | Bin 501 -> 4746 bytes .../locale/it/LC_MESSAGES/django.po | 109 +++-- .../web_theme/locale/it/LC_MESSAGES/django.mo | Bin 501 -> 1740 bytes .../web_theme/locale/it/LC_MESSAGES/django.po | 30 +- 40 files changed, 1134 insertions(+), 983 deletions(-) diff --git a/apps/converter/locale/it/LC_MESSAGES/django.mo b/apps/converter/locale/it/LC_MESSAGES/django.mo index 72cbfdd28e96e44641807cba5841648db40f9397..8c019894646f24a17d0b11e0f11c9cec637fa4a8 100644 GIT binary patch literal 19010 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 delta 111 zcmX>!h4Cx1#XTXGsSH5C2*ff#tOCT$K&%7AAYcK+yMdCHKpLb51}3-b&f_+))HOCx rFfg$)HJxmrCobU@>f@u}=jiLIVB_lR=;`C&=;9LO8XP>iSnnwSY<&}V diff --git a/apps/converter/locale/it/LC_MESSAGES/django.po b/apps/converter/locale/it/LC_MESSAGES/django.po index 5e8e9ffb0a..b50328c57f 100644 --- a/apps/converter/locale/it/LC_MESSAGES/django.po +++ b/apps/converter/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:55+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 14:53+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,889 +20,896 @@ msgstr "" #: __init__.py:10 msgid "file formats" -msgstr "" +msgstr "formato file" #: literals.py:19 msgid "Resize" -msgstr "" +msgstr "Ridimensiona" #: literals.py:20 msgid "Resize." -msgstr "" +msgstr "Ridimensiona" #: literals.py:22 literals.py:37 msgid "width" -msgstr "" +msgstr "larghezza" #: literals.py:23 literals.py:38 msgid "height" -msgstr "" +msgstr "altezza" #: literals.py:27 msgid "Rotate" -msgstr "" +msgstr "Ruotare" #: literals.py:28 msgid "Rotate by n degress." -msgstr "" +msgstr "Ruotate di n gradi" #: literals.py:30 msgid "degrees" -msgstr "" +msgstr "gradi" #: literals.py:34 msgid "Density" -msgstr "" +msgstr "Densità" #: literals.py:35 msgid "Change the resolution (ie: DPI) without resizing." -msgstr "" +msgstr "Cambia risoluzione (ie:DPi) senza ridimensionare" #: literals.py:42 msgid "Zoom" -msgstr "" +msgstr "Zoom" #: literals.py:43 msgid "Zoom by n percent." -msgstr "" +msgstr "Zoom in percentuale" #: literals.py:45 msgid "percent" -msgstr "" +msgstr "percento" #: literals.py:51 msgid "Hasselblad Photo RAW, CFV/H3D39II" -msgstr "" +msgstr "Hasselblad Photo RAW, CFV/H3D39II" #: literals.py:52 literals.py:53 msgid "Photoshop resource format" -msgstr "" +msgstr "risorsa per il formato Photoshop" #: literals.py:54 msgid "Photoshop resource text format" -msgstr "" +msgstr "risorsa per il formato txt di Photoshop" #: literals.py:55 msgid "Photoshop resource wide text format" -msgstr "" +msgstr "risorsa per un formato testo grande di Photoshop" #: literals.py:57 msgid "Raw alpha samples" -msgstr "" +msgstr "esempi Raw alpha" #: literals.py:58 msgid "Adobe Illustrator CS2" -msgstr "" +msgstr "Adobe Illustrator CS2" #: literals.py:59 msgid "Raw application information" -msgstr "" +msgstr "Informazioni appliaczione Raw" #: literals.py:60 msgid "Raw JPEG binary data" -msgstr "" +msgstr "Raw JPEG binary data" #: literals.py:61 msgid "PFS: 1st Publisher Clip Art" -msgstr "" +msgstr "PFS: 1st Publisher Clip Art" #: literals.py:62 msgid "Sony Alpha DSLR Raw Image Format" -msgstr "" +msgstr "Sony Alpha DSLR Raw Image Format" #: literals.py:63 msgid "Microsoft Audio/Visual Interleaved" -msgstr "" +msgstr "Microsoft Audio/Visual Interleaved" #: literals.py:64 msgid "AVS X image" -msgstr "" +msgstr "AVS X image" #: literals.py:66 msgid "Raw blue samples" -msgstr "" +msgstr "Esempi Raw blue" #: literals.py:67 msgid "Raw blue, green, and red samples" -msgstr "" +msgstr "Esempi di Raw blue, verde e rosso" #: literals.py:68 msgid "Raw blue, green, red and alpha samples" -msgstr "" +msgstr "Esempi alpha Raw blue, verde e rosso" #: literals.py:69 msgid "Microsoft Windows bitmap image" -msgstr "" +msgstr "Microsoft Windows bitmap image" #: literals.py:70 msgid "Microsoft Windows bitmap image version 2" -msgstr "" +msgstr "Microsoft Windows bitmap image version 2" #: literals.py:71 msgid "Microsoft Windows bitmap image version 3" -msgstr "" +msgstr "Microsoft Windows bitmap image version 3" #: literals.py:72 msgid "BRF ASCII Braille format" -msgstr "" +msgstr "BRF ASCII Braille format" #: literals.py:73 msgid "Raw blue, red, and green samples" -msgstr "" +msgstr "Esempi Raw blue, rosso e verde" #: literals.py:75 msgid "Raw cyan samples" -msgstr "" +msgstr "Esempi Raw cyan" #: literals.py:76 literals.py:181 msgid "Magick Persistent Cache image format" -msgstr "" +msgstr "Magick Persistent Cache image format" #: literals.py:77 literals.py:78 msgid "Continuous Acquisition and Life-cycle Support Type 1 image" -msgstr "" +msgstr "Continuous Acquisition and Life-cycle Support Type 1 image" #: literals.py:79 msgid "Image caption" -msgstr "" +msgstr "Image caption" #: literals.py:80 msgid "Cineon Image File" -msgstr "" +msgstr "Cineon Image File" #: literals.py:81 msgid "Cisco IP phone image format" -msgstr "" +msgstr "Cisco IP phone image format" #: literals.py:82 msgid "Image Clip Mask" -msgstr "" +msgstr "Image Clip Mask" #: literals.py:83 msgid "Raw cyan, magenta, yellow, and black samples" -msgstr "" +msgstr "Raw cyan, magenta, yellow, and black samples" #: literals.py:84 msgid "Raw cyan, magenta, yellow, black, and opacity samples" -msgstr "" +msgstr "Raw cyan, magenta, yellow, black, and opacity samples" #: literals.py:85 literals.py:86 msgid "Canon Digital Camera Raw Image Format" -msgstr "" +msgstr "Canon Digital Camera Raw Image Format" #: literals.py:87 msgid "Microsoft Cursor Icon" -msgstr "" +msgstr "Microsoft Cursor Icon" #: literals.py:88 msgid "DR Halo" -msgstr "" +msgstr "DR Halo" #: literals.py:90 msgid "Digital Imaging and Communications in Medicine image" -msgstr "" +msgstr "Digital Imaging and Communications in Medicine image" #: literals.py:91 msgid "Kodak Digital Camera Raw Image File" -msgstr "" +msgstr "Kodak Digital Camera Raw Image File" #: literals.py:92 msgid "ZSoft IBM PC multi-page Paintbrush" -msgstr "" +msgstr "ZSoft IBM PC multi-page Paintbrush" #: literals.py:93 msgid "Microsoft DirectDraw Surface" -msgstr "" +msgstr "Microsoft DirectDraw Surface" #: literals.py:94 msgid "Multi-face font package (Freetype 2.4.2)" -msgstr "" +msgstr "Multi-face font package (Freetype 2.4.2)" #: literals.py:95 msgid "Déjà vu" -msgstr "" +msgstr "Déjà vu" #: literals.py:96 msgid "Adobe Digital Negative" -msgstr "" +msgstr "Adobe Digital Negative" #: literals.py:97 msgid "Graphviz" -msgstr "" +msgstr "Graphviz" #: literals.py:98 msgid "SMPTE 268M-2003 (DPX 2.0)" -msgstr "" +msgstr "SMPTE 268M-2003 (DPX 2.0)" #: literals.py:100 msgid "Encapsulated Portable Document Format" -msgstr "" +msgstr "Encapsulated Portable Document Format" #: literals.py:101 literals.py:106 msgid "Adobe Encapsulated PostScript Interchange format" -msgstr "" +msgstr "Adobe Encapsulated PostScript Interchange format" #: literals.py:102 literals.py:105 msgid "Adobe Encapsulated PostScript" -msgstr "" +msgstr "Adobe Encapsulated PostScript" #: literals.py:103 msgid "Adobe Level II Encapsulated PostScript" -msgstr "" +msgstr "Adobe Level II Encapsulated PostScript" #: literals.py:104 msgid "Adobe Level III Encapsulated PostScript" -msgstr "" +msgstr "Adobe Level III Encapsulated PostScript" #: literals.py:107 msgid "Adobe Encapsulated PostScript with TIFF preview" -msgstr "" +msgstr "Adobe Encapsulated PostScript with TIFF preview" #: literals.py:108 msgid "Adobe Level II Encapsulated PostScript with TIFF preview" -msgstr "" +msgstr "Adobe Level II Encapsulated PostScript with TIFF preview" #: literals.py:109 msgid "Adobe Level III Encapsulated PostScript with TIFF preview" -msgstr "" +msgstr "Adobe Level III Encapsulated PostScript with TIFF preview" #: literals.py:110 msgid "Epson RAW Format" -msgstr "" +msgstr "Epson RAW Format" #: literals.py:111 msgid "Exif digital camera binary data" -msgstr "" +msgstr "Exif digital camera binary data" #: literals.py:112 msgid "High Dynamic-range (HDR)" -msgstr "" +msgstr "High Dynamic-range (HDR)" #: literals.py:114 msgid "Group 3 FAX (Not TIFF Group3 FAX)" -msgstr "" +msgstr "Group 3 FAX (Not TIFF Group3 FAX)" #: literals.py:115 msgid "Autodesk FLI animations file" -msgstr "" +msgstr "Autodesk FLI animations file" #: literals.py:116 msgid "Autodesk FLC animations file" -msgstr "" +msgstr "Autodesk FLC animations file" #: literals.py:117 literals.py:120 msgid "Flexible Image Transport System" -msgstr "" +msgstr "Flexible Image Transport System" #: literals.py:118 msgid "Kodak FlashPix file" -msgstr "" +msgstr "Kodak FlashPix file" #: literals.py:119 literals.py:225 msgid "Plasma fractal image" -msgstr "" +msgstr "Plasma fractal image" #: literals.py:122 msgid "Raw green samples" -msgstr "" +msgstr "Raw green samples" #: literals.py:123 msgid "Group 3 FAX" -msgstr "" +msgstr "Group 3 FAX" #: literals.py:124 msgid "Raw green, blue, and red samples" -msgstr "" +msgstr "Raw green, blue, and red samples" #: literals.py:125 msgid "GIMP brush file" -msgstr "" +msgstr "GIMP brush file" #: literals.py:126 msgid "CompuServe graphics interchange format (version 89a)" -msgstr "" +msgstr "CompuServe graphics interchange format (version 89a)" #: literals.py:127 msgid "CompuServe graphics interchange format (version 87a)" -msgstr "" +msgstr "CompuServe graphics interchange format (version 87a)" #: literals.py:128 msgid "Gradual passing from one shade to another" -msgstr "" +msgstr "Passaggio graduale da un colore ad un altro" #: literals.py:129 msgid "Raw gray samples" -msgstr "" +msgstr "Raw gray samples" #: literals.py:130 msgid "Raw green, red, and blue samples" -msgstr "" +msgstr "Raw green, red, and blue samples" #: literals.py:131 msgid "Raw CCITT Group4" -msgstr "" +msgstr "Raw CCITT Group4" #: literals.py:133 msgid "Histogram of the image" -msgstr "" +msgstr "Istogramma di questa immagine" #: literals.py:134 msgid "HRZ: Slow scan TV" -msgstr "" +msgstr "HRZ: Slow scan TV" #: literals.py:135 literals.py:136 literals.py:255 msgid "Hypertext Markup Language and a client-side image map" -msgstr "" +msgstr "Hypertext Markup Language and a client-side image map" #: literals.py:138 literals.py:264 literals.py:279 literals.py:283 msgid "Truevision Targa image" -msgstr "" +msgstr "Truevision Targa image" #: literals.py:139 literals.py:140 msgid "ICC Color Profile" -msgstr "" +msgstr "ICC Color Profile" #: literals.py:141 literals.py:142 msgid "Microsoft Icon" -msgstr "" +msgstr "Microsoft Icon" #: literals.py:143 msgid "Hald CLUT identity image" -msgstr "" +msgstr "Hald CLUT identity image" #: literals.py:144 msgid "LabEye image format" -msgstr "" +msgstr "LabEye image format" #: literals.py:145 msgid "GraphicsMagick Embedded Image" -msgstr "" +msgstr "GraphicsMagick Embedded Image" #: literals.py:146 msgid "The image format and characteristics" -msgstr "" +msgstr "Formato e caratteristiche dell'immagine" #: literals.py:147 msgid "Base64-encoded inline images" -msgstr "" +msgstr "Base64-encoded inline images" #: literals.py:148 msgid "IPL Image Sequence" -msgstr "" +msgstr "IPL Image Sequence" #: literals.py:149 msgid "IPTC Newsphoto" -msgstr "" +msgstr "IPTC Newsphoto" #: literals.py:150 literals.py:151 msgid "IPTC Newsphoto text format" -msgstr "" +msgstr "IPTC Newsphoto text format" #: literals.py:152 msgid "ISO/TR 11548-1 format" -msgstr "" +msgstr "ISO/TR 11548-1 format" #: literals.py:154 literals.py:157 msgid "JPEG-2000 Code Stream Syntax" -msgstr "" +msgstr "JPEG-2000 Code Stream Syntax" #: literals.py:155 msgid "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" -msgstr "" +msgstr "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:156 msgid "JPEG-2000 JP2 File Format Syntax" -msgstr "" +msgstr "JPEG-2000 JP2 File Format Syntax" #: literals.py:158 literals.py:159 msgid "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" -msgstr "" +msgstr "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" #: literals.py:160 msgid "JPEG-2000 File Format Syntax" -msgstr "" +msgstr "JPEG-2000 File Format Syntax" #: literals.py:162 msgid "Raw black samples" -msgstr "" +msgstr "Raw black samples" #: literals.py:163 literals.py:164 msgid "Kodak Digital Camera Raw Image Format" -msgstr "" +msgstr "Kodak Digital Camera Raw Image Format" #: literals.py:166 msgid "Image label" -msgstr "" +msgstr "Image label" #: literals.py:168 msgid "Raw magenta samples" -msgstr "" +msgstr "Raw magenta samples" #: literals.py:169 literals.py:179 literals.py:182 literals.py:183 msgid "MPEG Video Stream" -msgstr "" +msgstr "MPEG Video Stream" #: literals.py:170 msgid "Raw MPEG-4 Video" -msgstr "" +msgstr "Raw MPEG-4 Video" #: literals.py:171 msgid "Colormap intensities and indices" -msgstr "" +msgstr "Intensità colormap e indici" #: literals.py:172 msgid "MATLAB image format" -msgstr "" +msgstr "MATLAB image format" #: literals.py:173 msgid "MATTE raw opacity format" -msgstr "" +msgstr "MATTE raw opacity format" #: literals.py:174 msgid "8-bit McIdas area file" -msgstr "" +msgstr "8-bit McIdas area file" #: literals.py:175 msgid "Microsoft Image Composer (MIC) file" -msgstr "" +msgstr "Microsoft Image Composer (MIC) file" #: literals.py:176 msgid "Magick Image File Format" -msgstr "" +msgstr "Magick Image File Format" #: literals.py:177 msgid "" "Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" msgstr "" +"Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:178 msgid "Raw Bi-level bitmap in least-significant-byte first order" -msgstr "" +msgstr "Raw Bi-level bitmap in least-significant-byte first order" #: literals.py:180 msgid "MPEG-4 Video Stream" -msgstr "" +msgstr "MPEG-4 Video Stream" #: literals.py:184 msgid "Sony (Minolta) Raw Image File" -msgstr "" +msgstr "Sony (Minolta) Raw Image File" #: literals.py:185 msgid "Magick Scripting Language" -msgstr "" +msgstr "Magick Scripting Language" #: literals.py:186 msgid "Windows 1 and 2 MSP file format" -msgstr "" +msgstr "Windows 1 and 2 MSP file format" #: literals.py:187 msgid "ImageMagick's own SVG internal renderer" -msgstr "" +msgstr "ImageMagick's own SVG internal renderer" #: literals.py:188 msgid "MTV Raytracing image format" -msgstr "" +msgstr "MTV Raytracing image format" #: literals.py:189 msgid "Magick Vector Graphics" -msgstr "" +msgstr "Magick Vector Graphics" #: literals.py:191 msgid "Nikon Digital SLR Camera Raw Image File" -msgstr "" +msgstr "Nikon Digital SLR Camera Raw Image File" #: literals.py:192 msgid "Constant image of uniform color" -msgstr "" +msgstr "Immagine costante di colore uniforme" #: literals.py:194 msgid "Raw opacity samples" -msgstr "" +msgstr "Campioni di opacità grezza" #: literals.py:195 msgid "Olympus Digital Camera Raw Image File" -msgstr "" +msgstr "Olympus Digital Camera Raw Image File" #: literals.py:196 msgid "On-the-air bitmap" -msgstr "" +msgstr "On-the-air bitmap" #: literals.py:197 msgid "Open Type font (Freetype 2.4.2)" -msgstr "" +msgstr "Open Type font (Freetype 2.4.2)" #: literals.py:199 msgid "Xv thumbnail format" -msgstr "" +msgstr "Xv thumbnail format" #: literals.py:200 literals.py:277 msgid "16bit/pixel interleaved YUV" -msgstr "" +msgstr "16bit/pixel interleaved YUV" #: literals.py:201 msgid "Palm pixmap" -msgstr "" +msgstr "Palm pixmap" #: literals.py:202 msgid "Common 2-dimensional bitmap format" -msgstr "" +msgstr "Formato comune di bitmap 2 dimenzionale" #: literals.py:203 msgid "Predefined pattern" -msgstr "" +msgstr "Pattern predefinito" #: literals.py:204 msgid "Portable bitmap format (black and white)" -msgstr "" +msgstr "Portable bitmap format (black and white)" #: literals.py:205 literals.py:206 msgid "Photo CD" -msgstr "" +msgstr "Photo CD" #: literals.py:207 msgid "Page Control Language" -msgstr "" +msgstr "Page Control Language" #: literals.py:208 literals.py:221 msgid "Apple Macintosh QuickDraw/PICT" -msgstr "" +msgstr "Apple Macintosh QuickDraw/PICT" #: literals.py:209 msgid "ZSoft IBM PC Paintbrush" -msgstr "" +msgstr "ZSoft IBM PC Paintbrush" #: literals.py:210 msgid "Palm Database ImageViewer Format" -msgstr "" +msgstr "Palm Database ImageViewer Format" #: literals.py:211 msgid "Portable Document Format" -msgstr "" +msgstr "Portable Document Format" #: literals.py:212 msgid "Portable Document Archive Format" -msgstr "" +msgstr "Portable Document Archive Format" #: literals.py:213 msgid "Pentax Electronic File" -msgstr "" +msgstr "Pentax Electronic File" #: literals.py:214 msgid "Embrid Embroidery Format" -msgstr "" +msgstr "Embrid Embroidery Format" #: literals.py:215 msgid "Postscript Type 1 font (ASCII) (Freetype 2.4.2)" -msgstr "" +msgstr "Postscript Type 1 font (ASCII) (Freetype 2.4.2)" #: literals.py:216 msgid "Postscript Type 1 font (binary) (Freetype 2.4.2)" -msgstr "" +msgstr "Postscript Type 1 font (binary) (Freetype 2.4.2)" #: literals.py:217 msgid "Portable float format" -msgstr "" +msgstr "Portable float format" #: literals.py:218 msgid "Portable graymap format (gray scale)" -msgstr "" +msgstr "Portable graymap format (gray scale)" #: literals.py:219 msgid "JPEG-2000 VM Format" -msgstr "" +msgstr "JPEG-2000 VM Format" #: literals.py:220 msgid "Personal Icon" -msgstr "" +msgstr "Personal Icon" #: literals.py:222 msgid "Alias/Wavefront RLE image format" -msgstr "" +msgstr "Alias/Wavefront RLE image format" #: literals.py:223 msgid "PIXAR raster file" -msgstr "" +msgstr "PIXAR raster file" #: literals.py:224 msgid "Joint Photographic Experts Group JFIF format (62)" -msgstr "" +msgstr "Joint Photographic Experts Group JFIF format (62)" #: literals.py:226 msgid "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" msgstr "" +"Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:227 msgid "" "24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" msgstr "" +"24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:228 msgid "" "32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " "1.2.3.3,1.2.3.4)" msgstr "" +"32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" #: literals.py:229 msgid "" "8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " "1.2.3.3,1.2.3.4)" msgstr "" +"8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" #: literals.py:230 msgid "Portable anymap" -msgstr "" +msgstr "Portable anymap" #: literals.py:231 msgid "Portable pixmap format (color)" -msgstr "" +msgstr "Portable pixmap format (color)" #: literals.py:232 msgid "Show a preview an image enhancement, effect, or f/x" -msgstr "" +msgstr "Mostra l'anteprima d'immagine con gli effetti" #: literals.py:233 msgid "Adobe PostScript" -msgstr "" +msgstr "Adobe PostScript" #: literals.py:234 msgid "Adobe Level II PostScript" -msgstr "" +msgstr "Adobe Level II PostScript" #: literals.py:235 msgid "Adobe Level III PostScript" -msgstr "" +msgstr "Adobe Level III PostScript" #: literals.py:236 msgid "Adobe Large Document Format" -msgstr "" +msgstr "Adobe Large Document Format" #: literals.py:237 msgid "Adobe Photoshop bitmap" -msgstr "" +msgstr "Adobe Photoshop bitmap" #: literals.py:238 msgid "Pyramid encoded TIFF" -msgstr "" +msgstr "Pyramid encoded TIFF" #: literals.py:239 literals.py:253 msgid "Seattle Film Works" -msgstr "" +msgstr "Seattle Film Works" #: literals.py:241 msgid "Raw red samples" -msgstr "" +msgstr "Raw red samples" #: literals.py:242 msgid "Fuji CCD-RAW Graphic File" -msgstr "" +msgstr "Fuji CCD-RAW Graphic File" #: literals.py:243 literals.py:259 msgid "SUN Rasterfile" -msgstr "" +msgstr "SUN Rasterfile" #: literals.py:244 msgid "Raw red, blue, and green samples" -msgstr "" +msgstr "Raw red, blue, and green samples" #: literals.py:245 msgid "Raw red, green, and blue samples" -msgstr "" +msgstr "Raw red, green, and blue samples" #: literals.py:246 msgid "Raw red, green, blue, and matte samples" -msgstr "" +msgstr "Raw red, green, blue, and matte samples" #: literals.py:247 msgid "Raw red, green, blue, and opacity samples" -msgstr "" +msgstr "Raw red, green, blue, and opacity samples" #: literals.py:248 msgid "Alias/Wavefront image" -msgstr "" +msgstr "Alias/Wavefront image" #: literals.py:249 msgid "Utah Run length encoded image" -msgstr "" +msgstr "Utah Run length encoded image" #: literals.py:251 msgid "ZX-Spectrum SCREEN$" -msgstr "" +msgstr "ZX-Spectrum SCREEN$" #: literals.py:252 msgid "Scitex HandShake" -msgstr "" +msgstr "Scitex HandShake" #: literals.py:254 msgid "Irix RGB image" -msgstr "" +msgstr "Irix RGB image" #: literals.py:256 msgid "Sony Raw Format 2" -msgstr "" +msgstr "Sony Raw Format 2" #: literals.py:257 msgid "Sony Raw Format" -msgstr "" +msgstr "Sony Raw Format" #: literals.py:258 msgid "Steganographic image" -msgstr "" +msgstr "Steganographic image" #: literals.py:260 msgid "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" -msgstr "" +msgstr "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" #: literals.py:261 msgid "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" -msgstr "" +msgstr "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" #: literals.py:263 literals.py:273 msgid "Text" -msgstr "" +msgstr "Testo" #: literals.py:265 msgid "EXIF Profile Thumbnail" -msgstr "" +msgstr "EXIF Profile Thumbnail" #: literals.py:266 msgid "Tagged Image File Format (LIBTIFF, Version 3.9.4)" -msgstr "" +msgstr "Tagged Image File Format (LIBTIFF, Version 3.9.4)" #: literals.py:267 msgid "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" -msgstr "" +msgstr "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" #: literals.py:268 msgid "Tile image with a texture" -msgstr "" +msgstr "Immagine modificata con una texture" #: literals.py:269 msgid "PSX TIM" -msgstr "" +msgstr "PSX TIM" #: literals.py:270 msgid "TOPOL X Image" -msgstr "" +msgstr "TOPOL X Image" #: literals.py:271 msgid "TrueType font collection (Freetype 2.4.2)" -msgstr "" +msgstr "TrueType font collection (Freetype 2.4.2)" #: literals.py:272 msgid "TrueType font (Freetype 2.4.2)" -msgstr "" +msgstr "TrueType font (Freetype 2.4.2)" #: literals.py:275 msgid "Unicode Text format" -msgstr "" +msgstr "Testo formato Unicode" #: literals.py:276 msgid "X-Motif UIL table" -msgstr "" +msgstr "X-Motif UIL table" #: literals.py:280 msgid "VICAR rasterfile format" -msgstr "" +msgstr "VICAR rasterfile format" #: literals.py:281 msgid "Visual Image Directory" -msgstr "" +msgstr "Visual Image Directory" #: literals.py:282 literals.py:299 msgid "Khoros Visualization image" -msgstr "" +msgstr "Khoros Visualization image" #: literals.py:285 msgid "Wireless Bitmap (level 0) image" -msgstr "" +msgstr "Wireless Bitmap (level 0) image" #: literals.py:286 msgid "Windows Meta File" -msgstr "" +msgstr "Windows Meta File" #: literals.py:287 msgid "Word Perfect Graphics" -msgstr "" +msgstr "Word Perfect Graphics" #: literals.py:288 msgid "Windows Media Video" -msgstr "" +msgstr "Windows Media Video" #: literals.py:289 msgid "Compressed Windows Meta File" -msgstr "" +msgstr "Compressed Windows Meta File" #: literals.py:291 msgid "X Window System" -msgstr "" +msgstr "X Window System" #: literals.py:292 msgid "Foveon X3 (Sigma/Polaroid) Raw picture file" -msgstr "" +msgstr "Foveon X3 (Sigma/Polaroid) Raw picture file" #: literals.py:293 msgid "X Windows system bitmap (black and white)" -msgstr "" +msgstr "X Windows system bitmap (black and white)" #: literals.py:294 msgid "Constant image uniform color" -msgstr "" +msgstr "Constante d'immagine a colori uniformi" #: literals.py:295 msgid "GIMP image" -msgstr "" +msgstr "GIMP image" #: literals.py:296 msgid "Adobe XML metadata" -msgstr "" +msgstr "Adobe XML metadata" #: literals.py:297 msgid "X Windows system pixmap (color)" -msgstr "" +msgstr "X Windows system pixmap (color)" #: literals.py:298 msgid "Microsoft XML Paper Specification" -msgstr "" +msgstr "Microsoft XML Paper Specification" #: literals.py:300 msgid "XV thumbnail file" -msgstr "" +msgstr "XV thumbnail file" #: literals.py:301 msgid "X Windows system window dump (color)" -msgstr "" +msgstr "X Windows system window dump (color)" #: literals.py:303 msgid "Raw yellow samples" -msgstr "" +msgstr "Raw yellow samples" #: literals.py:304 msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" -msgstr "" +msgstr "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" #: views.py:15 msgid "suported file formats" -msgstr "" +msgstr "formato file supportati" #: views.py:20 msgid "name" -msgstr "" +msgstr "nome" #: views.py:24 msgid "description" -msgstr "" +msgstr "descrizione" #: conf/settings.py:11 msgid "File path to imagemagick's convert program." -msgstr "" +msgstr "File path per il programma di conversione imagemagick" #: conf/settings.py:12 msgid "File path to imagemagick's identify program." -msgstr "" +msgstr "File path per trovare imagemagick" #: conf/settings.py:13 msgid "File path to graphicsmagick's program." -msgstr "" +msgstr "File path per il progarmma " #: conf/settings.py:15 msgid "" @@ -909,20 +917,25 @@ msgid "" "converter.backends.imagemagick, converter.backends.graphicsmagick and " "converter.backends.python." msgstr "" +"Backend da usare per la conversione grafica. Le opzioni sono: " +"converter.backends.imagemagick, converter.backends.graphicsmagick e " +"converter.backends.python." #: conf/settings.py:16 msgid "Path to the unoconv program." -msgstr "" +msgstr "Path per il programma unoconv" #: conf/settings.py:17 msgid "" "Use alternate method of connection to LibreOffice using a pipe, it is slower" " but less prone to segmentation faults." msgstr "" +"Utilizzare il metodo alternativo di collegamento a LibreOffice utilizzando " +"questo collegamento, è più lento ma meno soggetto a errori di segmentazione." #: templates/converter_file_formats_help.html:3 msgid "Help" -msgstr "" +msgstr "Aiuto" #: templates/converter_file_formats_help.html:4 #, python-format @@ -930,5 +943,7 @@ msgid "" "These are the file formats supported by the currently selected converter " "backend. In this case: '%(backend)s'" msgstr "" +"Questi sono il formati file supportati dal backend selezionato.In questo " +"caso : '%(backend)s'" diff --git a/apps/django_gpg/locale/it/LC_MESSAGES/django.mo b/apps/django_gpg/locale/it/LC_MESSAGES/django.mo index 78fac47634810def560210d12c106f6b5c48b059..44d5c883f59b04faf8c86605f5765374212d4deb 100644 GIT binary patch literal 4723 zcma);O^h5z6@Uu}I4pl5A^ao|%EU?5@y^d~g5!+6PS(3?X+##A-E{~TOSLn#v&Hsw zH(fn5UUNW10_73`2csxLkp)5o$wGiYLI??jl|v*VazI=nIT9BRC=v%wNRjwnb@$A8 zy_RTA_1D#1_3FJ>uil#*ci(YEaV^n4OFQyjrM?E|?%>At{r4;NGW-EN2IoGY)JNfS z@O`icXW%aU5FEmz@Oiilufa#*zf0bKsQ7*s%6ci}r(Wd7(&`Enc`udx3A~T~FCZe+ z>*f15;RE#Ff}e-~g$wY$JC%AIu0d2*&qJB_0=x@;ujExI`v0o@{@e2XA4 zA@~lw8{YH5LcfPg&O>q4Dfkh%1n-CE;9)d4g8&LFn3$ldzN6CLd zS?@n({}4|382!5-rYa3(-YgV78)g4A{4o7hDEqMv#qNtx<|QRZQ2hTb$WQ%(@~1 z{}a^kpHSl9P9{sdJ_u!hmm#0jvry*upvX(1=q5zdyj@vfeBd|Ib6QXAMdmY(QD>IVf_vkT3{qHlUn|CQU9G ze=`1ce|;#*=s;^vby@sC^*Ut#YIt9R{QOF!hF(z?AJ2Ikq`)Mum9!B*rtGEV0^CfCmE)MU9%wsrNfk!Ega5SAL3 zF^Y%sh0GecDAHTDT(GN+*CQK6_1mlF`f0)nGTC*5cIu4jYVUfn$+4rZRyLN@%GiLZ zN6&L^Iy-i1xE`cYV!HBb(CJw3w+B(QhmfQ*=-W7$B(fQ>HOO_GOxujPW@ubwwj!&y zlS~h7=C)nOypcD1 zbNsp3y<5EfjPoIAcE@W-m=PD>7~oNci*pC@Zk&wbph#VP+4Sw4wzWR~p9|s8UJ*Ya zLT|gcXEWlA{XPXcCHgi8@7|#Ty0eGh2g>C z$qSohB75>;+eLP&>vICrGii3@x;>j8^*rYG5)V_O^1amFEV%e;i?^FL>#I%Iw@B-! zVc>;0#2p6SawgP;5Y-24y!fG*eY+7}Ju6YXr@Pe=koXU0i%-su!Uib362e?}Iozs9 z7@!C=)pcH!>#8n07GiKLMA`n9?Q-Ijy_C9aN=WGQzA#70PWDY~dR7jiifr7=chpq& z@M@BOypm7}+ga^iX8j<_y~^w`*+uMF12RyO+AJsF$L<(^^h$O@mBFTp^e{;;>U@@b z-FEU?yIaFgo`c@fYi7^HdUa)OV`kk-daAAYp6k}m40^t{nY8pyo~NxwqsQqVY}GqS zzmX;0WG=}XeVN;E-VdywIe%`mwp=>4wt{0@dZ9T#Uz=a3HIM7&LaTYa)_lC#WMFOG z4xKE&f83LL{)yIO3&)yVGtU^G*ETZ~`^e<7^XDB0!z59n&zPu-)~C|yO?@l8dAcV@ zN|Zd!^td-*18SSr^jo@}led^NTiP=kjq14wciZ+-J+?W?K6uAB(!#Ks?e={mXLiHo zjiWPb?X}g3-{$MhndKzT+1}b_h<`a2jWjYYKB+r9Ci6C5ys&w;c49J4*4wsOZ8h#B zT@HFnpV)HwSk;!Mb3PhmCaRrHvOWhdPD9r(E}YcGN>5F$s zn!2honzA$+GQA8QFI84ZqY07gSI6t*=0IhO({huph>R5i=#pB_v+f%ab|I?X)?SOJYPYmgJBo zvD+d|YR;jItP1BXa!ZL}b@5>67xhyNDpS;WWlbFpHnYsuAc=1pBgahnE%Z@24r0lc=$i6OlF^V2B15TaGuU}QgASs*6VR%(XCebxF zwbT2&T}+X@Jy$0CTX#fisF6S`@?Y?55bi=KdZ*LG`-FcmltrmoJz|DBnoQMENx78K zut+8c6L};pPJJQHW;n@84kQhe>&akJO+&z|b|qH3s8WKuz$O=JObwWFOc4R&F-6Jk zQF8I`iaslw8S2%lRM~Kl!WI&z2o~{WOsI`eW~W~C$l2gP0&XED}m_S!@Xf z{t{g_`wDKGKS$mdaeMnyri{tbSOD>Pprj>`2C0F8$w#;rv70Fvm{}Q^ rPtN5QS1QUcPAtmIFH*26%1=ryD#_P_is+^1=T#-, 2011. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "POT-Creation-Date: 2011-12-06 02:06-0400\n" -"PO-Revision-Date: 2011-12-06 06:07+0000\n" -"Last-Translator: rosarior \n" +"PO-Revision-Date: 2011-12-09 17:32+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,167 +20,169 @@ msgstr "" #: __init__.py:14 msgid "Verify document signatures" -msgstr "" +msgstr "Verifica la firma del documento" #: __init__.py:15 msgid "View keys" -msgstr "" +msgstr "Vista delle chiavi" #: __init__.py:16 msgid "Delete keys" -msgstr "" +msgstr "Cancella chiavi" #: __init__.py:17 msgid "Query keyservers" -msgstr "" +msgstr "Interroga l'autorità per le chiavi" #: __init__.py:18 msgid "Import key from keyservers" -msgstr "" +msgstr "Importa chiave dall'autorità" #: __init__.py:19 msgid "Upload detached signatures" -msgstr "" +msgstr "Carica firme separatamente" #: __init__.py:20 msgid "Download detached signatures" -msgstr "" +msgstr "Scarica firme separatamente" #: __init__.py:23 msgid "Signatures" -msgstr "" +msgstr "Firma" #: __init__.py:39 views.py:67 msgid "private keys" -msgstr "" +msgstr "Chiave privata" #: __init__.py:40 views.py:70 msgid "public keys" -msgstr "" +msgstr "Chiave pubblica" #: __init__.py:41 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:42 msgid "query keyservers" -msgstr "" +msgstr "Interroga il server delle chiavi" #: __init__.py:43 msgid "import" -msgstr "" +msgstr "import" #: __init__.py:44 msgid "upload signature" -msgstr "" +msgstr "aggiorna firma" #: __init__.py:45 msgid "download signature" -msgstr "" +msgstr "scarica firma" #: __init__.py:46 msgid "key management" -msgstr "" +msgstr "gestione della firma" #: __init__.py:49 msgid "signatures" -msgstr "" +msgstr "firma" #: api.py:22 msgid "Public" -msgstr "" +msgstr "Pubblica" #: api.py:23 msgid "Secret" -msgstr "" +msgstr "Segreta" #: api.py:31 api.py:36 msgid "RSA" -msgstr "" +msgstr "RSA" #: api.py:32 msgid "DSA" -msgstr "" +msgstr "DSA" #: api.py:37 msgid "Elgamal" -msgstr "" +msgstr "Elgamal" #: api.py:51 msgid "Bad signature." -msgstr "" +msgstr "Firma cattiva." #: api.py:55 msgid "Document not signed or invalid signature." -msgstr "" +msgstr "Documento non firmato o firma invalida." #: api.py:59 msgid "Signature error." -msgstr "" +msgstr "Errore di firma" #: api.py:63 msgid "Document is signed but no public key is available for verification." msgstr "" +"Il documento è stato firmato, ma la chiave pubblica non è disponibile per la" +" verifica" #: api.py:67 msgid "Document is signed, and signature is good." -msgstr "" +msgstr "Documento firmato e firma è buona." #: api.py:71 msgid "Document is signed with a valid signature." -msgstr "" +msgstr "Il documento è firmato con una firma valida." #: api.py:144 msgid "unknown" -msgstr "" +msgstr "sconosciuto" #: forms.py:11 msgid "Term" -msgstr "" +msgstr "Scadenza" #: forms.py:12 msgid "Name, e-mail, key ID or key fingerprint to look for." -msgstr "" +msgstr "Nome, e-mail,key ID , impronte digitali per cercare" #: forms.py:18 msgid "Signature file" -msgstr "" +msgstr "File della firma" #: views.py:45 #, python-format msgid "Key: %s, imported successfully." -msgstr "" +msgstr "Chiave: %s, importata con successo." #: views.py:48 #, python-format msgid "Unable to import key id: %s" -msgstr "" +msgstr "Impossibile importare la chiave id: %s" #: views.py:52 msgid "Import key" -msgstr "" +msgstr "Importa chiave" #: views.py:53 #, python-format msgid "Are you sure you wish to import key id: %s?" -msgstr "" +msgstr "Sei sicuro di voler importare la chiave id: %s?" #: views.py:78 msgid "Key ID" -msgstr "" +msgstr "chiave ID" #: views.py:82 msgid "Owner" -msgstr "" +msgstr "Proprietario" #: views.py:102 #, python-format msgid "Key: %s, deleted successfully." -msgstr "" +msgstr "chiave: %s, cancellata con successo." #: views.py:109 msgid "Delete key" -msgstr "" +msgstr "Cancella chiave" #: views.py:111 #, python-format @@ -188,105 +191,108 @@ msgid "" "that is part of a public/private pair the private key will be deleted as " "well." msgstr "" +"Sei sicuro di voler cancellare la chiave: %s? Se provi a cancellare una " +"chiave pubblica che è parte di una coppia publica/privata anche la chiave " +"privata sarà cancellata" #: views.py:129 msgid "Query key server" -msgstr "" +msgstr "Interroga il server delle chiavi" #: views.py:142 msgid "results" -msgstr "" +msgstr "risultati" #: views.py:147 msgid "ID" -msgstr "" +msgstr "ID" #: views.py:151 msgid "type" -msgstr "" +msgstr "tipo" #: views.py:155 msgid "creation date" -msgstr "" +msgstr "data di crezione" #: views.py:159 msgid "disabled" -msgstr "" +msgstr "disabilitata" #: views.py:163 msgid "expiration date" -msgstr "" +msgstr "data scadenza" #: views.py:167 msgid "expired" -msgstr "" +msgstr "scaduta" #: views.py:171 msgid "length" -msgstr "" +msgstr "lunghezza" #: views.py:175 msgid "revoked" -msgstr "" +msgstr "revocata" #: views.py:180 msgid "Identifies" -msgstr "" +msgstr "Identifica" #: views.py:205 #, python-format msgid "Signature status: %(widget)s %(text)s" -msgstr "" +msgstr "Status della firma: %(widget)s %(text)s" #: views.py:212 msgid "embedded" -msgstr "" +msgstr "incorporato" #: views.py:214 msgid "detached" -msgstr "" +msgstr "distaccato" #: views.py:219 #, python-format msgid "Signature ID: %s" -msgstr "" +msgstr "ID Firma: %s" #: views.py:220 #, python-format msgid "Signature type: %s" -msgstr "" +msgstr "Tipo di firma: %s" #: views.py:221 #, python-format msgid "Key ID: %s" -msgstr "" +msgstr "Chiave ID: %s" #: views.py:222 #, python-format msgid "Timestamp: %s" -msgstr "" +msgstr "Timestamp: %s" #: views.py:223 #, python-format msgid "Signee: %s" -msgstr "" +msgstr "Signee: %s" #: views.py:228 #, python-format msgid "signature properties for: %s" -msgstr "" +msgstr "Proprietà per la firma: %s" #: views.py:250 msgid "Detached signature uploaded successfully." -msgstr "" +msgstr "Firma scaduta aggiornata con successo." #: views.py:259 #, python-format msgid "Upload detached signature for: %s" -msgstr "" +msgstr "Aggiornata firma scaduta per: %s" #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." -msgstr "" +msgstr "Lista di server per chiavi che si possono interrogare." diff --git a/apps/document_comments/locale/it/LC_MESSAGES/django.mo b/apps/document_comments/locale/it/LC_MESSAGES/django.mo index 518cede71b9f64f7abe8c8b9155d58f69a1bc339..f30ca8e21693b68036674450b3ad9a5439726b70 100644 GIT binary patch literal 1791 zcmb7^&u<$=6vqcBKWcuJzzqt6MNpz@yta#)uqA{vaYYaoR_pcvTqe8Y^`P~PnVF57 z-Z}S##6Q4|e*mdBZg2o3u5bqlaYdZ?zWre*NR{Zwv!9(G@4fH5o#)@y&V9+yUP6Bb z{XY6d^iLnb1MMg9W$XO> zctBpcM!8)>zkq(aAqC4uIiN-{C|{HdNG@ZLKhi>tG~>vuMFX_+=#=N@Xh3Z*O?hHx zGi3q~mZvr;=so7^p6xlsPi(<`QNJv-pO(8+u7cuWsv29`zxyx-zOvY_L$}v`o2RAQ z6!DToc|R%g{G`L0Eiz5j1J*p-cS=H$QHw^AX9tza`gEQRQXN*S1Lv%(LTZyW^Sr&j zQ5$UfHZ*Q1+PCT1u<(J;ojum6;xh1DNlaL?OhJd;)~CZmZ{wBKE*tvgOPS{s(phzQ zR(R#u$l1?S62xIDZY$@tH8CH`6KVM1V0g22L(Q!VV(2rSifcvY#n{Gt8p1q|qD+Tr zanwP?$XPF)wl12HZKS;~ly8kb8jCVra4QZFI_CXuuP5;9_j#`u_pgZVTiq@;iW}-! zQ}{Fc`l9`;c@=hUjjxOC)jopQ%+*YG%W?EWts-Pq_eC1-KfQFBd% z(zT(|L*?0J)j?;eeYJdcU6+-|O<|8$+Sq8j~iU+ur$RF}(`NTS-VOV9hOfBlr7q~=s@16=*9Rr`BanJtyqMMmAPYgvVS(6=B I(EU;DUn^MZKmY&$ delta 110 zcmey*`<2<^o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlT(@JaT{3b8XG7W qm{=JbPv&D0mv9U9@lo(|^mSFRarJfd^l@->aS3t_4xSvy@)Q6v#1cdR diff --git a/apps/document_comments/locale/it/LC_MESSAGES/django.po b/apps/document_comments/locale/it/LC_MESSAGES/django.po index 5de0b4f4f6..3787bcec8d 100644 --- a/apps/document_comments/locale/it/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:33+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 17:37+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,84 +20,84 @@ msgstr "" #: __init__.py:15 msgid "Create new comments" -msgstr "" +msgstr "Crea nuovo commento" #: __init__.py:16 msgid "Delete comments" -msgstr "" +msgstr "Cancella commenti" #: __init__.py:17 msgid "Edit comments" -msgstr "" +msgstr "Modifica commenti" #: __init__.py:18 msgid "View comments" -msgstr "" +msgstr "Visualizza commenti" #: __init__.py:20 msgid "Comments" -msgstr "" +msgstr "Commenti" #: __init__.py:26 __init__.py:27 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:28 msgid "add comment" -msgstr "" +msgstr "aggiungi commento" #: __init__.py:29 utils.py:14 msgid "comments" -msgstr "" +msgstr "commenti" #: __init__.py:33 msgid "date" -msgstr "" +msgstr "data" #: __init__.py:37 msgid "user" -msgstr "" +msgstr "utente" #: __init__.py:41 msgid "comment" -msgstr "" +msgstr "commento" #: views.py:27 msgid "Must provide at least one comment." -msgstr "" +msgstr "Devi almeno fornire un commento" #: views.py:37 #, python-format msgid "Comment \"%s\" deleted successfully." -msgstr "" +msgstr "Commento \"%s\" cancellato con sucesso." #: views.py:39 #, python-format msgid "Error deleting comment \"%(comment)s\": %(error)s" -msgstr "" +msgstr "Erroro nel cancellare il commento \"%(comment)s\": %(error)s" #: views.py:54 #, python-format msgid "Are you sure you wish to delete the comment: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare questo commento: %s?" #: views.py:56 #, python-format msgid "Are you sure you wish to delete the comments: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare questi commenti: %s?" #: views.py:86 msgid "Comment added successfully." -msgstr "" +msgstr "Commento aggiunto con successo." #: views.py:93 #, python-format msgid "Add comment to document: %s" -msgstr "" +msgstr "Aggiungi un comento al documento: %s" #: views.py:109 #, python-format msgid "comments: %s" -msgstr "" +msgstr "commenti: %s" diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.mo b/apps/document_indexing/locale/it/LC_MESSAGES/django.mo index d0eb804bd170782f648845e1ba0dc2ee18f6e7c7..d7c013bab800dc10ec6cb977e3c21738d76f085e 100644 GIT binary patch literal 4162 zcmb7`O^h5z6~`-(5LiM834!pDPzgBRjXgWNt6;(yV>|XbS;5Mdy*5ITkZO8rXDaFG zYIRkwcYPrj#K#GcI3R&UBo0X20EuuxARj;iDJLYv0g)5eAORN+@O#zWGy7o)r!+nP z?w)$D-uu6=`Rl{?eowJZaDALB-lNoM@Q?4{i}m_DmFj`N0zVA?9UOrF1y{kry-Ixn z%)uAI*TG}pJ@+;HkAwH~d=@+hz5u=({08_G_?`CsFTlrm{ug*0eDGaLy#$^DKMj5t z6dQlv;y*#zr&0bW_#*fL@GIblz!H>mz79SFejAj1uYvCYe+kOI--3M9pZR(}_%{#} z)LY<#;J?8I@II7rs~!SH?lDl#>w}Mg=RuLX4vO4Mpy+!Ugc5bD{r#)p8*uzJ@EO^U za`F3BP`414&)dJ3a5PSrD8e9a0 z*URnmm)qx8!H0SOEl}+JA&3g~V-VBS&)fIE0YAd?@7mwr1m)bfK;iFxf+&1H07@P{ z0m}PRpy)jfLTieZ#97|SLOkV(#O@PZnoAb+rFD#Nv9DX=ldKb5VxKJWS2z?uC1=IY zk8;V9nxPcZTH;%561xvC$qlhve31AFx0tM+ zrOsDY@A+DXy1lvS!bC@}D?6-RKGG)7wJSz;*M_s|{El(C8Rk}R*F_ecFTy|{3+kfH zZL~p~Vx+Um8oA%D{8WdmGBKMZEpcM?$Y=G`7O_*gtk#QYD{XYS7bm{ZAy%#!Yr9)k zHUth3TZUHK9h2AS9U)OwzCytvWg=FWBlhf*#=6D1uBC7~J!iHQ+m}MCD~XBxLGw<& z4MiJ5(TudrPfKBB1g}|!BinVJ?=7o?yR0~p_)G6?Xnu#gapmiBW=+6ZSTH(P*6Q57 zV)ew?%2e6JWhNKS>MRn#_5eIln`YNdYXVSjZ@XQ+cq}aG%-1kac(RG`c)8HIsm27w zL^CvjbK}GX?MrkEKYD8RbTk|n{M72`gcU_2WYWbRsEPRxV7^R#WNrYuzY2suSUm|1TIru96|mH%EkM zip;i;IpJzy)1V|3bmvb{U0-TdsLK1Oq&Zl1 zrSdP6UA>J_?}n|Uc?|TX*)xS+zqomA;i@ft6?>au>_)xk>v8C9`GKCqSPuIAv5S*> zxJ=>pD<4edeAOrYP0@ED)HW}VSL5$V2*{iTJ?jm`BrZ>!5I3m2Ls>uv3ocpL35N^+ujT4xhe1sl&?-@4R$ZoW^> z+qPA2y~zA1#rnCSi!)OPnujZSU75Uh$yZZmM^UE7aAxhaZf?&k7W&CEdUa_*U9(OH zm(`WmBd2$KZYy26%uBzckLdh3N#HW8&#FsxaSOs78$$^WUG7q*U69Pob0fdfOJ?%T zGiqZUqtoNuk;f=QLp!28-8k6F1>V(#(Kd7=$#%nvMwv}+|3sHQ1lhoLt0fmB9km@) zRu^)9>V)l~Ja?9(0XO!kmc}$MfmuU4IItR>$IW<5no70Gc%TX8w$nRvLci@3uC@#x zHP-Cx*aF|An!CZ~n-SW1*@fqba0J9e7S>dsclEx(xhx$rMj5TL*|m%L3rqbALD~0n4OlMVc8|FM2K@gamUAH*PBVaO>P`wQ#giU+Y(7X;7vudI-iS%rrgAm3qry)e-Q@rWsw-c2 zNI?2m5|FaS3t_4xU`V`4j*wLlTAn diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.po b/apps/document_indexing/locale/it/LC_MESSAGES/django.po index 063bc16e02..acac9a45c9 100644 --- a/apps/document_indexing/locale/it/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:42+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-10 07:01+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,70 +20,74 @@ msgstr "" #: __init__.py:12 msgid "View document indexes" -msgstr "" +msgstr "Visualizza indici documento" #: __init__.py:13 msgid "Rebuild document indexes" -msgstr "" +msgstr "Ricostruisci indici documento" #: __init__.py:15 msgid "Indexing" -msgstr "" +msgstr "Indicizzazione" #: __init__.py:19 msgid "index list" -msgstr "" +msgstr "lista indici" #: __init__.py:20 msgid "go up one level" -msgstr "" +msgstr "sali di un livello" #: __init__.py:21 __init__.py:23 models.py:26 msgid "indexes" -msgstr "" +msgstr "indici" #: __init__.py:25 msgid "rebuild indexes" -msgstr "" +msgstr "ricostruisci gli indici" #: __init__.py:25 msgid "Deletes and creates from scratch all the document indexes." -msgstr "" +msgstr "Cancellazione e ricostruzione di tutti gli indici documento" #: __init__.py:27 msgid "Indexes" -msgstr "" +msgstr "Indici" #: api.py:83 msgid "root" -msgstr "" +msgstr "root" #: api.py:139 #, python-format msgid "Maximum suffix (%s) count reached." -msgstr "" +msgstr "Massimo dei suffissi contati (%s) ." #: api.py:175 #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" msgstr "" +"Errore nella creazione dell'indice per l'espressione: %(expression)s; " +"%(exception)s" #: api.py:178 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" msgstr "" +"Errore nell'aggiornamento delle'indice documento per l'espressione: " +"%(expression)s; %(exception)s" #: api.py:209 #, python-format msgid "Unable to delete document indexing node; %s" -msgstr "" +msgstr "Impossibile cancellare l'indice del documento; %s" #: filesystem.py:34 #, python-format msgid "Unable to create indexing directory; %s" -msgstr "" +msgstr "Impossibile creare la directory per gli indici; %s" #: filesystem.py:52 #, python-format @@ -90,116 +95,122 @@ msgid "" "Unable to create symbolic link, file exists and could not be deleted: " "%(filepath)s; %(exc)s" msgstr "" +"Impossibile creare un link simbolico, il file già esiste e non può essere " +"cancellato: %(filepath)s; %(exc)s" #: filesystem.py:54 #, python-format msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" -msgstr "" +msgstr "Impossibile creare un link simbolico: %(filepath)s; %(exc)s" #: filesystem.py:71 #, python-format msgid "Unable to delete document symbolic link; %s" -msgstr "" +msgstr "Impossibile cancellare il link simbolico al documento; %s" #: filesystem.py:83 #, python-format msgid "Unable to delete indexing directory; %s" -msgstr "" +msgstr "Impossibile cancellare la directory degli indici; %s" #: models.py:11 #, python-format msgid "Available functions: %s" -msgstr "" +msgstr "Funzioni disponibili: %s" #: models.py:16 msgid "indexing expression" -msgstr "" +msgstr "Espressione per indice" #: models.py:16 msgid "Enter a python string expression to be evaluated." -msgstr "" +msgstr "Inserisci una espressione python perchè possa essere valutata." #: models.py:18 msgid "enabled" -msgstr "" +msgstr "abilitato" #: models.py:19 msgid "link documents" -msgstr "" +msgstr "link al documento" #: models.py:25 models.py:31 views.py:56 msgid "index" -msgstr "" +msgstr "indice" #: models.py:32 msgid "value" -msgstr "" +msgstr "valore" #: models.py:33 msgid "documents" -msgstr "" +msgstr "documenti" #: models.py:46 models.py:51 msgid "index instance" -msgstr "" +msgstr "istanza indice" #: models.py:47 msgid "indexes instances" -msgstr "" +msgstr "istanze indici" #: models.py:52 msgid "document" -msgstr "" +msgstr "document" #: models.py:59 msgid "document rename count" -msgstr "" +msgstr "conteggio della rinomina del documento" #: models.py:60 msgid "documents rename count" -msgstr "" +msgstr "conteggio delle rinomine dei documenti" #: utils.py:19 msgid "document indexes" -msgstr "" +msgstr "indici dei documenti" #: views.py:38 #, python-format msgid "contents for index: %s" -msgstr "" +msgstr "contenuto per indice: %s" #: views.py:60 msgid "items" -msgstr "" +msgstr "voci" #: views.py:82 msgid "Are you sure you wish to rebuild all indexes?" -msgstr "" +msgstr "Sei sicuro di voler ricostruire l'indice ?" #: views.py:83 msgid "On large databases this operation may take some time to execute." msgstr "" +"Per un database di grosse dimensioni l'operazione protrebbe aver bisogno di " +"tempo." #: views.py:89 msgid "Index rebuild completed successfully." -msgstr "" +msgstr "Ricostruzione dell'indice avvenuta con successo" #: views.py:94 #, python-format msgid "Index rebuild error: %s" -msgstr "" +msgstr "Errore nella ricostruzione dell'indice: %s" #: views.py:109 #, python-format msgid "indexes containing: %s" -msgstr "" +msgstr "Gli indici contengono: %s" #: templates/indexing_help.html:3 msgid "What are indexes?" -msgstr "" +msgstr "Cosa sono gli indici ?" #: templates/indexing_help.html:4 msgid "Indexes group documents into a tree like hierarchical structure." msgstr "" +"Gli Indici dei documenti rappresentano , nella forma di albero, la struttura" +" gerarchica dei documenti stessi.." diff --git a/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo index d0eb804bd170782f648845e1ba0dc2ee18f6e7c7..85cbc415e440be5601d59a996af9523e87cdfca2 100644 GIT binary patch literal 2118 zcmZ{kO>Z1E7{?71+HQI43!owd4^jgOW%doI%7hf!G=WGg4aow>$UEcg8fNUl_GGiU zae)gQIKW5Xf`r78Pmv23B*aJHGw^?AW;aSptvJ86$Iq+%JpWue^OL}M0rMryKQUjy z{QeRA!#MY-5ZA!-;1q0wXTV>;F8C{W1N<9&0=)c~5YK`yf=`3j!6(5Odpcsyo+}Nng2(XvW$+E`{|n_gcojly z=R5E=_yf2K9yj|JVB`wc7eUU&Yv3jD7Rd2@3bKDA5F(-gIld{#{(cLx+|M9^zk%n$ zV{ice1+x9u&((fMAp0GItnYo0Q~n$#>tS1bo(J2xh>6fETO2nJmP6XB0rACvsmf>G zcpj7O@ZfkZW416kRvs5H*-x>N$-=9Yg3eV;OUul?RAoV~c=9T-CiP;&1m!496s5{* zhvQyJmrUp@HJe(O^2tIv8SrH^BVWiwwTbSTY*tAHTR?R!v*(mAv*7nKo$CN2&6=h< z%V?xX9!Q? z{khE7rE*$TVov3%`dZ*b>6L4X-72I8q@1%33Gwrd#?AQ>3CX>X>47xKA|E0}3OIw5 zIK|lz?51G5GvQRC7XF`JDS!W(mh&cTxWAOH;Cq#|Ip3sZKe1D7#$-9m$S#(qN$y_4 zsX}gT894r>_L?`)FumnuJiqoz7T?NjYjKHt#s=rPJ1Ra+d9A?@Q%d+xLdiI;RI} zqr1pbO#N=J7vZnpr(Q4a--x;;~bBSoxBBcGcM&=MMEX?n6`qAVVSpA9#on`hL;XColEa^&PR!_ zKk%(WKPnZKqcNj6^9a<8>zG7 z+V4h4QQaCe*8gv>R*v@D9DJ}l%mq(WphM)=BrCl>kU0nZuvURs9&8iUy@>jD Q(C8482)eMMta2y*1NH4tbpQYW delta 128 zcmX>m@Rix(o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlVw@vSs7UB8XG7W zm{^$@X&V3mmrr7GiEc, 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-09-30 04:42+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 15:32+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,78 +20,80 @@ msgstr "" #: __init__.py:5 msgid "search" -msgstr "" +msgstr "cerca" #: __init__.py:6 views.py:72 msgid "advanced search" -msgstr "" +msgstr "ricerca avanzata" #: __init__.py:7 msgid "search again" -msgstr "" +msgstr "cerca ancora" #: forms.py:8 msgid "Search terms" -msgstr "" +msgstr "Termini di ricerca" #: models.py:20 msgid "user" -msgstr "" +msgstr "utente" #: models.py:21 msgid "query" -msgstr "" +msgstr "interrogazione" #: models.py:22 msgid "datetime created" -msgstr "" +msgstr "orario creato" #: models.py:23 msgid "hits" -msgstr "" +msgstr "visite" #: models.py:61 msgid "recent search" -msgstr "" +msgstr "ricerce recenti" #: models.py:62 msgid "recent searches" -msgstr "" +msgstr "risultati della ricerca" #: views.py:33 #, python-format msgid "results, (showing only %(shown_result_count)s out of %(result_count)s)" msgstr "" +"risultati, (mostra esclusivamente %(shown_result_count)s di " +"%(result_count)s)" #: views.py:37 msgid "results" -msgstr "" +msgstr "risultati" #: views.py:56 #, python-format msgid "Search error: %s" -msgstr "" +msgstr "Errore di ricerca:%s" #: views.py:60 msgid "type" -msgstr "" +msgstr "tipo" #: views.py:76 views.py:86 views.py:88 templatetags/search_tags.py:19 #: templatetags/search_tags.py:20 msgid "Search" -msgstr "" +msgstr "Cerca" #: conf/settings.py:12 msgid "Maximum amount search hits to fetch and display." -msgstr "" +msgstr "Ricerca importo massimo di visitatori per questa visualizzazione." #: conf/settings.py:13 msgid "Maximum number of search queries to remember per user." -msgstr "" +msgstr "Numero massimo di query di ricerca da ricordare per utente." #: templates/search_help.html:3 msgid "Help" -msgstr "" +msgstr "Aiuto" #: templates/search_help.html:4 #, python-format @@ -98,19 +101,21 @@ msgid "" "Enter the desired search keywords separated by space. Only the top " "%(search_results_limit)s results will be available." msgstr "" +"Inserisci le parole da cercare separate da spazzi. Solo i primi " +"%(search_results_limit)s saranno disponibili." #: templates/search_results.html:3 msgid "Search results" -msgstr "" +msgstr "Risultati della ricerca" #: templates/search_results.html:19 #, python-format msgid "Elapsed time: %(time_delta)s seconds" -msgstr "" +msgstr "Tempo trascorso: %(time_delta)s in secondi" #: templatetags/search_tags.py:33 #, python-format msgid "recent searches (maximum of %d)" -msgstr "" +msgstr "ricerche recenti (maximum of %d)" diff --git a/apps/folders/locale/it/LC_MESSAGES/django.mo b/apps/folders/locale/it/LC_MESSAGES/django.mo index 72cbfdd28e96e44641807cba5841648db40f9397..6b70cfac007cbe73553babe3a78b2f685e612a53 100644 GIT binary patch literal 4333 zcmbW4ON<;x8OIC9kYsr#KnR3DdBMpp_RQ=q1e-C&@na1}Y;59nc-(5IYiA4fbPZiK zyIu=UNZb(Ozy%4x2_X)-fe05Qasi15E=UB#LmW832?-$~@%nw;)jd5<90;ZD`FC}H z@A@9SzrFwHR~737*W0<`E0j6|{`3extnc5Y)VsiEzz4zKfS&~a27Vg6dQ_{Vd_TK=P zz~{h!gTDmt6TDlghrvIAuLtkB2U*~QAdl1|py=&`u&8q&f9f(n_kvf!w}77laY20+ z6gm5#(0?)QzXXb$uY<1!p9V$#55Nb&AAw@e^Wgp9pFvzx{{ltsQI!3R7~cy@T%N}n z4gLeX0X~dS!2n8Je*%64{5v=VFTAEcpU;Djuzv;=Ill)*-(5I;4155T^E?e|@CJAa z+y{m4Y49ZY3-B@U$m^8iPo3sxfPEhZB_0O^LFm5>ihth&VNuV45|>|t;_n|oTvUGr zC7%CGcsIckJMIJJeII-?cq;9;K(YI&gbsWY`_HBKUjZdAzLws97Zf{w42u5WCHy0Z z*_Dn*LGeYFz&*j<9Z{P_|&W;+(^#Ik~5b47T+cQ>b&0dd1gyp zn2F7X`gl00O;|0iAS9;tv>WK9cJm~z=b`bDDA}W zTOIdo%ZTWeM#yT=yQQC0@00rF<16*uYFIw^vIK{&IGgy}oVLDG zAZioj5E99v1%0(O3sFx?zwa`uP1LzHJn)50p0%l$NW;{Q-0mUiTiAn!hIp8w&UEn~ z?!J1WeXX|lY-r>KJ%ZHa!RsCJ+J;f-c5u)HJquJ&?NR7!4Hs&t38N3pp=1fErCpIZ zY@M0BqDNd6Sg8V6YJX6)25VoAP2p~t=zO6kHtzXMkY79+wb|XZBcOnr$K`_csBX=m^gppjV8xT<+&M+!w*Arc^ zMvY{s^whkhU}^(FrQTLGu%s}$m|G>spstnvGeoy{CF?z9%fR^!^_Dp#aW*e)U0-_A zPJJ1BTVd?7-i6sX^tSy_@5MMB4hCZv_hvi&k)I4oA57_dIhY9Vz=bfgVd>h{?cPO6 z8pQT45yYY1SX*E3@wc&|*Vl&|@9(X>Z*2|2-jjCUiTVY)jo#V^^!lmcWA8n&##;Iq z71P@;O%ZYvr4Lyx} z-eq4-m>$Kn+J>_mXLNmgcBRnA&g%8mC3Pj&g_lehnv3vHL+6MB6c5!|@ zcC%va+8kj*LfNvY>(=SuMzhlE%;|lfQ*))8%oveWmdodiNbe5GY(Wmy)^<&1IRNCH1e8H79)#SnpN9OIU&wjf;s6vcykE3hDqFRbSslaZ!XJeu7t7>vuJt3ub9aI@DeJ-+^ zp%?26u_-T#=u~=S>ONU@KbSg#=M*pbvQZoFz}j`0Vr5 z@S+B+o)vSy=Q);$WyG~q1qt4v^%ZNUawu%|!~%`_I9-l!FhoePSv~b3c(ijYj5fZh zq+keOVC0wdKknzXiEYvflU z>1671*phc?7~e8g;xYK=mG1gF#S&BMX`UI;Tw9{$GoeE*c3|Qx^33Sm(+~=>p>%Z7 zl5XpDoJG9C^ELz+VDgATl}N1V2K^#qLRS&$vM{9Umc+5qTY;69W}B)CakC19YKlcQv(dMAZhptdR#&)WoNDq}ZKZl@wN_?6k>o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlQ}r&aT{3b8XG7W qm{^&bPTt5VF5wpHEqz&;u7Q<96b38=TiVWt`kE5 diff --git a/apps/folders/locale/it/LC_MESSAGES/django.po b/apps/folders/locale/it/LC_MESSAGES/django.po index 6fccff809c..3138265a01 100644 --- a/apps/folders/locale/it/LC_MESSAGES/django.po +++ b/apps/folders/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:55+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 17:53+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,165 +20,166 @@ msgstr "" #: __init__.py:10 msgid "folder list" -msgstr "" +msgstr "lista delle cartelle" #: __init__.py:11 views.py:53 msgid "create folder" -msgstr "" +msgstr "crea cartella" #: __init__.py:12 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:13 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:14 msgid "remove from folder" -msgstr "" +msgstr "rimuovi dalla cartella" #: __init__.py:15 msgid "folder documents" -msgstr "" +msgstr "cartella documenti" #: __init__.py:16 msgid "add to a folder" -msgstr "" +msgstr "aggiungi alla cartella" #: __init__.py:17 __init__.py:25 models.py:31 views.py:21 msgid "folders" -msgstr "" +msgstr "cartelle" #: forms.py:20 msgid "Existing folders" -msgstr "" +msgstr "Cartelle esistenti" #: forms.py:22 msgid "New folder" -msgstr "" +msgstr "Nuova cartella" #: models.py:11 msgid "title" -msgstr "" +msgstr "titolo" #: models.py:12 msgid "user" -msgstr "" +msgstr "utente" #: models.py:13 msgid "datetime created" -msgstr "" +msgstr "data di creazione" #: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 msgid "folder" -msgstr "" +msgstr "cartella" #: models.py:36 msgid "document" -msgstr "" +msgstr "documento" #: models.py:42 views.py:257 msgid "folder document" -msgstr "" +msgstr "cartella documento" #: models.py:43 msgid "folders documents" -msgstr "" +msgstr "cartelle documento" #: views.py:24 msgid "created" -msgstr "" +msgstr "creata" #: views.py:25 msgid "documents" -msgstr "" +msgstr "documenti" #: views.py:45 views.py:152 msgid "Folder created successfully" -msgstr "" +msgstr "Cartella creata con successo" #: views.py:48 views.py:154 views.py:188 #, python-format msgid "A folder named: %s, already exists." -msgstr "" +msgstr "Il nome cartella: %s, già esiste." #: views.py:71 msgid "Folder edited successfully" -msgstr "" +msgstr "Cartella modificata con successo" #: views.py:74 #, python-format msgid "Error editing folder; %s" -msgstr "" +msgstr "Errore modificando la cartella; %s" #: views.py:79 #, python-format msgid "edit folder: %s" -msgstr "" +msgstr "Modifica cartella: %s" #: views.py:101 #, python-format msgid "Folder: %s deleted successfully." -msgstr "" +msgstr "Cartella : %s cancellata con successo." #: views.py:103 #, python-format msgid "Folder: %(folder)s delete error: %(error)s" -msgstr "" +msgstr "Cartella: %(folder)s errore di cancellazione: %(error)s" #: views.py:114 #, python-format msgid "Are you sure you with to delete the folder: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare la cartella: %s?" #: views.py:131 #, python-format msgid "documents in folder: %s" -msgstr "" +msgstr "documenti nella cartella: %s" #: views.py:157 views.py:191 msgid "Must specify a new folder or an existing one." -msgstr "" +msgstr "Devi indicare una nuova cartella o una già esistente" #: views.py:162 views.py:196 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." msgstr "" +"Documento: %(document)s aggiunto alla cartella: %(folder)s successfully." #: views.py:165 views.py:199 #, python-format msgid "Document: %(document)s is already in folder: %(folder)s." -msgstr "" +msgstr "Documento: %(document)s è già nella cartella: %(folder)s." #: views.py:186 #, python-format msgid "Folder \"%s\" created successfully" -msgstr "" +msgstr "Cartella \"%s\" creata con successo" #: views.py:207 #, python-format msgid "add document \"%s\" to a folder" -msgstr "" +msgstr "aggiungo il dcumento\"%s\" alla cartella" #: views.py:223 #, python-format msgid "folders containing: %s" -msgstr "" +msgstr "le cartelle contengono: %s" #: views.py:239 msgid "Must provide at least one folder document." -msgstr "" +msgstr "Devi almeno indicare una cartella documenti." #: views.py:249 #, python-format msgid "Document: %s removed successfully." -msgstr "" +msgstr "Documento: %s cancellato con successo." #: views.py:251 #, python-format msgid "Document: %(document)s delete error: %(error)s" -msgstr "" +msgstr "Documento: %(document)s errore di cancellazione: %(error)s" #: views.py:265 #, python-format @@ -185,6 +187,8 @@ msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " "\"%(folder)s\"?" msgstr "" +"Sei sicuro di voler rimuovere il documento: %(document)s dalla cartella " +"\"%(folder)s\"?" #: views.py:268 #, python-format @@ -192,10 +196,12 @@ msgid "" "Are you sure you wish to remove the documents: %(documents)s from the folder" " \"%(folder)s\"?" msgstr "" +"Sei sicuro di voler rimuovere i documenti: %(documents)s dalla cartella " +"\"%(folder)s\"?" #: templates/folders_help.html:3 msgid "What are folders?" -msgstr "" +msgstr "Cosa sono le cartelle ?" #: templates/folders_help.html:4 msgid "" @@ -204,9 +210,14 @@ msgid "" "created by one user and the documents contained by them don't affect any " "other user folders or documents." msgstr "" +"Queste cartelle possono anche essere considerate come cartelle utente. Sono " +"un modo per consentire agli utenti singoli per creare i propri metodi di " +"organizzazione dei documenti. Cartelle create da un utente e dei documenti " +"contenuti da loro non riguardano tutte le cartelle di altri utenti o " +"documenti." #: templatetags/folder_tags.py:17 msgid "Add document to a folder" -msgstr "" +msgstr "Aggiungi documento alla cartella" diff --git a/apps/history/locale/it/LC_MESSAGES/django.mo b/apps/history/locale/it/LC_MESSAGES/django.mo index 2ee6d674a1b50e1bb980d92bcbf06dea702c38ce..62c400c776fa49ec09ef36f69d8a563ba38b3953 100644 GIT binary patch literal 1478 zcmY+DOOM<{5XU}8Kz~ZnxlHDj9G1}E;;ND}`dK%eotGj16 zgOE6KYNAhNxcb5+*_dNz1s6*P~z`^FM@Z$iy(s%|1BtS_d&_? z11Nfb1f||Dpv3zIak=6Dg*O79L#+ISC;;LbFyYp1L^DjAz zYGx}|IU>l^ImNZry>;Pq;CxDN2bJ3_T2~vtQe8pIp?^DGSrJR+^>S~nQydFzwfx@* zsy2`!kI;q(^G&L(z)ArW%?qHuA=cAs6!shzMvIu(S zQd-2=q)AfPxLD4InX3}-g7Mb*q>|XghOp!?*xQ}yo1TsAPRseFG#QP@8o$Ye#^ZGI zo*rEtjo_&F`Or%F$NVOG^Z||EPp@sfJHi-zWF93U?(UKSFq2EKR|B#->VXCz{eC=5oKEqobo?l;rk+?+t5?Nz&)f0E>hZ<+qjmR5{$ia=}oC`IbVg8>ZUcr=HxncubY=^y0}T>D}%Oqb4#Wy zFQI8mo0+e0s7wueDwz(uJGRozMs0D7rYNoJ+R349oArC&4p!|J1^k@a^>W41)rOed ziKXy==<}dV+IF;5ZQV2PYTQp@S*?q=y=-ay$*7apRw*=flB}5RpQM%6XJ8R(3Hw~9 Qtli^X-fIp{+8nC?1MZ1&BLDyZ delta 128 zcmX@c{gv6`o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlkYOkvof&MH8xN% zFtIW<(>4GCE}z8W65WuZ#Ju91#FG3XD+RYuA0GujM_*S38&_XPPag+I7ndN{;NZz8 HnV$jx, 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-09-30 04:56+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 17:58+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,88 +20,88 @@ msgstr "" #: __init__.py:6 msgid "Access the history app" -msgstr "" +msgstr "Accedi all'applicazione per le versioni" #: __init__.py:8 msgid "History" -msgstr "" +msgstr "Versioni" #: __init__.py:12 models.py:69 msgid "history" -msgstr "" +msgstr "versioni" #: models.py:16 msgid "namespace" -msgstr "" +msgstr "namespace" #: models.py:17 msgid "name" -msgstr "" +msgstr "nome" #: models.py:25 models.py:34 msgid "history type" -msgstr "" +msgstr "Tipo versione" #: models.py:26 msgid "history types" -msgstr "" +msgstr "Tipi di versioni" #: models.py:30 msgid "date time" -msgstr "" +msgstr "data" #: models.py:35 msgid "dictionary" -msgstr "" +msgstr "dizionario" #: models.py:70 msgid "histories" -msgstr "" +msgstr "cronologie" #: views.py:23 msgid "history events" -msgstr "" +msgstr "eventi cronologia" #: views.py:26 views.py:60 msgid "date and time" -msgstr "" +msgstr "data e orario" #: views.py:30 msgid "object" -msgstr "" +msgstr "oggetto" #: views.py:34 views.py:64 msgid "summary" -msgstr "" +msgstr "sommario" #: views.py:56 #, python-format msgid "history events for: %s" -msgstr "" +msgstr "cronologia per gli eventi per: %s" #: views.py:81 msgid "Date" -msgstr "" +msgstr "Data" #: views.py:82 msgid "Time" -msgstr "" +msgstr "Orario" #: views.py:83 msgid "Object" -msgstr "" +msgstr "Oggetto" #: views.py:84 msgid "Event type" -msgstr "" +msgstr "Tipo evento" #: views.py:85 msgid "Event details" -msgstr "" +msgstr "Dettaglio evento" #: views.py:89 #, python-format msgid "details for: %s" -msgstr "" +msgstr "dettaglio per:%s" diff --git a/apps/linking/locale/it/LC_MESSAGES/django.mo b/apps/linking/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..706288b1b5f67a667815bcd7640c5619850a3e9c 100644 GIT binary patch literal 7140 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 delta 110 zcmaE2{*~F{o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlg;_(aT{3b8XG7W qm{^$@PJX~IF5wpHEqz&;u7Q<96VWB;3)u2q7v%> diff --git a/apps/linking/locale/it/LC_MESSAGES/django.po b/apps/linking/locale/it/LC_MESSAGES/django.po index e5b46e064b..92812d71b3 100644 --- a/apps/linking/locale/it/LC_MESSAGES/django.po +++ b/apps/linking/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-12 08:59+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,143 +20,143 @@ msgstr "" #: __init__.py:11 msgid "View existing smart links" -msgstr "" +msgstr "Vista intelligente dei link esistenti" #: __init__.py:12 msgid "Create new smart links" -msgstr "" +msgstr "Crea link intelligenti" #: __init__.py:13 msgid "Delete smart links" -msgstr "" +msgstr "Cancella link intelligenti" #: __init__.py:14 msgid "Edit smart links" -msgstr "" +msgstr "Modifica link intelligenti" #: __init__.py:16 msgid "Smart links" -msgstr "" +msgstr "Link intelligenti" #: __init__.py:22 msgid "smart links actions" -msgstr "" +msgstr "azioni dei link intelligenti" #: __init__.py:23 __init__.py:25 models.py:21 views.py:105 msgid "smart links" -msgstr "" +msgstr "link intelligenti" #: __init__.py:26 msgid "smart links list" -msgstr "" +msgstr "lista dei link intelligenti" #: __init__.py:27 msgid "create new smart link" -msgstr "" +msgstr "crea nuovi link intelligenti" #: __init__.py:28 __init__.py:33 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:29 __init__.py:34 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:31 msgid "conditions" -msgstr "" +msgstr "condizioni" #: __init__.py:32 msgid "create condition" -msgstr "" +msgstr "crea condizioni" #: forms.py:48 msgid "Pages" -msgstr "" +msgstr "Pagine" #: forms.py:54 msgid "Select" -msgstr "" +msgstr "Seleziona" #: forms.py:61 msgid "Click on the image for full size view of the first page." -msgstr "" +msgstr "Click sull'immagine per vedere la prima pagina" #: literals.py:7 msgid "and" -msgstr "" +msgstr "e" #: literals.py:8 msgid "or" -msgstr "" +msgstr "o" #: literals.py:12 msgid "is equal to" -msgstr "" +msgstr "è uguale" #: literals.py:13 msgid "is equal to (case insensitive)" -msgstr "" +msgstr "è uguale a (case insensitive)" #: literals.py:14 msgid "contains" -msgstr "" +msgstr "contiene" #: literals.py:15 msgid "contains (case insensitive)" -msgstr "" +msgstr "contiene (case insensitive)" #: literals.py:16 msgid "is in" -msgstr "" +msgstr "è in" #: literals.py:17 msgid "is greater than" -msgstr "" +msgstr "è più grande di" #: literals.py:18 msgid "is greater than or equal to" -msgstr "" +msgstr "è più grande o uguale a" #: literals.py:19 msgid "is less than" -msgstr "" +msgstr "è inferiore a " #: literals.py:20 msgid "is less than or equal to" -msgstr "" +msgstr "è inferiore o uguale a" #: literals.py:21 msgid "starts with" -msgstr "" +msgstr "inizia con" #: literals.py:22 msgid "starts with (case insensitive)" -msgstr "" +msgstr "inizia con (case insensitive)" #: literals.py:23 msgid "ends with" -msgstr "" +msgstr "finisce con" #: literals.py:24 msgid "ends with (case insensitive)" -msgstr "" +msgstr "finisce con (case insensitive)" #: literals.py:25 msgid "is in regular expression" -msgstr "" +msgstr "è un'espressione regolare" #: literals.py:26 msgid "is in regular expression (case insensitive)" -msgstr "" +msgstr "è un'espressione regolare (case insensitive)" #: models.py:10 msgid "title" -msgstr "" +msgstr "titolo" #: models.py:11 views.py:108 msgid "dynamic title" -msgstr "" +msgstr "titolo dinamico" #: models.py:11 models.py:29 msgid "" @@ -163,161 +164,170 @@ msgid "" "The document metadata is available as variables `metadata` and document " "properties under the variable `document`." msgstr "" +"Questa espressione sarà valutata per il documento corrente selezionato. I " +"metadati del documento sono disponibile come variabili `metadati` e le " +"proprietà dei documenti sotto la variabile `documento`." #: models.py:12 models.py:31 views.py:109 views.py:196 msgid "enabled" -msgstr "" +msgstr "abilitato" #: models.py:20 models.py:25 views.py:256 views.py:287 msgid "smart link" -msgstr "" +msgstr "link intelligente" #: models.py:26 msgid "The inclusion is ignored for the first item." -msgstr "" +msgstr "L'inserimento viene ignorato per la prima voce." #: models.py:27 msgid "foreign document data" -msgstr "" +msgstr "dati del documento estero" #: models.py:27 msgid "" "This represents the metadata of all other documents. Available objects: " "`document.` and `metadata.`." msgstr "" +"Questo rappresenta i metadati di tutti gli altri documenti. Oggetti " +"disponibili: `document.` e `metadata.`." #: models.py:29 msgid "expression" -msgstr "" +msgstr "espressione" #: models.py:30 msgid "negated" -msgstr "" +msgstr "negato" #: models.py:30 msgid "Inverts the logic of the operator." -msgstr "" +msgstr "Inverti la logica dell'operazione" #: models.py:34 msgid "not" -msgstr "" +msgstr "not" #: models.py:37 msgid "link condition" -msgstr "" +msgstr "condizione per il link" #: models.py:38 msgid "link conditions" -msgstr "" +msgstr "condizioni per i link" #: views.py:32 msgid "No action selected." -msgstr "" +msgstr "Nessuna azione selezionata " #: views.py:47 #, python-format msgid "documents in smart link: %(group)s" -msgstr "" +msgstr "documenti nei link intelligenti: %(group)s" #: views.py:65 #, python-format msgid "Smart link query error: %s" -msgstr "" +msgstr "Interrogazione dei link intelligenti, errore: %s" #: views.py:76 #, python-format msgid "smart links (%s)" -msgstr "" +msgstr "link intelligenti (%s)" #: views.py:90 msgid "There no defined smart links for the current document." -msgstr "" +msgstr "Non ci sono link intelligenti per questo documento." #: views.py:124 #, python-format msgid "Smart link: %s created successfully." -msgstr "" +msgstr "Link inteligente: %s creato con successo." #: views.py:131 msgid "Create new smart link" -msgstr "" +msgstr "Crea un nuovo link intelligente" #: views.py:144 #, python-format msgid "Smart link: %s edited successfully." -msgstr "" +msgstr "Link intelligente: %s modificato con successo." #: views.py:153 #, python-format msgid "Edit smart link: %s" -msgstr "" +msgstr "Modifica il link intelligente: %s" #: views.py:168 #, python-format msgid "Smart link: %s deleted successfully." -msgstr "" +msgstr "Link intelligente: %s cancellato con successo." #: views.py:170 #, python-format msgid "Error deleting smart link: %(smart_link)s; %(error)s." -msgstr "" +msgstr "Errore link intelligente: %(smart_link)s; %(error)s." #: views.py:180 #, python-format msgid "Are you sure you wish to delete smart link: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancella questo link intelligente: %s?" #: views.py:193 #, python-format msgid "conditions for smart link: %s" -msgstr "" +msgstr "condizioni per il link intelligente: %s" #: views.py:216 #, python-format msgid "Smart link condition: \"%s\" created successfully." -msgstr "" +msgstr "Condizione per il link intelligente: \"%s\" creata con successo." #: views.py:223 #, python-format msgid "Add new conditions to smart link: \"%s\"" -msgstr "" +msgstr "Aggiungi una nuova condizione al link intelligente: \"%s\"" #: views.py:243 #, python-format msgid "Smart link condition: \"%s\" edited successfully." -msgstr "" +msgstr "Condizione per il link intelligente: \"%s\" modificato con successo." #: views.py:250 msgid "Edit smart link condition" -msgstr "" +msgstr "Modifica condizioni per i link intelligenti" #: views.py:257 views.py:288 msgid "condition" -msgstr "" +msgstr "condizioni" #: views.py:274 #, python-format msgid "Smart link condition: \"%s\" deleted successfully." -msgstr "" +msgstr "Condizioni per il link intelligente: \"%s\" cancellato con successo." #: views.py:276 #, python-format msgid "" "Error deleting smart link condition: %(smart_link_condition)s; %(error)s." msgstr "" +"Errore nella cancellazione del link intelligente: %(smart_link_condition)s; " +"%(error)s." #: views.py:290 #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "" +"Sei sicuro di voler cancellare le condizioni per il link intelligente : " +"\"%s\"?" #: conf/settings.py:11 msgid "Show smart link that don't return any documents." -msgstr "" +msgstr "Mostra i link intelligenti che non restituiscono documenti" #: templates/smart_links_help.html:3 msgid "What are smart links?" -msgstr "" +msgstr "Che cosa sono i link intelligenti ?" #: templates/smart_links_help.html:4 msgid "" @@ -327,5 +337,11 @@ msgid "" "some manner to the document being displayed and allow users the ability to " "jump to and from linked documents very easily." msgstr "" +"Collegamenti intelligenti sono un insieme di istruzioni condizionali che " +"vengono utilizzati per interrogare il database utilizzando il documento " +"corrente l'utente sta accedendo come origine dati, i risultati di queste " +"query sono un elenco di documenti che riguardano in qualche modo al " +"documento e consentire la visualizzazione agli utenti la possibilità di " +"saltare da e per i documenti collegati molto facilmente." diff --git a/apps/main/locale/it/LC_MESSAGES/django.mo b/apps/main/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..cef91c1286a59d4539e9bfd460fe5c5572acc7d8 100644 GIT binary patch literal 2531 zcma)+OKcoP5QZBF0hSOTyuu@>!b8|N<9!4|*kFVm+fgK2w*1Hip{RGJJ=@Vt_tM>C zXMNzn8Mtxa77j?jDK`*80x4X0NRhZ8B*ck3+(ClBW@ckMywcj4Z@Raux~jVS|M}3q zcLmzxcpk%Z;3gr)!9PH5mu?o~Ht>D$5cpBu{~Vk^|0}Qq{suk)K6#4}cYyQYz2GwV z8rTEx1iu7t1-}FLgWrR1fj@!|fgAgTxEp)}JPN)89t1Cg4e$#PKk*G-2f(W!$M+M+ z|NjE=I=_PWiQnr!FM1F92S8r;NX@4}wwnO2BIgqz``eG#Bj7=h=Z}NWf-SHOz6x@_ zZ-e-W%Xo2pJ_XN%-+~;+#O+nSFM#Z43j7S51rLLNf}HPR6zvE&26BHMWcza<+x6;k z4Z=hW!3V)NL7w*>$oYN%a$P;pZoDtN z2keJ^bDVeK;Wj!qoI5wp30qk<&V$>dc)0ewKF7{+a=X7m87GcUxer|PhwEdqtU_B3!dbut&zanRQI5oyCZdV0*rT#fr~`L(H2$#c%z-USth@$2VS z!{=|<ak)l^_6FvMN6n2CwP0}Q^bb5tiIgmY#ytMLSsZ3n{tu`wvlK~-(YK6WkV=S;@ zRjD(}3v}){E$CPouf(c~tx2RCB0N)w)qqv2?AH;E;1?wbTxVXKQ_dqKA(LFA7CI=A z>?&8^=1Sy}gE!K|d%i30)h-EN)>`q4~X zQ=LRJMe3t9+ogU8gKo2#qQpgSGPZfsSudTou9>rKQ+r=1-&kH+i%vULmNS|~eY(_X zwc8PXoes6z-Oh=q^<1lkiP4JM)STm9QUhiJ`7<56wvy0om7 z8%Ud3nvq$8s9ze4MkagZ$SWxdlW~wQ!`!3=PDiw+WZtE-0jCuQBI6$^RU4)YiJ9CQS zzI0xNsr9w_=;Y2kUT;IWXwJko!4d4z$(|0^LhTYd%UR)M7R_6iLk`TK?E0zBDXKoF z#ta>uqV{;>n#io^v~Y>V)q5Q~5$s56aw(>_QD$91(E!Knf2F3hsHfhT(y&G4{J)e& z=e7=q672^Fi!Yj}g(ib;D8d`!!v0uWu3W-Qa=1e-mUQJqmP(_8q(o9-M*1?68(R%a z+O)A^L%wRerAGdP)U586np&fCS>}&uQq;4|ZlpO90)o5Dkq)f)We#Eimc6&{ruv67S*RKMV64P05kZLy5dx}|YH#rt4y{W_s zRNcoK_ooV)})OUQq)Ri*tE=0@Q$!(?~IgND{xUAG;T+$5WrtGK)u)i delta 110 zcmaDX{FT|_o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlTBIYaT{3b8XG7W qm{^$@PQJ$~F5wpHEqz&;u7Q<96VW(?I{2{8WN%a diff --git a/apps/main/locale/it/LC_MESSAGES/django.po b/apps/main/locale/it/LC_MESSAGES/django.po index 5fbd304397..dc3c3c9cf5 100644 --- a/apps/main/locale/it/LC_MESSAGES/django.po +++ b/apps/main/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 15:03+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,125 +20,130 @@ msgstr "" #: __init__.py:15 msgid "maintenance" -msgstr "" +msgstr "manutenzione" #: __init__.py:16 msgid "statistics" -msgstr "" +msgstr "statistiche" #: __init__.py:17 msgid "diagnostics" -msgstr "" +msgstr "disgnostica" #: __init__.py:18 msgid "sentry" -msgstr "" +msgstr "guardia" #: __init__.py:19 msgid "admin site" -msgstr "" +msgstr "sito d'amministrazione" #: __init__.py:30 msgid "home" -msgstr "" +msgstr "home" #: __init__.py:32 msgid "search" -msgstr "" +msgstr "cerca" #: views.py:41 msgid "maintenance menu" -msgstr "" +msgstr "menu manutenzione" #: views.py:53 msgid "Statistics" -msgstr "" +msgstr "Statistiche" #: views.py:61 msgid "Diagnostics" -msgstr "" +msgstr "Diagnostica" #: conf/settings.py:12 msgid "" "Controls whether the search functionality is provided by a sidebar widget or" " by a menu entry." msgstr "" +"Controlla se la funzionalità di ricerca è fornita da un widget sidebar o da " +"una voce di menu." #: templates/about.html:5 msgid "About this program" -msgstr "" +msgstr "Rigurdo a questo programma" #: templates/about.html:9 templates/verbose_login.html:4 msgid "Version" -msgstr "" +msgstr "Versione" #: templates/base.html:28 msgid "(DEBUG)" -msgstr "" +msgstr "(DEBUG)" #: templates/base.html:183 msgid "User" -msgstr "" +msgstr "Utente" #: templates/base.html:185 msgid "Anonymous" -msgstr "" +msgstr "Anonimo" #: templates/base.html:188 msgid "User details" -msgstr "" +msgstr "Dettagli utente" #: templates/base.html:205 msgid "Login" -msgstr "" +msgstr "Login" #: templates/base.html:205 msgid "Logout" -msgstr "" +msgstr "Logout" #: templates/base.html:285 msgid "Secondary menu" -msgstr "" +msgstr "Menu secondario" #: templates/base.html:302 #, python-format msgid "Actions for %(name)s: %(navigation_object)s" -msgstr "" +msgstr "Azione per %(name)s: %(navigation_object)s" #: templates/base.html:304 templates/base.html.py:336 #, python-format msgid "Actions for: %(navigation_object)s" -msgstr "" +msgstr "Azione per : %(navigation_object)s" #: templates/base.html:307 msgid "Available actions" -msgstr "" +msgstr "Azioni disponibili" #: templates/base.html:319 templates/base.html.py:351 msgid "Related actions" -msgstr "" +msgstr "Azioni relative" #: templates/base.html:334 #, python-format msgid "Actions for %(object_name)s: %(navigation_object)s" -msgstr "" +msgstr "Azioni per %(object_name)s: %(navigation_object)s" #: templates/base.html:339 msgid "Actions" -msgstr "" +msgstr "Azioni" #: templates/base.html:364 msgid "Other available actions" -msgstr "" +msgstr "Altre azioni disponibili" #: templates/project_description.html:6 msgid "" "Open source, Django based electronic document manager with custom metadata, " "indexing, tagging, file serving integration and OCR capabilities" msgstr "" +"Open Source, Django programma per la gestione documentale con la possibilità" +" di metadati personalizabili, tagging, indicizzazione, integrazione con file" +" server e con possibilità di OCR" #: templates/project_description.html:15 msgid "Released under the GPL V3 License" -msgstr "" +msgstr "Rilasciato con licenza GPL V3" diff --git a/apps/metadata/locale/it/LC_MESSAGES/django.mo b/apps/metadata/locale/it/LC_MESSAGES/django.mo index 2ee6d674a1b50e1bb980d92bcbf06dea702c38ce..828e1eaeac01877cc1a7a0cd295a4da88b8608ed 100644 GIT binary patch literal 9782 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 delta 128 zcmdny^Of1+o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlZ`~@Ss7UB8XG7W zm{^&bX&V3mmrr7GiEc, 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-09-30 04:56+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-13 09:10+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,171 +20,171 @@ msgstr "" #: __init__.py:12 msgid "Edit a document's metadata" -msgstr "" +msgstr "Modifica i metadata dei documenti" #: __init__.py:13 msgid "Add metadata to a document" -msgstr "" +msgstr "Aggiungi il metadato al documento" #: __init__.py:14 msgid "Remove metadata from a document" -msgstr "" +msgstr "Revoca il metadato al documento" #: __init__.py:15 msgid "View metadata from a document" -msgstr "" +msgstr "Visualizza il metadato per il documento" #: __init__.py:17 msgid "Edit metadata types" -msgstr "" +msgstr "Modifica il tipo di metadato" #: __init__.py:18 msgid "Create new metadata types" -msgstr "" +msgstr "Crea il nuovo tipo di metadato" #: __init__.py:19 msgid "Delete metadata types" -msgstr "" +msgstr "Cancella il tipo di metadato" #: __init__.py:20 msgid "View metadata types" -msgstr "" +msgstr "Visualizza il tipo di metadato" #: __init__.py:22 msgid "Edit metadata sets" -msgstr "" +msgstr "Modifica il set di metadati" #: __init__.py:23 msgid "Create new metadata sets" -msgstr "" +msgstr "Crea un nuovo set di metadati" #: __init__.py:24 msgid "Delete metadata sets" -msgstr "" +msgstr "Cancella il set dei metadati" #: __init__.py:25 msgid "View metadata sets" -msgstr "" +msgstr "Visualizza il set dei metadati" #: __init__.py:27 forms.py:94 msgid "Metadata" -msgstr "" +msgstr "Metadati" #: __init__.py:33 msgid "Metadata setup" -msgstr "" +msgstr "Setup metadati" #: __init__.py:44 __init__.py:46 msgid "edit metadata" -msgstr "" +msgstr "modifica metadati" #: __init__.py:45 msgid "metadata" -msgstr "" +msgstr "metadati" #: __init__.py:47 __init__.py:48 msgid "add metadata" -msgstr "" +msgstr "aggiungi metadata" #: __init__.py:49 __init__.py:50 msgid "remove metadata" -msgstr "" +msgstr "revoca metadata" #: __init__.py:52 models.py:33 views.py:294 msgid "metadata types" -msgstr "" +msgstr "tipo di metadata" #: __init__.py:53 __init__.py:58 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:54 __init__.py:59 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:55 __init__.py:60 msgid "create new" -msgstr "" +msgstr "crea nuovo" #: __init__.py:57 views.py:394 msgid "metadata sets" -msgstr "" +msgstr "set di metadati" #: __init__.py:62 models.py:92 msgid "default metadata" -msgstr "" +msgstr "metadati di default" #: classes.py:12 #, python-format msgid "'metadata' object has no attribute '%s'" -msgstr "" +msgstr "'metadata' non ha gli attributi '%s'" #: forms.py:28 msgid "required" -msgstr "" +msgstr "richiesto" #: forms.py:54 msgid "id" -msgstr "" +msgstr "id" #: forms.py:55 msgid "Name" -msgstr "" +msgstr "Nome" #: forms.py:57 msgid "Value" -msgstr "" +msgstr "Valore" #: forms.py:58 msgid "Update" -msgstr "" +msgstr "Aggiurnato" #: forms.py:64 msgid "Metadata type" -msgstr "" +msgstr "Tipo di metadato" #: forms.py:68 msgid "Remove" -msgstr "" +msgstr "Revoca" #: forms.py:86 msgid "Metadata sets" -msgstr "" +msgstr "Set di metadati" #: models.py:9 #, python-format msgid " Available models: %s" -msgstr "" +msgstr " Modelli disponibili: %s" #: models.py:10 #, python-format msgid " Available functions: %s" -msgstr "" +msgstr " Funzioni disponibili: %s" #: models.py:17 msgid "name" -msgstr "" +msgstr "nome" #: models.py:17 msgid "Do not use python reserved words, or spaces." -msgstr "" +msgstr "Non usare parole riservate python, o spazi." #: models.py:18 models.py:40 msgid "title" -msgstr "" +msgstr "titolo" #: models.py:20 msgid "default" -msgstr "" +msgstr "default" #: models.py:21 #, python-format msgid "Enter a string to be evaluated.%s" -msgstr "" +msgstr "Inserisci una stringa per la valutazione.%s" #: models.py:23 msgid "lookup" -msgstr "" +msgstr "lookup" #: models.py:24 #, python-format @@ -191,96 +192,99 @@ 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:32 models.py:57 views.py:331 views.py:376 msgid "metadata type" -msgstr "" +msgstr "tipo di metadata" #: models.py:47 models.py:48 models.py:56 views.py:446 views.py:491 msgid "metadata set" -msgstr "" +msgstr "set di metadata" #: models.py:64 msgid "metadata set item" -msgstr "" +msgstr "set di elemento per il metadata" #: models.py:65 msgid "metadata set items" -msgstr "" +msgstr "set di elementi per il metadata" #: models.py:73 msgid "document" -msgstr "" +msgstr "documento" #: models.py:74 msgid "type" -msgstr "" +msgstr "tipo" #: models.py:75 views.py:283 msgid "value" -msgstr "" +msgstr "valore" #: models.py:81 models.py:82 msgid "document metadata" -msgstr "" +msgstr "metadata per il doccumento" #: models.py:90 views.py:559 msgid "document type" -msgstr "" +msgstr "tipo documento" #: models.py:91 msgid "default metadata sets" -msgstr "" +msgstr "set di default di metadata" #: models.py:98 msgid "document type defaults" -msgstr "" +msgstr "tipo documento predefinito" #: models.py:99 msgid "document types defaults" -msgstr "" +msgstr "tipi di documento predefiniti" #: views.py:38 views.py:193 msgid "The selected document doesn't have any metadata." -msgstr "" +msgstr "Il documento selezionato non ha metadati." #: views.py:43 views.py:131 views.py:199 msgid "Must provide at least one document." -msgstr "" +msgstr "Devi fornire almeno un documento." #: views.py:78 views.py:234 #, python-format msgid "Error deleting document indexes; %s" -msgstr "" +msgstr "Errore nella cancellazione degli indici di documento;%s" #: views.py:90 #, 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:93 #, python-format msgid "Metadata for document %s edited successfully." -msgstr "" +msgstr "Metadata per il documento %s modificato con successo." #: views.py:98 views.py:251 #, python-format msgid "Error updating document indexes; %s" -msgstr "" +msgstr "Errore nella'ggiornamento degli indici del documento; %s" #: views.py:100 views.py:253 msgid "Document indexes updated successfully." -msgstr "" +msgstr "Indici documento aggiornati con successo." #: views.py:111 #, python-format msgid "Edit metadata for document: %s" -msgstr "" +msgstr "Modifica metadata per il documento: %s" #: views.py:113 #, python-format msgid "Edit metadata for documents: %s" -msgstr "" +msgstr "Modifica metadata per i documenti: %s" #: views.py:148 #, python-format @@ -288,22 +292,25 @@ 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:151 #, 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:175 #, python-format msgid "Add metadata type to document: %s" -msgstr "" +msgstr "Aggiungi tipo metadata al document: %s" #: views.py:177 #, python-format msgid "Add metadata type to documents: %s" -msgstr "" +msgstr "Aggiungi tipo metadata ai documents: %s" #: views.py:242 #, python-format @@ -311,119 +318,123 @@ 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:245 #, 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:264 #, python-format msgid "Remove metadata types from document: %s" -msgstr "" +msgstr "Rimuovi il tipo metadata per il documento: %s" #: views.py:266 #, python-format msgid "Remove metadata types from documents: %s" -msgstr "" +msgstr "Rimuovi il tipo metadata per il documenti: %s" #: views.py:281 #, python-format msgid "metadata for: %s" -msgstr "" +msgstr "metadata per:%s" #: views.py:298 msgid "internal name" -msgstr "" +msgstr "nome interno" #: views.py:319 msgid "Metadata type edited successfully" -msgstr "" +msgstr "Tipo di metadata modificato con successo" #: views.py:322 #, python-format msgid "Error editing metadata type; %s" -msgstr "" +msgstr "Errore nella modifica del tipo di metadata ; %s" #: views.py:328 #, python-format msgid "edit metadata type: %s" -msgstr "" +msgstr "modifica tipo di metadata: %s" #: views.py:343 msgid "Metadata type created successfully" -msgstr "" +msgstr "Tipo metadata creato con successo" #: views.py:349 msgid "create metadata type" -msgstr "" +msgstr "create tipo di metadata" #: views.py:368 #, python-format msgid "Metadata type: %s deleted successfully." -msgstr "" +msgstr "Tipo metadata:%s cancellato con successo." #: views.py:370 #, python-format msgid "Metadata type: %(metadata_type)s delete error: %(error)s" -msgstr "" +msgstr "Tipo metadata: %(metadata_type)s erroce di cancellazione: %(error)s" #: views.py:381 #, python-format msgid "Are you sure you wish to delete the metadata type: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare il tipo di metadata: %s?" #: views.py:398 msgid "members" -msgstr "" +msgstr "membri" #: views.py:442 #, python-format msgid "non members of metadata set: %s" -msgstr "" +msgstr "non membri del set di metadata:%s" #: views.py:443 #, python-format msgid "members of metadata set: %s" -msgstr "" +msgstr "membri del set di metadata:%s" #: views.py:458 msgid "Metadata set created successfully" -msgstr "" +msgstr "Set di metadata creata con successo" #: views.py:464 msgid "create metadata set" -msgstr "" +msgstr "creazione del set di metadata" #: views.py:483 #, python-format msgid "Metadata set: %s deleted successfully." -msgstr "" +msgstr "Set di metadata: %s cancellata con successo." #: views.py:485 #, python-format msgid "Metadata set: %(metadata_set)s delete error: %(error)s" -msgstr "" +msgstr "Set di metadata: %(metadata_set)s errore di cancellazione: %(error)s" #: views.py:496 #, python-format msgid "Are you sure you wish to delete the metadata set: %s?" -msgstr "" +msgstr "Sei sicuro di voler eliminare il set di metadati: %s?" #: views.py:554 #, python-format msgid "non members of document type: %s" -msgstr "" +msgstr "non membri del tipo di documento: %s" #: views.py:555 #, python-format msgid "members of document type: %s" -msgstr "" +msgstr "membri del tipo di documento: %s" #: templates/metadata_set_help.html:3 msgid "What are metadata sets?" -msgstr "" +msgstr "Cosa sono i set di metadati ?" #: templates/metadata_set_help.html:4 msgid "" @@ -431,10 +442,14 @@ msgid "" "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 "" +msgstr "Cosa sono i tipi di metadati?" #: templates/metadata_type_help.html:4 msgid "" @@ -448,5 +463,15 @@ msgid "" "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/navigation/locale/it/LC_MESSAGES/django.mo b/apps/navigation/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..e67720c602dad5c509c2c9a35b6b9578ad7753f9 100644 GIT binary patch delta 291 zcmey$yo$B{o)F7a1|VPoVi_Q|0b*7ljsap2C;(zXAT9)AF(7URVvyQdKzyE&fnh$7 zmH^^>CW!tHAPtgV3Z#M3V89F{L1I851_s~KoRUn1%#zexg~a3%`ON%0hTznk)Z~)X z6u2l*u-J+rGdVwRqQyLJLnB=SO9ev~)3Q~&{603j)XDZ}^Tu_jc3bq#{l&X-EiXjQI GodE!8>qnLV delta 127 zcmZ3*`jy$@o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OG6X(sdGO*M&Hc&7y zu`)5#HUI)HpTy!4-H@WhyyBe1lKdho1-DQi9|b>0UsnYiS6@d@9|uPlmmt^R;K^N# FPXW1)807!} diff --git a/apps/navigation/locale/it/LC_MESSAGES/django.po b/apps/navigation/locale/it/LC_MESSAGES/django.po index 086ca792fb..764528c927 100644 --- a/apps/navigation/locale/it/LC_MESSAGES/django.po +++ b/apps/navigation/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,14 +20,14 @@ msgstr "" #: forms.py:14 msgid "Multi item action" -msgstr "" +msgstr "Voce per azioni multiple" #: widgets.py:28 msgid "icon" -msgstr "" +msgstr "icon" #: templatetags/navigation_tags.py:275 msgid "Selected item actions:" -msgstr "" +msgstr "Selezione le azioni multiple" diff --git a/apps/ocr/locale/it/LC_MESSAGES/django.mo b/apps/ocr/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..2719e242b38c46364bc5a9b796189881a86bc98f 100644 GIT binary patch literal 9009 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 V=Wv3bsFY>yM9-6Fdpz80@Gn1+KJfqm delta 110 zcmdn!_LbS(brYM#?{x+)5pQl#U;o!IC%17k*5G%x)c-u diff --git a/apps/ocr/locale/it/LC_MESSAGES/django.po b/apps/ocr/locale/it/LC_MESSAGES/django.po index dd3f06215a..799dd966d3 100644 --- a/apps/ocr/locale/it/LC_MESSAGES/django.po +++ b/apps/ocr/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 16:09+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,416 +20,426 @@ msgstr "" #: __init__.py:28 msgid "Submit document for OCR" -msgstr "" +msgstr "Sottoporre documenti per l'OCR" #: __init__.py:29 msgid "Delete document for OCR queue" -msgstr "" +msgstr "Cancellare i documenti dalla coda per OCR" #: __init__.py:30 msgid "Can enable/disable an OCR queue" -msgstr "" +msgstr "Posso attivare/disattivare una coda per OCR" #: __init__.py:31 msgid "Can execute an OCR clean up on all document pages" -msgstr "" +msgstr "Può eseguire un OCR ripulendo tutte le pagine del documento" #: __init__.py:32 msgid "Can edit an OCR queue properties" -msgstr "" +msgstr "Posso modificare le proprità della coda di OCR" #: __init__.py:34 __init__.py:56 __init__.py:74 msgid "OCR" -msgstr "" +msgstr "OCR" #: __init__.py:40 msgid "OCR Setup" -msgstr "" +msgstr "Configurazione OCR" #: __init__.py:44 msgid "submit to OCR queue" -msgstr "" +msgstr "Sottoponi una coda di OCR" #: __init__.py:45 __init__.py:46 msgid "re-queue" -msgstr "" +msgstr "riaccoda" #: __init__.py:47 __init__.py:48 __init__.py:63 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:50 msgid "stop queue" -msgstr "" +msgstr "stoppa la coda" #: __init__.py:51 msgid "activate queue" -msgstr "" +msgstr "attiva la coda" #: __init__.py:53 msgid "clean up pages content" -msgstr "" +msgstr "ripulisci il contenuto delle pagine" #: __init__.py:53 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:55 msgid "queue document list" -msgstr "" +msgstr "lista dei documenti in coda" #: __init__.py:58 views.py:316 msgid "active tasks" -msgstr "" +msgstr "attiva i tasks" #: __init__.py:60 msgid "transformations" -msgstr "" +msgstr "transformazioni" #: __init__.py:61 msgid "add transformation" -msgstr "" +msgstr "aggiungi trasformazione" #: __init__.py:62 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:82 msgid "Default" -msgstr "" +msgstr "Default" #: __init__.py:104 msgid "Checks the OCR queue for pending documents." -msgstr "" +msgstr "Controlla i documenti nella coda dell'OCR" #: api.py:119 msgid "Text from OCR" -msgstr "" +msgstr "testo dall'OCR" #: literals.py:8 msgid "stopped" -msgstr "" +msgstr "fermato" #: literals.py:9 msgid "active" -msgstr "" +msgstr "attivo" #: literals.py:18 msgid "pending" -msgstr "" +msgstr "in esecuzione" #: literals.py:19 msgid "processing" -msgstr "" +msgstr "in elaborazione" #: literals.py:20 msgid "error" -msgstr "" +msgstr "errore" #: models.py:22 msgid "name" -msgstr "" +msgstr "nome" #: models.py:23 msgid "label" -msgstr "" +msgstr "etichetta" #: models.py:27 models.py:47 msgid "state" -msgstr "" +msgstr "stato" #: models.py:32 models.py:40 views.py:44 views.py:337 views.py:378 #: views.py:408 views.py:444 msgid "document queue" -msgstr "" +msgstr "coda del documento" #: models.py:33 msgid "document queues" -msgstr "" +msgstr "code di documenti" #: models.py:41 msgid "document" -msgstr "" +msgstr "documento" #: models.py:42 msgid "date time submitted" -msgstr "" +msgstr "orario di esecuzione" #: models.py:43 msgid "delay ocr" -msgstr "" +msgstr "proroga ocr" #: models.py:48 msgid "result" -msgstr "" +msgstr "risultato" #: models.py:49 msgid "node name" -msgstr "" +msgstr "nome del nodo" #: models.py:53 msgid "queue document" -msgstr "" +msgstr "coda del documento" #: models.py:54 msgid "queue documents" -msgstr "" +msgstr "code dei documenti" #: models.py:63 views.py:48 msgid "Missing document." -msgstr "" +msgstr "Documento perso" #: models.py:67 msgid "Enter a valid value." -msgstr "" +msgstr "Inserisci un valore valido" #: models.py:95 views.py:341 msgid "order" -msgstr "" +msgstr "ordina" #: models.py:96 views.py:342 views.py:379 views.py:409 msgid "transformation" -msgstr "" +msgstr "trasforma" #: models.py:97 views.py:343 msgid "arguments" -msgstr "" +msgstr "argomenti" #: models.py:97 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" -msgstr "" +msgstr "Usa un dizionario per identificare gli argomenti, esempio: %s" #: models.py:107 msgid "document queue transformation" -msgstr "" +msgstr "coda del documento in trasformazione" #: models.py:108 msgid "document queue transformations" -msgstr "" +msgstr "code dei documenti in trasformazione" #: statistics.py:8 #, python-format msgid "Document queues: %d" -msgstr "" +msgstr "Coda documento:%d" #: statistics.py:9 #, python-format msgid "Queued documents: %d" -msgstr "" +msgstr "Code di documenti:%d" #: statistics.py:13 msgid "OCR statistics" -msgstr "" +msgstr "Statistiche OCR" #: views.py:41 #, python-format msgid "documents in queue: %s" -msgstr "" +msgstr "documenti in coda: %s" #: views.py:49 msgid "thumbnail" -msgstr "" +msgstr "thumbnail" #: views.py:62 msgid "document queue properties" -msgstr "" +msgstr "proprietà della coda documenti" #: views.py:63 #, python-format msgid "Current state: %s" -msgstr "" +msgstr "Stato corrente: %s" #: views.py:79 views.py:154 msgid "Must provide at least one queue document." -msgstr "" +msgstr "Deve fornire almeno un documento di coda." #: views.py:89 #, python-format msgid "Document: %s is being processed and can't be deleted." -msgstr "" +msgstr "Il document: %s è in elaborazione e non può essere cancellato." #: views.py:92 #, python-format msgid "Queue document: %(document)s deleted successfully." -msgstr "" +msgstr "Coda documento: %(document)s cancellata con successo." #: views.py:96 #, python-format msgid "Error deleting document: %(document)s; %(error)s" -msgstr "" +msgstr "Errore nella cancellazione del documento: %(document)s; %(error)s" #: views.py:109 #, python-format msgid "Are you sure you wish to delete queue document: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare questa coda documento: %s?" #: views.py:111 #, python-format msgid "Are you sure you wish to delete queue documents: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare queste code documento: %s?" #: views.py:134 #, 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:137 #, python-format msgid "Document: %(document)s is already queued." -msgstr "" +msgstr "Il documento: %(document)s è gia stato elaborato." #: views.py:165 #, python-format msgid "Document: %s is already being processed and can't be re-queded." -msgstr "" +msgstr "Il documento: %s è gia stato processato non può essere riprocessato." #: views.py:173 #, python-format msgid "Document: %(document)s was re-queued to the OCR queue: %(queue)s" -msgstr "" +msgstr "Il documento: %(document)s è stato riprocessato %(queue)s per OCR." #: views.py:176 #, python-format msgid "Document id#: %d, no longer exists." -msgstr "" +msgstr "il documento id#: %d,non esiste più." #: views.py:189 #, python-format msgid "Are you sure you wish to re-queue document: %s?" -msgstr "" +msgstr "Sei sicuro di volere riprocessare il documento: %s?" #: views.py:191 #, python-format msgid "Are you sure you wish to re-queue documents: %s?" -msgstr "" +msgstr "Sei sicuro di volere riprocessare questi documenti: %s?" #: views.py:209 #, python-format msgid "Document queue: %s, already stopped." -msgstr "" +msgstr "Questa coda: %s, è stata appena fermata." #: views.py:215 #, python-format msgid "Document queue: %s, stopped successfully." -msgstr "" +msgstr "Questa coda: %s,è stata fermata con successo." #: views.py:221 #, python-format msgid "Are you sure you wish to disable document queue: %s" -msgstr "" +msgstr "Sei sicuro di voler fermare la coda per il documento: %s" #: views.py:236 #, python-format msgid "Document queue: %s, already active." -msgstr "" +msgstr "La coda per questo documento: %s, è già attiva." #: views.py:242 #, python-format msgid "Document queue: %s, activated successfully." -msgstr "" +msgstr "Coda documento: %s, attivata con successo." #: views.py:248 #, python-format msgid "Are you sure you wish to activate document queue: %s" -msgstr "" +msgstr "Sei sicuro di voler attivare questa coda documento: %s" #: views.py:265 msgid "Are you sure you wish to clean up all the pages content?" -msgstr "" +msgstr "Sei sicuro di voler ripulire tutto il contenuto delle pagine?" #: views.py:266 msgid "On large databases this operation may take some time to execute." -msgstr "" +msgstr "Nei database grandi questa operazione può richiedere del tempo." #: views.py:272 msgid "Document pages content clean up complete." -msgstr "" +msgstr "Pulizia del contenuto delle pagine completata." #: views.py:274 #, python-format msgid "Document pages content clean up error: %s" -msgstr "" +msgstr "Errore nella pulizia del contenuto delle pagine: %s" #: views.py:320 msgid "node" -msgstr "" +msgstr "nodo" #: views.py:321 msgid "task id" -msgstr "" +msgstr "task id" #: views.py:322 msgid "task name" -msgstr "" +msgstr "nome task" #: views.py:323 msgid "related object" -msgstr "" +msgstr "oggetto correlato" #: views.py:335 #, python-format msgid "transformations for: %s" -msgstr "" +msgstr "trasformazione per: %s" #: views.py:365 msgid "Queue transformation edited successfully" -msgstr "" +msgstr "Modifica della coda di trasformazione effettuata con successo" #: views.py:368 #, python-format msgid "Error editing queue transformation; %s" -msgstr "" +msgstr "Errore nella modifica alla coda di trasformazione; %s" #: views.py:373 #, python-format msgid "Edit transformation: %s" -msgstr "" +msgstr "Modifica trasformazioni:%s" #: views.py:396 msgid "Queue transformation deleted successfully." -msgstr "" +msgstr "Coda di trasformazione cancellata con successo" #: views.py:398 #, python-format msgid "Error deleting queue transformation; %(error)s" -msgstr "" +msgstr "Errore nella cancellazione della coda di trasformazione; %(error)s" #: views.py:411 #, 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:434 msgid "Queue transformation created successfully" -msgstr "" +msgstr "Coda di trasformazione creata con successo" #: views.py:437 #, python-format msgid "Error creating queue transformation; %s" -msgstr "" +msgstr "Errore creano la coda di trasformazione; %s" #: views.py:446 #, python-format msgid "Create new transformation for queue: %s" -msgstr "" +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 "" @@ -436,13 +447,16 @@ msgid "" " to use for locking. Multiple hosts can be specified separated by a " "semicolon." msgstr "" +"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." #: conf/settings.py:18 msgid "File path to unpaper program." -msgstr "" +msgstr "File path per il programma unpaper" #: parsers/__init__.py:23 msgid "Text extracted from PDF" -msgstr "" +msgstr "Testo estratto da PDF" diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.mo b/apps/permissions/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..f280a0f28ab729d1acb36791f60a61fccd54c0df 100644 GIT binary patch literal 3264 zcmbW2O^g&p6vs;eKSohR{6f%Tb!8^n^RW=J8C(%|7qjTf1{M<3gw%G|^ptjY4PDjy zt)?)rH3-m6!y zukPIXF+-`L?m-Q1W9%^a)$M3dKHb9DHt-_I!Oy{Q@JDb0+`5&qli(D10=x*m4E_P$ z3pTNsI0jb06ClYugXRJ7b?`AT1`mNBfTQ5|;632K;2q!=G&{ixNOJaq_k&ds4;w{; zE!hzeOV|W>A9$kpJ_p{3@AKe;UD8*m1j`lcJ>r1*}_rb7PcFed_jd`ykF>^)rt@D z9mNCrs9(0z3l~Yi*>JTd(^wg!bYg0TTg`{7sl1R$V`W-1m{9t9j*BRjB3R;G5pdg; ze6X4im1Wh;5D!z4SQ*rBmJw)alKmDk=H;ymIm#ntEY}?_7xAK!kf%D5P`N8C7pdeT zvpN=5`67yzxPVPzBB7?{iCjRB57nU$&x}kBJBk%cI^!lQUKW(;(qyN$)2nQdIUk8R z8No%vRjX_y&zr2%QHwQmWMfgOoY!yVHr}eNai?T%8k>-jw6ge^43sTiUn0*k*OpGe zu&Kl;PWXD$1|iG_ue__H zK&ESZOsUJT+y{)dbWO2A`5lumTGBl4Fl;8(Z%W^KQ-OCDCg1|L`LtLP37?#pK3zE_ zdpfn=vG0s#HL}fx}j{NR+*lfo*ekCRc}_tHL^_tC6{`z*2+Z) ziG)fHbH6K6BkkCk+2h{mU>@z)k*PPC_&Pv7Y4g!JWmi;fb9~H1St=s$xK3l!=1I?e znz50?JbxXlCVbx*Z`CRrBvi5bO5L0byMl-6=P$U5T!ctt^x6yR>%^y#HJOw`8WL20 zty*`jfmf7Ob#^AkGHHx4WL9Hjm>{)s5n@r6 zuMoYSOhlem6+0~zH_Fda?L^s(&udJ^IBAc&B)R*m=)SV_rx{$h&GKtWG!&o5bxJwi zJfE`u{}oENBX1F=OXfJ-8odw2HWTGKx#Rm;m_8Dq+& zS(?XHDHE@BZ*sI;teZmDkB8iL{Hox-jg~2wZ+%gKuhsP|a_fqLlzw@V>3Qv3pqXFz zgvEs~SP_NJ2NZOJh-DH#-LAA&xICPy0;C_!Bd6*%Wn{fNBg4Fml5#SKsJVGE#Rl2W w5WG5~qsBjBC3yP13cZ8)XT>7rGBd1qTj%N^>ao7mK}-7`{dG=S9t3&&A0~)+od5s; delta 128 zcmX>g`IXt?o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlO@^bSs7UB8XG7W zm{^$@Y8wCnmrr7GiEc#GZ+;B diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.po b/apps/permissions/locale/it/LC_MESSAGES/django.po index 11a0b7b7f7..1dcf050cc9 100644 --- a/apps/permissions/locale/it/LC_MESSAGES/django.po +++ b/apps/permissions/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-13 08:38+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,176 +20,182 @@ msgstr "" #: __init__.py:12 msgid "View roles" -msgstr "" +msgstr "Vedi i ruoli" #: __init__.py:13 msgid "Edit roles" -msgstr "" +msgstr "Modifica i ruoli" #: __init__.py:14 msgid "Create roles" -msgstr "" +msgstr "Crea ruoli" #: __init__.py:15 msgid "Delete roles" -msgstr "" +msgstr "Cancella i ruoli" #: __init__.py:16 msgid "Grant permissions" -msgstr "" +msgstr "Concedere le autorizzazioni" #: __init__.py:17 msgid "Revoke permissions" -msgstr "" +msgstr "Revoca le autorizzazioni" #: __init__.py:19 models.py:87 views.py:38 msgid "roles" -msgstr "" +msgstr "ruoli" #: __init__.py:20 msgid "create new role" -msgstr "" +msgstr "crea nuovo ruolo" #: __init__.py:21 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:22 msgid "members" -msgstr "" +msgstr "membri" #: __init__.py:23 msgid "role permissions" -msgstr "" +msgstr "permessi dei ruoli" #: __init__.py:24 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:26 msgid "grant" -msgstr "" +msgstr "concessione" #: __init__.py:27 msgid "revoke" -msgstr "" +msgstr "revoca" #: api.py:22 msgid "Permissions" -msgstr "" +msgstr "Permessi" #: api.py:55 msgid "Insufficient permissions." -msgstr "" +msgstr "Permessi insufficienti" #: models.py:11 views.py:58 msgid "namespace" -msgstr "" +msgstr "namespace" #: models.py:12 views.py:59 msgid "name" -msgstr "" +msgstr "nome" #: models.py:13 models.py:82 msgid "label" -msgstr "" +msgstr "etichetta" #: models.py:20 models.py:65 views.py:145 views.py:204 msgid "permission" -msgstr "" +msgstr "permesso" #: models.py:21 views.py:55 views.py:147 views.py:206 msgid "permissions" -msgstr "" +msgstr "permessi" #: models.py:73 msgid "permission holder" -msgstr "" +msgstr "titolare del permesso" #: models.py:74 msgid "permission holders" -msgstr "" +msgstr "titolari dei permessi" #: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115 #: views.py:282 msgid "role" -msgstr "" +msgstr "ruolo" #: models.py:115 msgid "role member" -msgstr "" +msgstr "membro del ruolo" #: models.py:116 msgid "role members" -msgstr "" +msgstr "membri del ruolo" #: views.py:61 msgid "has permission" -msgstr "" +msgstr "ha il permesso" #: views.py:142 views.py:201 msgid " and " -msgstr "" +msgstr " and " #: views.py:142 views.py:201 #, python-format msgid "%(permissions)s to %(requester)s" -msgstr "" +msgstr "%(permissions)s a %(requester)s" #: views.py:152 #, python-format msgid "Permission \"%(permission)s\" granted to: %(requester)s." -msgstr "" +msgstr "Permesso \"%(permission)s\" concesso a: %(requester)s." #: views.py:155 #, python-format msgid "%(requester)s, already had the permission \"%(permission)s\" granted." -msgstr "" +msgstr "%(requester)s, ha già il permesso \"%(permission)s\" concesso." #: views.py:167 #, 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:211 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." -msgstr "" +msgstr "Permesso \"%(permission)s\" revocato per: %(requester)s." #: views.py:214 #, python-format msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." -msgstr "" +msgstr "%(requester)s, non ha i permessi \"%(permission)s\" consentiti." #: views.py:226 #, 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:278 #, python-format msgid "non members of role: %s" -msgstr "" +msgstr "nessun menbro per il ruolo:%s" #: views.py:279 #, python-format msgid "members of role: %s" -msgstr "" +msgstr "membri per il ruolo:%s" #: widgets.py:16 msgid "Revoke" -msgstr "" +msgstr "Revoca" #: widgets.py:21 msgid "Grant" -msgstr "" +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/project_setup/locale/it/LC_MESSAGES/django.mo b/apps/project_setup/locale/it/LC_MESSAGES/django.mo index d0eb804bd170782f648845e1ba0dc2ee18f6e7c7..228f7547c6abd139e708e3d6773bfefa2c316317 100644 GIT binary patch delta 238 zcmey${F0^qo)F7a1|VPtVi_Pd0b*7l_5orLNC09GKM{zzfjAwA&oeSG6a#5aAa-VA zV2}pVzCao%%mAdo0AwB*6sMMy7BGNGh0K!F++v1+qWrAXl< zSeY1U8vp^9PhxS2Zb(sLUU5!hNq&))f?KGMkAk10ud9NMtFNP{kAtI&OOR`D@Z>ng FrvS{>7|Z|w diff --git a/apps/project_setup/locale/it/LC_MESSAGES/django.po b/apps/project_setup/locale/it/LC_MESSAGES/django.po index 966177ce1a..de45fa3044 100644 --- a/apps/project_setup/locale/it/LC_MESSAGES/django.po +++ b/apps/project_setup/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:42+0000\n" -"Last-Translator: FULL NAME \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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,10 +20,10 @@ msgstr "" #: __init__.py:6 msgid "setup" -msgstr "" +msgstr "configura" #: views.py:13 msgid "setup items" -msgstr "" +msgstr "parametri di configurazione" diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.mo b/apps/project_tools/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..bf768aae63544c0f0b27345295ad90cdf757551d 100644 GIT binary patch delta 168 zcmey$ypbjBo)F7a1|VPpVi_RT0b*7lwgF-g2moRbKM;t|GcquQ18GhmRtIVTa>4q5 z6atjw=jRkpw3x?bXryaksbFYfWiau9gib(aYEeOAeonrEQ({g^VxEFc0Zc?M2`u7} co|~ANqnDhYJ6VA7DOYhxQE6^!UP&ec04B>LRsaA1 delta 107 zcmdnU@|D@*o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OG6T{|l8CdEX8z>l< nSeZ=xCn4b$>f@u}=jiLIVB_lR=;`C&=;9LO8XP>?iSa1_2Y3>H diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.po b/apps/project_tools/locale/it/LC_MESSAGES/django.po index 086a78ab58..959bcf5413 100644 --- a/apps/project_tools/locale/it/LC_MESSAGES/django.po +++ b/apps/project_tools/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +20,6 @@ msgstr "" #: __init__.py:7 views.py:13 msgid "tools" -msgstr "" +msgstr "strumenti" diff --git a/apps/smart_settings/locale/it/LC_MESSAGES/django.mo b/apps/smart_settings/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..ec725d4764000c19450336b186a0880bf371e902 100644 GIT binary patch delta 273 zcmey$JcG6Vo)F7a1|VPsVi_QI0b+I_&H-W&=m266zY~aAfOsMha{%!)AO`7~55(sg z85ouVX^^^7CWyLPAk7ElHvwrjAUzRC1C=oVDX=*py+EMKzzkt9Fr=iWC6?xtFytlX zrZN<#mXu`Xr57`lCFYc-PPCZEZD^!xV5wkeZe?sS@u9d*KxS%DL1KPRzJgO?PD)~) zf=vNTL@x;};*g%3n3cfbpp^-1vN;@yYplX_@JzMTu3J`FW`zOY)0S833Mg BIl=${ delta 109 zcmbQi`jy$@o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OG6PL{6Hn7w+Hc&7y pu`)57?8_)F;TG!Squ}T0>#AVm>g(v~, 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-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,18 +20,18 @@ msgstr "" #: __init__.py:8 views.py:26 msgid "settings" -msgstr "" +msgstr "configurazione" #: views.py:31 msgid "name" -msgstr "" +msgstr "nome" #: views.py:32 msgid "default" -msgstr "" +msgstr "default" #: views.py:33 msgid "value" -msgstr "" +msgstr "valore" diff --git a/apps/sources/locale/it/LC_MESSAGES/django.mo b/apps/sources/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..3941752e44f67febee8c61051620ab689185f09c 100644 GIT binary patch literal 8598 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 delta 128 zcmbQ{{FT|_o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlRpW~vof&MH8xN% zFtIW*)HVPDE}z8W65WuZ#Ju91#FG3XD+RYuA0GujM_*S38&_XPPag+I7ndN{;NZ#k Hgr5Qc@Mjs_ diff --git a/apps/sources/locale/it/LC_MESSAGES/django.po b/apps/sources/locale/it/LC_MESSAGES/django.po index a03efbdf8a..873463f23c 100644 --- a/apps/sources/locale/it/LC_MESSAGES/django.po +++ b/apps/sources/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-13 08:26+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,444 +20,455 @@ msgstr "" #: __init__.py:14 msgid "View existing document sources" -msgstr "" +msgstr "Visualizza sorgenti documento esistente" #: __init__.py:15 msgid "Edit document sources" -msgstr "" +msgstr "Modifica sorgenti dei documenti" #: __init__.py:16 msgid "Delete document sources" -msgstr "" +msgstr "Cancella sorgenti dei documenti" #: __init__.py:17 msgid "Create new document sources" -msgstr "" +msgstr "Crea nuova sorgente dei documenti" #: __init__.py:19 msgid "Sources setup" -msgstr "" +msgstr "Setup sorgente" #: __init__.py:25 msgid "preview" -msgstr "" +msgstr "anteprima" #: __init__.py:26 __init__.py:34 __init__.py:40 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:28 msgid "sources" -msgstr "" +msgstr "sorgenti" #: __init__.py:29 literals.py:53 models.py:159 msgid "web forms" -msgstr "" +msgstr "web forms" #: __init__.py:30 models.py:130 msgid "staging folders" -msgstr "" +msgstr "cartelle per la gestione temporanea" #: __init__.py:31 models.py:194 msgid "watch folders" -msgstr "" +msgstr "cartelle di" #: __init__.py:33 __init__.py:39 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:35 msgid "add new source" -msgstr "" +msgstr "aggiungi una nuova sorgente" #: __init__.py:37 msgid "transformations" -msgstr "" +msgstr "trasformazioni" #: __init__.py:38 msgid "add transformation" -msgstr "" +msgstr "aggiungi una trasformazione" #: __init__.py:42 msgid "Document sources" -msgstr "" +msgstr "Sorgente del documento" #: __init__.py:69 widgets.py:39 msgid "thumbnail" -msgstr "" +msgstr "thumbnail" #: forms.py:32 forms.py:55 msgid "Expand compressed files" -msgstr "" +msgstr "Espandi" #: forms.py:33 forms.py:56 msgid "Upload a compressed file's contained files as individual documents" -msgstr "" +msgstr "Pubblicare un file compresso contenente singoli documenti" #: forms.py:41 msgid "Staging file" -msgstr "" +msgstr "Mostra file" #: literals.py:8 literals.py:13 msgid "Always" -msgstr "" +msgstr "Sempre" #: literals.py:9 literals.py:14 msgid "Never" -msgstr "" +msgstr "Mai" #: literals.py:15 msgid "Ask user" -msgstr "" +msgstr "Chiedi all'utente" #: literals.py:30 msgid "Disk" -msgstr "" +msgstr "Disco" #: literals.py:31 msgid "Database" -msgstr "" +msgstr "Database" #: literals.py:32 msgid "Drive" -msgstr "" +msgstr "Drive" #: literals.py:33 msgid "Network drive" -msgstr "" +msgstr "Disco di rete" #: literals.py:34 msgid "User drive" -msgstr "" +msgstr "Disco locale" #: literals.py:35 msgid "Envelope" -msgstr "" +msgstr "Busta" #: literals.py:36 msgid "Folder" -msgstr "" +msgstr "Cartella" #: literals.py:37 msgid "World" -msgstr "" +msgstr "Mondo" #: literals.py:38 msgid "Printer" -msgstr "" +msgstr "Stampante" #: literals.py:39 msgid "Empty printer" -msgstr "" +msgstr "Stampante vuota" #: literals.py:47 models.py:158 msgid "web form" -msgstr "" +msgstr "web form" #: literals.py:48 msgid "server staging folder" -msgstr "" +msgstr "server per la gestione temporanea della cartella" #: literals.py:49 msgid "server watch folder" -msgstr "" +msgstr "server di salvataggio cartella" #: literals.py:54 msgid "server staging folders" -msgstr "" +msgstr "server per la gestione temporanea delle cartelle" #: literals.py:55 msgid "server watch folders" -msgstr "" +msgstr "server di salvataggio delle cartelle" #: models.py:29 msgid "title" -msgstr "" +msgstr "titolo" #: models.py:30 msgid "enabled" -msgstr "" +msgstr "abilitato" #: models.py:31 msgid "whitelist" -msgstr "" +msgstr "whitelist" #: models.py:32 msgid "blacklist" -msgstr "" +msgstr "blacklist" #: models.py:98 msgid "icon" -msgstr "" +msgstr "icona" #: models.py:98 msgid "An icon to visually distinguish this source." -msgstr "" +msgstr "Un'icona per distinguere visivamente questa fonte." #: models.py:114 models.py:166 msgid "folder path" -msgstr "" +msgstr "path della cartella" #: models.py:114 models.py:166 msgid "Server side filesystem path." -msgstr "" +msgstr "Path del server di filesystem" #: models.py:115 msgid "preview width" -msgstr "" +msgstr "anteprima larghezza" #: models.py:115 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:116 msgid "preview height" -msgstr "" +msgstr "anteprima altezza" #: models.py:116 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:117 models.py:154 models.py:167 msgid "uncompress" -msgstr "" +msgstr "decomprimere" #: models.py:117 models.py:154 models.py:167 msgid "Whether to expand or not compressed archives." -msgstr "" +msgstr "Se espandere o meno degli archivi compressi." #: models.py:118 models.py:168 msgid "delete after upload" -msgstr "" +msgstr "cancella dopo il caricamento" #: models.py:118 models.py:168 msgid "Delete the file after is has been successfully uploaded." -msgstr "" +msgstr "Cancella il file dopo essere stato caricato" #: models.py:129 msgid "staging folder" -msgstr "" +msgstr "Cartella di conservazione" #: models.py:169 msgid "interval" -msgstr "" +msgstr "intervallo" #: models.py:169 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:193 msgid "watch folder" -msgstr "" +msgstr "controlla cartella" #: models.py:198 msgid "Enter a valid value." -msgstr "" +msgstr "Inserisci un valore valido" #: models.py:226 views.py:487 msgid "order" -msgstr "" +msgstr "ordine" #: models.py:227 views.py:488 views.py:525 views.py:555 msgid "transformation" -msgstr "" +msgstr "trasformazione" #: models.py:228 views.py:489 msgid "arguments" -msgstr "" +msgstr "argomenti" #: models.py:228 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" -msgstr "" +msgstr "Usa dei dizionari per identificare gli argomenti , esempio: %s" #: models.py:239 msgid "document source transformation" -msgstr "" +msgstr "trasformazione del documento sorgente" #: models.py:240 msgid "document source transformations" -msgstr "" +msgstr "trasformazioni dei documenti sorgente" #: staging.py:42 #, python-format msgid "Unable get list of staging files: %s" -msgstr "" +msgstr "Impossibile ottenere lista dei file di gestione temporanea: %s" #: staging.py:127 #, python-format msgid "Unable to upload staging file: %s" -msgstr "" +msgstr "Impossibile caricare file di gestione temporanea: %s" #: staging.py:137 #, python-format msgid "Unable to delete staging file: %s" -msgstr "" +msgstr "Impossibile eliminare file di gestione temporanea: %s" #: utils.py:40 msgid "Whitelist Blacklist validation error." -msgstr "" +msgstr "Errori di validazione nelle Whitelist e Blacklist." #: views.py:80 msgid "here" -msgstr "" +msgstr "qui" #: views.py:85 msgid "Upload sources" -msgstr "" +msgstr "Sorgenti caricamento" #: views.py:87 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:88 #, 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:136 msgid "Document uploaded successfully." -msgstr "" +msgstr "Documenti caricati con successo" #: views.py:152 #, python-format msgid "upload a local document from source: %s" -msgstr "" +msgstr "carica un documento in locale dalla sorgente: %s" #: views.py:182 #, python-format msgid "Staging file: %s, uploaded successfully." -msgstr "" +msgstr "File in allestimento:%s, caricato con successo." #: views.py:187 #, python-format msgid "Staging file: %s, deleted successfully." -msgstr "" +msgstr "File in allestimento:%s, cancellato con successo." #: views.py:209 #, python-format msgid "upload a document from staging source: %s" -msgstr "" +msgstr "carica documento dalla sorgente allestimento:%s" #: views.py:215 msgid "files in staging path" -msgstr "" +msgstr "path dei file in allestimento" #: views.py:229 msgid "Current metadata" -msgstr "" +msgstr "Metadati correnti" #: views.py:265 views.py:284 #, python-format msgid "Staging file transformation error: %(error)s" -msgstr "" +msgstr "Errore nella trasformazione del file: %(error)s" #: views.py:307 msgid "Staging file delete successfully." -msgstr "" +msgstr "File in allestimento cancellato con successo." #: views.py:309 #, python-format msgid "Staging file delete error; %s." -msgstr "" +msgstr "Errore nella cancellazione del file in allestimento;%s." #: views.py:368 msgid "Source edited successfully" -msgstr "" +msgstr "Sorgente modificata con successo" #: views.py:371 #, python-format msgid "Error editing source; %s" -msgstr "" +msgstr "Errore nella modifica del sorgente;%s" #: views.py:376 #, python-format msgid "edit source: %s" -msgstr "" +msgstr "modifica sorgente:%s" #: views.py:381 views.py:421 views.py:483 views.py:524 views.py:554 #: views.py:597 msgid "source" -msgstr "" +msgstr "sorgente" #: views.py:410 #, python-format msgid "Source \"%s\" deleted successfully." -msgstr "" +msgstr "Sorgente \"%s\" cancellata con successo." #: views.py:412 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" -msgstr "" +msgstr "Errore nella cancellazione della sorgente \"%(source)s\": %(error)s" #: views.py:419 #, python-format msgid "Are you sure you wish to delete the source: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare la sorgente: %s?" #: views.py:451 msgid "Source created successfully" -msgstr "" +msgstr "Sorgente creata con successo" #: views.py:454 #, python-format msgid "Error creating source; %s" -msgstr "" +msgstr "Errore nella creazione della sorgente;%s" #: views.py:459 #, python-format msgid "Create new source of type: %s" -msgstr "" +msgstr "Crea nuovo tipo di sorgente:%s" #: views.py:481 #, python-format msgid "transformations for: %s" -msgstr "" +msgstr "trasformazione per: %s" #: views.py:511 msgid "Source transformation edited successfully" -msgstr "" +msgstr "Sorgente per la trasformazione modificata con successo" #: views.py:514 #, python-format msgid "Error editing source transformation; %s" -msgstr "" +msgstr "Errore nella modifica della sorgente per la trasformazione;%s" #: views.py:519 #, python-format msgid "Edit transformation: %s" -msgstr "" +msgstr "Modifica trasformazione:%s" #: views.py:542 msgid "Source transformation deleted successfully." -msgstr "" +msgstr "Sorgente per la trasformazione cancellata con successo." #: views.py:544 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "" +"Erroro nella cancellazione della sorgente per la trasformazione; %(error)s" #: views.py:557 #, 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:587 msgid "Source transformation created successfully" -msgstr "" +msgstr "Sorgente di trasformazione creata con successo" #: views.py:590 #, python-format msgid "Error creating source transformation; %s" -msgstr "" +msgstr "Errore nella creazione della sorgente di trasformazione; %s" #: views.py:599 #, python-format msgid "Create new transformation for source: %s" -msgstr "" +msgstr "Crea una nuova sorgente per la trasformazione:%s" diff --git a/apps/tags/locale/it/LC_MESSAGES/django.mo b/apps/tags/locale/it/LC_MESSAGES/django.mo index 34e8cee481a6504dbbaf0d0a1d235e31ce9135f7..e7c323701a9f190dba53036ae784466638a28df0 100644 GIT binary patch literal 4271 zcma);OKe?78Gt9n(9~^tG=1<2OiY7q+H5(^{{4}pY$1%(AtktzXex-3!`fU-ld0zp?i1UvZt^SJjqwUv%M_d9dW z{Qu1VnECz32PVF)Xy@o3rT^=QQdi(_-^CB@=)09V2JeB7!{ac5pKHc9oAFPe%=;aj zfPaDfska*b1HO;(f1!Lo`W~eofcL{GsNwtJ5}bzX@P7Cbybpd2ioWl{d*Bb?-SDSy z4!#OM2LA*_|Nolr6HMY!-3P^_WAMZ95jYDMpxFH-_;I)kMbGyd{u+v1x8Mii-y2RG zt=BmYALjiO`~-Xo%6iYkNf^TqKo4dAUuoXI4ByN6o6Y#gP~?6NKLTHaV#k|M?Eii9 z{m)SB_$%a3y~U5{`8O2*P2e1v{}2@Usb)M4#s5#hH;M5wJi++EdwB=Xz#e=7ia%dz zcnivYj-pibJql%?vk+IPIrs=X+q}ODA7%U;T!1e@k$)AQfp0+Z=UoI>{PQprznp*) z?`eKS?`bIVi%`RDDC>U%iXGp9n4n&PBL54h;V)qq-hwCL-8e_~6TxY?){OU{?E8oC zIQ$h9fBXT8-v7XPc!b3yKTkoi`#O~UKMx;*FE;OAhPX<79ZH^jAEH9N1|?3vfs$8m zG~>TPS^u9FJZ<>32Fg++lWZ2mZ!8RlR?5tGXyme@ok&F1QSXOcK;HX=&AxPkqjBZc??BTZ09e z-Ki%m?V3z2*JdTD-!N(Ye!205c0rpIp?Ft5BsSJ2=&6%oO0C4M(Bm>IdG2!^i?U_| zOq@Y#HcVmtjFs=RL9MXEc1BPaa%;2bi#ARDj{5wTdBLemF4-!0zpGYFLO_gKEkmLE zTiyq&t;7GhHmwnwMNL-OU1{~1?bHI>xxe9Jt4*O(YtX2BoVu{iDU6XMz1{1Ae8;S4PmoP)7{SPGY|WC2jR+(hwH9W z;Gm`3a7iK*q25lv3VS_^gue@Y<*Pb3$ zY=T+4N5s_Vkz*t$LG`PotbTPS(WtlB2DKfEaP0{-TtM%T0qr5IbJ3EEN`7RuN`JjS zCGvEg;*08moY=N`;cSqhFl@N6(Z=h}JQEt0=a6-EM*juUcIs&RfiR|(K0dW>4mxZ`G~)T1wB9CTR0QVJux@O#Awal;LP7PZy}mLrRPug zPCxnB9BuLv2OwG})kA6uv8Y{Fe>(RYxWspwH=V?1dnUDepG^kFrLxJ-Af6>9r!iW$ zX3*0Y3zIr5ooVdZ+1cq7qTFrTo1M%ST^uFe3El15u*k-P&@GVex}rNfxq5MRW#qT{ z&fMgZ&k9a^w7$EIwS~QjlGM2D94Fu8!4`{OSbsJ;JDMl!ZQ49q$@)I#%IWE|8?G2` zwWk?eO-t^*=vki+xF@siY8Vz5&guGbaVFCz7WMq>q&lA@uFMjr(`jz7{+8v0a`_Dt z#H(x8>EQZhPO)(MhEKVN`X=jhc^OK@iv$jlp|E7l({~ao%7P2I66J1d*2VtAL~}PN zsT3@ij^-PguMb}9K!Iuj1gH(EO~&@DZQ!U720KUeXV6W>kOH@f!LnB`Vg zWk*U{Iv$JBg65Da)Vg|Tu~Qu5*e4lRQ&Wj9bkKCl=eF?fU z%-gzDRT(WQ$(j;p9{WCP>y=lB%^#oCsb*D&p;mg3rg~C+WU5*1vAAu;x6LCvF>U|0 zI_lEMGo%OEQG0T1zg4-|FE;j-o1GgqJJeoFc?%_1*xp{9Q%<|#Id_$hZa>WGn#tKn zyWjW#Id#F|X0K{r?~iZuZkXTN^x7(DRVJBU)xx?C9+Xm5MH~fQwGJNE#d_QO^PYdx z2F=kKK8#;)vWNP9aB8?UCB>4;{VFjh(B%UyvF_MK-lwt=CF!YM8KZ%%S^8f$< delta 128 zcmZ3l_?6k>o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlbt!|Ss7UB8XG7W zm{^$@Y8wCnmrr7GiEc, 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:41+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-13 15:57+0000\n" +"Last-Translator: rosarior \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" @@ -19,249 +21,249 @@ msgstr "" #: __init__.py:13 msgid "Create new tags" -msgstr "" +msgstr "Crea un nuova etichetta" #: __init__.py:14 msgid "Attach exising tags" -msgstr "" +msgstr "Collega etichetta esistente" #: __init__.py:15 msgid "Remove tags from documents" -msgstr "" +msgstr "Rimuovi etichetta dal documento" #: __init__.py:16 msgid "Delete global tags" -msgstr "" +msgstr "Cancellazione globale dell'etichette" #: __init__.py:17 msgid "Edit global tags" -msgstr "" +msgstr "Modifica tutte le etichette" #: __init__.py:18 msgid "View a document's tags" -msgstr "" +msgstr "Visualizza tutti i documenti con questa etichetta" #: __init__.py:20 msgid "Tags" -msgstr "" +msgstr "Etichette" #: __init__.py:28 msgid "tag list" -msgstr "" +msgstr "lista delle etichette" #: __init__.py:29 msgid "create new tag" -msgstr "" +msgstr "crea una nuova etichetta" #: __init__.py:30 msgid "attach tag" -msgstr "" +msgstr "allega un'etichetta" #: __init__.py:31 __init__.py:32 msgid "remove" -msgstr "" +msgstr "rimuovi" #: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 msgid "tags" -msgstr "" +msgstr "etichette" #: __init__.py:34 __init__.py:37 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:35 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:36 msgid "tagged documents" -msgstr "" +msgstr "documenti etichettati" #: __init__.py:41 models.py:46 msgid "color" -msgstr "" +msgstr "colore" #: __init__.py:45 msgid "color name" -msgstr "" +msgstr "nome colore" #: forms.py:14 msgid "New tag" -msgstr "" +msgstr "Nuova etichetta" #: forms.py:15 forms.py:24 msgid "Color" -msgstr "" +msgstr "Colori" #: forms.py:16 msgid "Existing tags" -msgstr "" +msgstr "Etichette esistenti" #: forms.py:23 msgid "Name" -msgstr "" +msgstr "Nome" #: models.py:18 msgid "Blue" -msgstr "" +msgstr "Blue" #: models.py:19 msgid "Cyan" -msgstr "" +msgstr "Ciaono" #: models.py:20 msgid "Coral" -msgstr "" +msgstr "Corallo" #: models.py:21 msgid "Green-Yellow" -msgstr "" +msgstr "Verdognolo" #: models.py:22 msgid "Khaki" -msgstr "" +msgstr "Khaki" #: models.py:23 msgid "LightGrey" -msgstr "" +msgstr "Grigio chiaro" #: models.py:24 msgid "Magenta" -msgstr "" +msgstr "Magenta" #: models.py:25 msgid "Red" -msgstr "" +msgstr "Rosso" #: models.py:26 msgid "Orange" -msgstr "" +msgstr "Arancione" #: models.py:27 msgid "Yellow" -msgstr "" +msgstr "Giallo" #: models.py:45 views.py:185 views.py:233 views.py:248 msgid "tag" -msgstr "" +msgstr "etichetta" #: models.py:49 msgid "tag properties" -msgstr "" +msgstr "proprità dell'etichetta" #: models.py:50 msgid "tags properties" -msgstr "" +msgstr "proprietà delle etichette" #: views.py:33 msgid "Tag already exists." -msgstr "" +msgstr "L'etichetta già esiste" #: views.py:40 msgid "Tag created succesfully." -msgstr "" +msgstr "Etichetta creata con successo" #: views.py:46 msgid "create tag" -msgstr "" +msgstr "crea etichetta" #: views.py:73 views.py:112 msgid "Must choose either a new tag or an existing one." -msgstr "" +msgstr "Devi scegliere una nuova etichetta o una esistente" #: views.py:77 views.py:116 #, python-format msgid "Document is already tagged as \"%s\"" -msgstr "" +msgstr "Il documento è giià stato etichettato come \"%s\"." #: views.py:86 #, python-format msgid "Tag \"%s\" added successfully." -msgstr "" +msgstr "Etichetta \"%s\" aggiunta con successo." #: views.py:124 #, python-format msgid "Tag \"%s\" added and attached successfully." -msgstr "" +msgstr "Etichetta \"%s\" aggiunta e allegata con successo" #: views.py:126 #, python-format msgid "Tag \"%s\" attached successfully." -msgstr "" +msgstr "Eticetta \"%s\" allegata con successo." #: views.py:133 #, python-format msgid "attach tag to: %s" -msgstr "" +msgstr "allega etichetta a:%s" #: views.py:149 msgid "tagged items" -msgstr "" +msgstr "articoli etichettati." #: views.py:166 views.py:280 msgid "Must provide at least one tag." -msgstr "" +msgstr "Devi fornire almeno un'etichetta" #: views.py:176 #, python-format msgid "Tag \"%s\" deleted successfully." -msgstr "" +msgstr "Etichetta \"%s\" cancellata con successo." #: views.py:178 views.py:294 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" -msgstr "" +msgstr "Errore nel cancellare l'etichetta \"%(tag)s\": %(error)s" #: views.py:193 #, python-format msgid "Are you sure you wish to delete the tag: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare questa etichetta: %s?" #: views.py:194 views.py:197 msgid "Will be removed from all documents." -msgstr "" +msgstr "Sarà rimossa da tutti i documenti" #: views.py:196 #, python-format msgid "Are you sure you wish to delete the tags: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare tutte queste etichette: %s?" #: views.py:221 msgid "Tag updated succesfully." -msgstr "" +msgstr "Etichetta aggiornata con successo" #: views.py:230 #, python-format msgid "edit tag: %s" -msgstr "" +msgstr "modifica l'etichetta:%s" #: views.py:245 #, python-format msgid "documents with the tag \"%s\"" -msgstr "" +msgstr "documenti con l'etichetta \"%s\"" #: views.py:258 #, python-format msgid "tags for: %s" -msgstr "" +msgstr "etichette per: %s" #: views.py:292 #, python-format msgid "Tag \"%s\" removed successfully." -msgstr "" +msgstr "Etichetta \"%s\" rimossa con successo." #: views.py:308 #, python-format msgid "Are you sure you wish to remove the tag: %s?" -msgstr "" +msgstr "Sei sicuro di voler rimuovere le etichetta: %s ?" #: views.py:310 #, python-format msgid "Are you sure you wish to remove the tags: %s?" -msgstr "" +msgstr "Sei sicuro di voler rimuovere le etichette: %s ?" #: templatetags/tags_tags.py:17 msgid "Add tag to document" -msgstr "" +msgstr "Aggiungi l'etichetta al documento" diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.mo b/apps/user_management/locale/it/LC_MESSAGES/django.mo index 72cbfdd28e96e44641807cba5841648db40f9397..bb05dd71b6d93923629a2e2cb14ec33574086f68 100644 GIT binary patch literal 4746 zcmcJSONbmr7{^N!U+ep=@l~#_*)`iUvuo5iF~*pzA?TVV*#vxmRJvz-I!F2c7_LK>v^6c_2HBu~FcB z@OrQXQvZH%9Ms^W;OpQc;O}5U{bzf*_XEEP{2jay{g<8N^}QJ+eeVJ>C7T7w-g%JZ zWN5EIxP(0oUI0D|o)5kX!Zdaq#2?VgPT#`fJtuw zw}3Bz2f(MmZ^2i88Cu)D+m#`AEfv^4&skl{E$DN2g$yd1K$7=KqvWO1f=>kfukVh^#n-%+8OE(hkgyhm25H8p92vl zHid#vxj6y%+=yQqV-kgQCV!AFr=yVXHlo~$LJ!$K{6uJIhDNf9ql||-t?8Rkt_$_s zKw2-u&omk+9<*j@>62~rv``u-lygWe=L_-=#h4!Q=_ZsbQD_gL9Hux^Y-k;l&&Ut7 z)+bQvXDePPzu{(=e{7eLd|6lAR^eqy*#%x|p2$>|l9vmTca5%!HXpM)PhQ-fynJP) z`ESx;@ZCD^D3kF*Si7W6!gd=epmQ#lyv}y8g{HA=k2gymRkl=lx0V}j_QErXD*3SJ z%ElmQj5gk7y+Qft*tqlDgdK%>j+du0+$X8%vQGKh0%*DkzABKl>!Yq54qA{YYUL# z4fYU1RNKSmLi{XGG|zR(Gf~D1le{#`Ty%xX8|=WEPN2+Lr`x3pJJ`3sH!XLL?KzXi zX+W?*IGl4u4y#Mi>G-Pi6a`mVr=v(yy(E)K>UFC`B$>*&%1dcFB9?AotRD2n!pe2W zmdLaJY3SO?-r7@|>zuFJ;q$Hz40Ec{j~|-eESod>2^p8sz9c$~y3%=@&x&P{^O-%f2S*ObLYp$0 zwOy4&_f=gR&FeN_D9fVVY<5+-P#tN+I%^tjg;ClxGy1lvtgWOSncF`fxvdhzMtiWl z+kCn;H5K7+dYVs7wWsfhT3cH!2u26wqN3?n$W2F6xAE3p?dfe>T6jht#OjacjmT{( zN(~>*DQOC!Q_b%aX#%b9F6x%X5!Z5WmwZf0-h0iDvRxCs;OZzU_!Ad#biMDsyRNL>k?%O@?hI zFI?5`nBLC)>yGi9-?)QMO^mREQgN%|%HUvCd{L(ecP#Q)rm4Wet5PIRRTKy!owENX z?S<7z38$MYvK&^Q#K_%LaVH+erW010O!PKQccAjT!p>i7AX*eo2}QLzXE4oLQTyd?K$C(a0RThD*Tke-qb-{8ab&Rx13tom*3ruB|u z$?0%Ftc+Ayp>a6SKIN`TP^VtdPUv5T+v|coa7Jq$W4j2)w5B7PvLOfrUt*@Ug+#ZD zb)IAS4GHbR0_GxxrW%J+0zV_)5H6o@xDTNl7m8e=If$Xx=M2tiM7nPpd$9kGLomlw z#wc6pJdu;!D7p~{I;?|x_*!mhkI|XEmefENLax3Y^u1m}3k0I}F=cjx?MmT3cX+#W z=P=U0ke;8uLte3zesIvLxr0xw&P57Cs#2xu*fDZcy172kVKsS*^k#A{T%p=2&ix;J08@HdOm+?gwx{1IYIDf@pnnk^PR$hp zYbE)h(3(lUmjXb$fQz}p)xlOcL=eN?1~k|fq(q5(gLc;hS`oCX>3UtzWuo8cKEMql zD9P$@_Flqgl#2Z}{}tuBzfj~l!(~us1^%L7So13D( ZTNpLmV-zmavYU&+kg}k^pDS1&@DE|iMAQHP delta 128 zcmeBD{mN`{Pl#nI0}wC*u?!Ha05LNV>i{tbSOD>Eprj>`2C0F8$?{zDtPCu5jSUnG zOsq^zwGDuP%O|n8L^q@;F|Rl$u_V99O2IAE$49}>(brYM#?{x+)5pQl#U;o!ICwHQ G_fr6&lNbU3 diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.po b/apps/user_management/locale/it/LC_MESSAGES/django.po index 5e5ae7a353..c816b88945 100644 --- a/apps/user_management/locale/it/LC_MESSAGES/django.po +++ b/apps/user_management/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:55+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-13 09:28+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -19,236 +20,244 @@ msgstr "" #: __init__.py:8 msgid "Create new users" -msgstr "" +msgstr "Crea un nuovo utente" #: __init__.py:9 msgid "Edit existing users" -msgstr "" +msgstr "Modifica utenti " #: __init__.py:10 msgid "View existing users" -msgstr "" +msgstr "Visualizza utenti" #: __init__.py:11 msgid "Delete existing users" -msgstr "" +msgstr "Cancella utenti" #: __init__.py:13 msgid "Create new groups" -msgstr "" +msgstr "Crea nuovi gruppi" #: __init__.py:14 msgid "Edit existing groups" -msgstr "" +msgstr "Modifica gruppi esistenti" #: __init__.py:15 msgid "View existing groups" -msgstr "" +msgstr "Visualizza i gruppi" #: __init__.py:16 msgid "Delete existing groups" -msgstr "" +msgstr "Cancella i gruppi esistenti" #: __init__.py:18 msgid "User management" -msgstr "" +msgstr "Gestione utenti" #: __init__.py:28 msgid "user list" -msgstr "" +msgstr "lista utenti" #: __init__.py:29 views.py:31 msgid "users" -msgstr "" +msgstr "utenti" #: __init__.py:30 __init__.py:39 msgid "edit" -msgstr "" +msgstr "modifica" #: __init__.py:31 views.py:92 msgid "create new user" -msgstr "" +msgstr "crea un nuovo utente" #: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 msgid "delete" -msgstr "" +msgstr "cancella" #: __init__.py:34 __init__.py:35 msgid "reset password" -msgstr "" +msgstr "riassegna la password" #: __init__.py:37 msgid "group list" -msgstr "" +msgstr "lista dei gruppi" #: __init__.py:38 views.py:222 msgid "groups" -msgstr "" +msgstr "gruppi" #: __init__.py:40 views.py:270 msgid "create new group" -msgstr "" +msgstr "crea un nuovo gruppo" #: __init__.py:43 views.py:226 msgid "members" -msgstr "" +msgstr "membri" #: forms.py:13 msgid "New password" -msgstr "" +msgstr "Nuova password" #: forms.py:14 msgid "Confirm password" -msgstr "" +msgstr "Conferma password" #: views.py:35 msgid "full name" -msgstr "" +msgstr "nome completo" #: views.py:39 msgid "email" -msgstr "" +msgstr "email" #: views.py:43 msgid "active" -msgstr "" +msgstr "attivo" #: views.py:58 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." msgstr "" +"Super utente e utente modifica il personale non è consentito, utilizzare " +"l'interfaccia di amministrazione per questi casi." #: views.py:65 #, python-format msgid "User \"%s\" updated successfully." -msgstr "" +msgstr "Utente \"%s\" aggiornato con successo." #: views.py:71 #, python-format msgid "edit user: %s" -msgstr "" +msgstr "modifica utente:%s" #: views.py:74 views.py:130 views.py:193 msgid "user" -msgstr "" +msgstr "utente" #: views.py:86 #, python-format msgid "User \"%s\" created successfully." -msgstr "" +msgstr "Utente \"%s\" creato con successo." #: views.py:108 views.py:162 msgid "Must provide at least one user." -msgstr "" +msgstr "Devi fornire almeno un utente." #: views.py:118 msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." msgstr "" +"Al super utente e utente non è consentito la cancellazione del personale, " +"utilizzare l'interfaccia di amministrazione per questi casi." #: views.py:121 #, python-format msgid "User \"%s\" deleted successfully." -msgstr "" +msgstr "Utente \"%s\" cancellato con successo." #: views.py:123 #, python-format msgid "Error deleting user \"%(user)s\": %(error)s" -msgstr "" +msgstr "Errore nella cancellazione dell'utente \"%(user)s\": %(error)s" #: views.py:138 #, python-format msgid "Are you sure you wish to delete the user: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare l'utente: %s?" #: views.py:140 #, python-format msgid "Are you sure you wish to delete the users: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare gli utenti: %s?" #: views.py:173 msgid "Passwords do not match, try again." -msgstr "" +msgstr "La password non corrisponde, riprova." #: views.py:178 msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." msgstr "" +"Al super utente e utente non è consentito di reimpostare la password " +"personale, utilizzare l'interfaccia di amministrazione per questi casi." #: views.py:182 #, python-format msgid "Successfull password reset for user: %s." -msgstr "" +msgstr "Password reimpostata per l'utente: %s." #: views.py:184 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" msgstr "" +"Errore per il reimpostamento della password per l'utente \"%(user)s\": " +"%(error)s" #: views.py:200 #, python-format msgid "Reseting password for user: %s" -msgstr "" +msgstr "Reimposta la password per l'utente:%s" #: views.py:202 #, python-format msgid "Reseting password for users: %s" -msgstr "" +msgstr "Reimposta la password per gli utenti:%s" #: views.py:243 #, python-format msgid "Group \"%s\" updated successfully." -msgstr "" +msgstr "Gruppo \"%s\" aggiornato con successo." #: views.py:249 #, python-format msgid "edit group: %s" -msgstr "" +msgstr "modifica gruppo: %s" #: views.py:252 views.py:305 views.py:350 msgid "group" -msgstr "" +msgstr "gruppo" #: views.py:264 #, python-format msgid "Group \"%s\" created successfully." -msgstr "" +msgstr "Gruppo \"%s\" creato con successo." #: views.py:286 msgid "Must provide at least one group." -msgstr "" +msgstr "Devi almeno indicare un gruppo" #: views.py:296 #, python-format msgid "Group \"%s\" deleted successfully." -msgstr "" +msgstr "Gruppo \"%s\" cancellato con successo." #: views.py:298 #, python-format msgid "Error deleting group \"%(group)s\": %(error)s" -msgstr "" +msgstr "Erroro nella cancellazione del gruppo\"%(group)s\": %(error)s" #: views.py:313 #, python-format msgid "Are you sure you wish to delete the group: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare il gruppo: %s?" #: views.py:315 #, python-format msgid "Are you sure you wish to delete the groups: %s?" -msgstr "" +msgstr "Sei sicuro di voler cancellare i gruppi: %s?" #: views.py:345 #, python-format msgid "non members of group: %s" -msgstr "" +msgstr "non membri del gruppo: %s" #: views.py:346 #, python-format msgid "members of group: %s" -msgstr "" +msgstr "membri del gruppo: %s" diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.mo b/apps/web_theme/locale/it/LC_MESSAGES/django.mo index dec8509d2476cd85c7d29c827507779e32e37d0f..1dd30bb263840b82d76ddd4a5118e4dc43aa9896 100644 GIT binary patch literal 1740 zcma)6&u<$=6rMt%V9EgwNFWZ6NQgvay|%@V;3k3QM^U7>jvN;W38@l^QeLMs)RVeR9r_5d_w`X#%H*%*gribpL5CN4aur1 z=9^?HuZ(siE%!;5)@;&*lctF>%dF8YYTl%jr?M_QI`>q`QNp$^SYkP~(s`9cskCRC zbS8aXU>kOrLY)V&QfENRX=qeBSvXcMC#h4K;pp7dj@#luxvG$J;s@SJQhI7^DFZ+B z19K`&hMr3Tv9>r4BXJwnVrVHTRB}e!l5)$_owaw@kB6Th-M%|IJUAL1?vL-@869u9 zwcVU8Z^v?%)HG01mXqd$)Ueaq$E?Wo(U;Rv8loV7*)7wy8Q+Swp4f%+rfj1_otRYV ztWR4L=WJ7$LZ#56`fr^=)k~Sm$R%}9`M-oJH<7JUCkji* z3KyW!YH*L|vxb;TnaPU_rA=E54CXF1x}dm_tt=KYUCQ&cP7-!bof|Q%sv3&;pF+J~ ztCdbGwgewgE?HILr-3YjT*%jkAVWi%3reIz2mgv`ts6d#iW5%pt_&S34Y8|>3t3{~ za(h*W0pf-?v^b+#XnZ~;XVn&`tO#ipj2kx4Jzhv8xvEnolF)*V_ePwS?EPYZ9~Q54 Uo3nub3de+N+=tG*T&+p*51*(7^#A|> delta 127 zcmX@Z`<2<^o)F7a1|VPrVi_P-0b*t#)&XJ=umIxSKuJp=4N?OGlYcYKw=~o>Fjg=! zv@$W$HUI)HpTy!4-H@WhyyBe1lKdho1-DQi9|b>0UsnYiS6@d@9|uPlmmt^R;K|RK Gp8^2cwi%ZI diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.po b/apps/web_theme/locale/it/LC_MESSAGES/django.po index 69086d2e50..e35a81dd81 100644 --- a/apps/web_theme/locale/it/LC_MESSAGES/django.po +++ b/apps/web_theme/locale/it/LC_MESSAGES/django.po @@ -3,13 +3,14 @@ # 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: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-11-03 21:42+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2011-12-09 18:07+0000\n" +"Last-Translator: Pierpaolo Baldan \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" @@ -23,38 +24,41 @@ msgid "" "cerulean, drastic-dark, kathleene, olive, orange, red, reidb-greenish and " "warehouse." msgstr "" +"Tema CSS da applicare, le opzioni sono: ABN AMRO, bec, bec-verde, blu, di " +"default, djime-ceruleo, drastica-scuro, kathleene, oliva, arancio, rosso, " +"reidb-verdastro e magazzino." #: conf/settings.py:12 msgid "Display extra information in the login screen." -msgstr "" +msgstr "Mostra informazioni extra al login" #: templates/web_theme_base.html:101 msgid "dismiss all notifications" -msgstr "" +msgstr "Smetti tutte le notifiche" #: templates/web_theme_base.html:101 msgid "close all" -msgstr "" +msgstr "ciudi tutto" #: templates/web_theme_base.html:102 msgid "dismiss this notification" -msgstr "" +msgstr "respingere questa notifica" #: templates/web_theme_base.html:102 msgid "close" -msgstr "" +msgstr "chiudi" #: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 msgid "Login" -msgstr "" +msgstr "Login" #: templates/web_theme_login.html:17 msgid "You are already logged in" -msgstr "" +msgstr "Sei pronto per entrare" #: templates/web_theme_login.html:20 msgid "Redirecting you to the website entry point in 5 seconds." -msgstr "" +msgstr "Reindirizzamento al tuo punto di ingresso al sito in 5 secondi." #: templates/web_theme_login.html:23 #, python-format @@ -62,15 +66,17 @@ msgid "" "Or click here if redirection doesn't " "work." msgstr "" +"Oppure click qui if per essere " +"rimandato al tuo sito nel caso non funzioni." #: templates/pagination/pagination.html:6 #: templates/pagination/pagination.html:8 msgid "Previous" -msgstr "" +msgstr "Precedente" #: templates/pagination/pagination.html:26 #: templates/pagination/pagination.html:28 msgid "Next" -msgstr "" +msgstr "Successivo" From c99ed273fa79b1eba86b3b91eaf3a6e229b6af10 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 12:03:28 -0400 Subject: [PATCH 058/484] Update Italian translation credits --- docs/contributors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributors.rst b/docs/contributors.rst index 45689b59da..a89656ffb3 100644 --- a/docs/contributors.rst +++ b/docs/contributors.rst @@ -44,4 +44,4 @@ Translations * Russian * Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Italian - * Pierpaolo Baldan + * SeeOpen.IT (Numero Verde: 800.910.125, E-mail: sales@seeopen.it) From 7067130750fb689c8aeb363a304540b881fea9e4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 12:03:51 -0400 Subject: [PATCH 059/484] Update changelog --- docs/changelog.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 80d0787351..02739221f4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,3 +1,8 @@ +Version 0.12 +------------ +* Italian translation by SeeOpen.IT (www.seeopen.it, info@seeopen.it) + + Version 0.11 ------------ * Support for signed documents verification added, embedded and detached From fe0e3de898d113776d1c98d818202cfe9d60f3a3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 12:42:00 -0400 Subject: [PATCH 060/484] Update changelog --- docs/changelog.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 02739221f4..df1652937f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -3,6 +3,16 @@ Version 0.12 * Italian translation by SeeOpen.IT (www.seeopen.it, info@seeopen.it) +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 + + Version 0.11 ------------ * Support for signed documents verification added, embedded and detached From 4c86a9823a40e424918a3f601cf86dbc8e14c5bd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 13:00:19 -0400 Subject: [PATCH 061/484] Remove db_index from TextField class fields, this closes issue #12 --- apps/documents/migrations/0001_initial.py | 4 ++-- apps/documents/migrations/0002_filename_extension_merge.py | 4 ++-- .../0003_auto__del_field_document_file_extension.py | 4 ++-- ...tversion__add_unique_documentversion_document_mayor_m.py | 4 ++-- apps/documents/migrations/0005_document_versions.py | 4 ++-- .../migrations/0006_fix_invalid_document_version_id_keys.py | 4 ++-- apps/documents/migrations/0007_remove_old_file_fields.py | 4 ++-- apps/documents/migrations/0008_fix_mayor_field_name.py | 4 ++-- apps/documents/migrations/0009_add_comment_field.py | 4 ++-- .../migrations/0010_auto__chg_field_document_date_added.py | 4 ++-- .../0011_auto__add_field_documentversion_signature_state.py | 4 ++-- .../0012_auto__add_field_documentversion_signature_file.py | 4 ++-- apps/documents/models.py | 6 +++--- 13 files changed, 27 insertions(+), 27 deletions(-) diff --git a/apps/documents/migrations/0001_initial.py b/apps/documents/migrations/0001_initial.py index 25acbc89de..c50a63a10f 100644 --- a/apps/documents/migrations/0001_initial.py +++ b/apps/documents/migrations/0001_initial.py @@ -28,7 +28,7 @@ class Migration(SchemaMigration): ('date_added', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, db_index=True, blank=True)), ('date_updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), ('checksum', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), - ('description', self.gf('django.db.models.fields.TextField')(db_index=True, null=True, blank=True)), + ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), )) db.send_create_signal('documents', ['Document']) @@ -45,7 +45,7 @@ class Migration(SchemaMigration): db.create_table('documents_documentpage', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])), - ('content', self.gf('django.db.models.fields.TextField')(db_index=True, null=True, blank=True)), + ('content', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), ('page_label', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)), ('page_number', self.gf('django.db.models.fields.PositiveIntegerField')(default=1, db_index=True)), )) diff --git a/apps/documents/migrations/0002_filename_extension_merge.py b/apps/documents/migrations/0002_filename_extension_merge.py index 6d7dc4182b..976a9452cd 100644 --- a/apps/documents/migrations/0002_filename_extension_merge.py +++ b/apps/documents/migrations/0002_filename_extension_merge.py @@ -77,7 +77,7 @@ class Migration(DataMigration): 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), 'file_extension': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '16', 'db_index': 'True'}), @@ -89,7 +89,7 @@ class Migration(DataMigration): }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0003_auto__del_field_document_file_extension.py b/apps/documents/migrations/0003_auto__del_field_document_file_extension.py index 85f3a1821f..f5ac51cb3e 100644 --- a/apps/documents/migrations/0003_auto__del_field_document_file_extension.py +++ b/apps/documents/migrations/0003_auto__del_field_document_file_extension.py @@ -76,7 +76,7 @@ class Migration(SchemaMigration): 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), @@ -87,7 +87,7 @@ class Migration(SchemaMigration): }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py b/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py index e6b0c9bf10..60ce9a9f3a 100644 --- a/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py +++ b/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py @@ -103,7 +103,7 @@ class Migration(SchemaMigration): 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), @@ -114,7 +114,7 @@ class Migration(SchemaMigration): }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), diff --git a/apps/documents/migrations/0005_document_versions.py b/apps/documents/migrations/0005_document_versions.py index 7244593da3..6e54b2963d 100644 --- a/apps/documents/migrations/0005_document_versions.py +++ b/apps/documents/migrations/0005_document_versions.py @@ -91,7 +91,7 @@ class Migration(DataMigration): 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), @@ -102,7 +102,7 @@ class Migration(DataMigration): }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), diff --git a/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py b/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py index 03f4ba4133..0cdd0a2b52 100644 --- a/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py +++ b/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py @@ -74,7 +74,7 @@ class Migration(DataMigration): 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), @@ -85,7 +85,7 @@ class Migration(DataMigration): }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), diff --git a/apps/documents/migrations/0007_remove_old_file_fields.py b/apps/documents/migrations/0007_remove_old_file_fields.py index 02c074fcfd..9c84b2f93d 100644 --- a/apps/documents/migrations/0007_remove_old_file_fields.py +++ b/apps/documents/migrations/0007_remove_old_file_fields.py @@ -122,14 +122,14 @@ class Migration(SchemaMigration): 'documents.document': { 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'83100718-e901-4880-95f8-3618749c8a99'", 'max_length': '48', 'blank': 'True'}) }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0008_fix_mayor_field_name.py b/apps/documents/migrations/0008_fix_mayor_field_name.py index dc540dfbec..17f9fa483f 100644 --- a/apps/documents/migrations/0008_fix_mayor_field_name.py +++ b/apps/documents/migrations/0008_fix_mayor_field_name.py @@ -92,14 +92,14 @@ class Migration(SchemaMigration): 'documents.document': { 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'750a3848-39cf-45a5-9a96-e948d09833d7'", 'max_length': '48', 'blank': 'True'}) }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0009_add_comment_field.py b/apps/documents/migrations/0009_add_comment_field.py index 2010270407..51a3b16790 100644 --- a/apps/documents/migrations/0009_add_comment_field.py +++ b/apps/documents/migrations/0009_add_comment_field.py @@ -74,14 +74,14 @@ class Migration(SchemaMigration): 'documents.document': { 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'123068ef-26d2-45bb-8933-cb6818cd87e4'", 'max_length': '48', 'blank': 'True'}) }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0010_auto__chg_field_document_date_added.py b/apps/documents/migrations/0010_auto__chg_field_document_date_added.py index 6220ef13ad..3408618acf 100644 --- a/apps/documents/migrations/0010_auto__chg_field_document_date_added.py +++ b/apps/documents/migrations/0010_auto__chg_field_document_date_added.py @@ -74,14 +74,14 @@ class Migration(SchemaMigration): 'documents.document': { 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0011_auto__add_field_documentversion_signature_state.py b/apps/documents/migrations/0011_auto__add_field_documentversion_signature_state.py index 54a039b91f..d58503615d 100644 --- a/apps/documents/migrations/0011_auto__add_field_documentversion_signature_state.py +++ b/apps/documents/migrations/0011_auto__add_field_documentversion_signature_state.py @@ -74,14 +74,14 @@ class Migration(SchemaMigration): 'documents.document': { 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/migrations/0012_auto__add_field_documentversion_signature_file.py b/apps/documents/migrations/0012_auto__add_field_documentversion_signature_file.py index 2938016090..08aff6d53d 100644 --- a/apps/documents/migrations/0012_auto__add_field_documentversion_signature_file.py +++ b/apps/documents/migrations/0012_auto__add_field_documentversion_signature_file.py @@ -74,14 +74,14 @@ class Migration(SchemaMigration): 'documents.document': { 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) }, 'documents.documentpage': { 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, - 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), diff --git a/apps/documents/models.py b/apps/documents/models.py index 25cb703d22..d05737632a 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -83,7 +83,7 @@ class Document(models.Model): ''' uuid = models.CharField(max_length=48, blank=True, editable=False) document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'), null=True, blank=True) - description = models.TextField(blank=True, null=True, verbose_name=_(u'description'), db_index=True) + description = models.TextField(blank=True, null=True, verbose_name=_(u'description')) date_added = models.DateTimeField(verbose_name=_(u'added'), db_index=True, editable=False) tags = TaggableManager() @@ -598,10 +598,10 @@ class DocumentPage(models.Model): Model that describes a document version page including it's content ''' # New parent field - document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'))#, null=True, blank=True) # TODO: Remove these after datamigration + document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version')) # Unchanged fields - content = models.TextField(blank=True, null=True, verbose_name=_(u'content'), db_index=True) + content = models.TextField(blank=True, null=True, verbose_name=_(u'content')) page_label = models.CharField(max_length=32, blank=True, null=True, verbose_name=_(u'page label')) page_number = models.PositiveIntegerField(default=1, editable=False, verbose_name=_(u'page number'), db_index=True) From 37dc4187740b718c53c606de30c40153a7d60732 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 13:01:00 -0400 Subject: [PATCH 062/484] Updated the FAQ regarding the db_index issue --- docs/faq.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/faq.rst b/docs/faq.rst index 241e76b4a2..2a125b02e1 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -104,7 +104,6 @@ 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 From 7c179f2e9061538c2bcb75ccdab3bb32f6246660 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 13 Dec 2011 13:02:32 -0400 Subject: [PATCH 063/484] Update changelog --- docs/changelog.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index df1652937f..d06b77d2d2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,7 +1,9 @@ Version 0.12 ------------ +* Statistics fixes * Italian translation by SeeOpen.IT (www.seeopen.it, info@seeopen.it) - +* Removed the 'db_index' argument from Text fields definition and + migrations as it was causing error messages for MySQL users. Version 0.11.1 -------------- From ac4498de125883a08fe9080c158c3a41ab9a047a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 14 Dec 2011 09:10:34 -0400 Subject: [PATCH 064/484] Add support for classes --- apps/acls/widgets.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/acls/widgets.py b/apps/acls/widgets.py index c35501df58..e2a57823e2 100644 --- a/apps/acls/widgets.py +++ b/apps/acls/widgets.py @@ -5,6 +5,8 @@ from django.forms.util import flatatt from django.utils.html import conditional_escape from django.utils.encoding import force_unicode from django.contrib.contenttypes.models import ContentType +from django.db.models.base import ModelBase +from django.template.defaultfilters import capfirst from acls.literals import CONTENT_TYPE_ICON_MAP @@ -14,13 +16,15 @@ def content_type_icon(content_type): def object_w_content_type_icon(obj): - content_type = ContentType.objects.get_for_model(obj) - - ct_fullname = '%s.%s' % (content_type.app_label, content_type.name) - - if ct_fullname == 'auth.user': - label = obj.get_full_name() - else: - label = unicode(obj) - - return mark_safe('%s%s' % (content_type_icon(content_type), label)) + content_type = ContentType.objects.get_for_model(obj) + + ct_fullname = '%s.%s' % (content_type.app_label, content_type.name) + if isinstance(obj, ModelBase): + label = getattr(obj._meta, 'verbose_name_plural', unicode(content_type)) + else: + if ct_fullname == 'auth.user': + label = obj.get_full_name() + else: + label = unicode(obj) + + return mark_safe('%s%s' % (content_type_icon(content_type), capfirst(label))) From 742b934bcc312d9d229ff6e96cdc8d0e2e2b890e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 14 Dec 2011 09:10:45 -0400 Subject: [PATCH 065/484] Initial db support for default classes ACLs --- apps/acls/models.py | 92 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index d1186c9218..9e5df58ace 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -11,6 +11,7 @@ from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import get_object_or_404 +from django.db.models.base import ModelBase from permissions.models import StoredPermission @@ -42,11 +43,14 @@ class EncapsulatedObject(object): def encapsulate(cls, source_object=None, app_label=None, model=None, pk=None): if source_object: content_type = ContentType.objects.get_for_model(source_object) - elif app_label and model and pk: + elif app_label and model: try: content_type = ContentType.objects.get(app_label=app_label, model=model) source_object_model_class = content_type.model_class() - source_object = content_type.get_object_for_this_type(pk=pk) + if pk: + source_object = content_type.get_object_for_this_type(pk=pk) + else: + source_object = source_object_model_class except ContentType.DoesNotExist: #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) #raise cls.DoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) @@ -56,7 +60,12 @@ class EncapsulatedObject(object): #raise cls.DoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) raise ObjectDoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) - object_key = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) + if hasattr(source_object, 'pk'): + # Object + object_key = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) + else: + # Class + object_key = '%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model) try: return _cache[object_key] @@ -67,16 +76,33 @@ class EncapsulatedObject(object): @classmethod def get(cls, gid): - app_label, model, pk = gid.split('.') - object_key = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) + elements = gid.split('.') + if len(elements) == 3: + app_label, model, pk = elements[0], elements[1], elements[2] + object_key = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) + elif len(elements) == 2: + app_label, model = elements[0], elements[1] + pk = None + object_key = '%s.%s.%s' % (cls.__name__, app_label, model) + try: return _cache[object_key] except KeyError: - return cls.encapsulate(app_label=app_label, model=model, pk=pk) + if pk: + return cls.encapsulate(app_label=app_label, model=model, pk=pk) + else: + return cls.encapsulate(app_label=app_label, model=model) def __init__(self, source_object): + print 'source_object', source_object.__class__ self.content_type = ContentType.objects.get_for_model(source_object) - self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.name, source_object.pk) + if isinstance(source_object, ModelBase): + # Class + self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.name) + else: + # Object + self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.name, source_object.pk) + setattr(self, self.__class__.source_object_name, source_object) def __unicode__(self): @@ -101,6 +127,10 @@ class AccessObject(EncapsulatedObject): source_object_name = u'obj' +class AccessObjectClass(EncapsulatedObject): + source_object_name = u'object_class' + + class AccessEntryManager(models.Manager): def grant(self, permission, requester, obj): """ @@ -215,6 +245,54 @@ class AccessEntry(models.Model): return u'%s: %s' % (self.content_type, self.content_object) +class DefaultAccessEntryManager(models.Manager): + def get_holders_for(self, cls): + content_type = ContentType.objects.get_for_model(cls) + holder_list = [] + for access_entry in self.model.objects.filter(content_type=content_type): + entry = AccessHolder.encapsulate(access_entry.holder_object) + + if entry not in holder_list: + holder_list.append(entry) + + return holder_list + + + +class DefaultAccessEntry(models.Model): + @classmethod + def get_classes(cls): + #return _class_permissions.keys() + return [AccessObjectClass.encapsulate(cls) for cls in _class_permissions.keys()] + + permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) + + holder_type = models.ForeignKey( + ContentType, + limit_choices_to={'model__in': ('user', 'group', 'role')}, + related_name='default_access_entry_holder' + ) + holder_id = models.PositiveIntegerField() + holder_object = generic.GenericForeignKey( + ct_field='holder_type', + fk_field='holder_id' + ) + + content_type = models.ForeignKey( + ContentType, + related_name='default_access_entry_class' + ) + + objects = DefaultAccessEntryManager() + + class Meta: + verbose_name = _(u'default access entry') + verbose_name_plural = _(u'default access entries') + + def __unicode__(self): + return u'%s: %s' % (self.content_type, self.content_object) + + if sys.version_info < (2, 5): # Prior to Python 2.5, Exception was an old-style class def subclass_exception(name, parents, unused): From 7dcaa1757a9469e32f33076c5b1e0948e67003aa Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 14 Dec 2011 09:11:09 -0400 Subject: [PATCH 066/484] Initial class default ACLs views --- apps/acls/__init__.py | 11 ++++- apps/acls/urls.py | 4 ++ apps/acls/views.py | 98 ++++++++++++++++++++----------------------- 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 6753b2779b..f478d84250 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -2,8 +2,9 @@ from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_multi_item_links from permissions.models import PermissionNamespace, Permission +from project_setup.api import register_setup -from acls.models import AccessHolder +from acls.models import AccessHolder, AccessObjectClass acls_namespace = PermissionNamespace('acls', _(u'Access control lists')) @@ -15,5 +16,13 @@ acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object. acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} +acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png'}#, 'permissions': [ACLS_EDIT_ACL]} +acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} + register_links(AccessHolder, [acl_detail]) register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) + +register_setup(acl_setup_valid_classes) +register_links(['acl_setup_valid_classes', 'acl_class_acl_list',], [acl_setup_valid_classes], menu_name='sidebar') + +register_links(AccessObjectClass, [acl_class_acl_list]) diff --git a/apps/acls/urls.py b/apps/acls/urls.py index 2f70970766..13de21e23f 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -8,4 +8,8 @@ urlpatterns = patterns('acls.views', url(r'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), url(r'^multiple/revoke/$', 'acl_revoke', (), 'acl_multiple_revoke'), + + url(r'^class/setup/$', 'acl_setup_valid_classes', (), 'acl_setup_valid_classes'), + #url(r'^class/list_for/(?P[-\w]+)/(?P[-\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), + url(r'^class/list_for/(?P[.\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), ) diff --git a/apps/acls/views.py b/apps/acls/views.py index 6bad2858c7..b3ff2cbcae 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -9,7 +9,6 @@ from django.template import RequestContext from django.contrib import messages from django.views.generic.list_detail import object_list 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.core.exceptions import ObjectDoesNotExist @@ -20,7 +19,8 @@ from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL -from acls.models import AccessEntry, AccessObject, AccessHolder +from acls.models import (AccessEntry, AccessObject, AccessHolder, + DefaultAccessEntry, AccessObjectClass) from acls.widgets import object_w_content_type_icon from acls.forms import HolderSelectionForm @@ -44,7 +44,7 @@ def acl_list_for(request, obj, extra_context=None): 'extra_columns': [ {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, - ], + ], 'hide_object': True, 'access_object': AccessObject.encapsulate(obj) } @@ -264,55 +264,6 @@ def acl_revoke(request): return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) -''' -def get_role_members(role): - 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])] - - -def get_non_role_members(role): - #non members = all users - members - staff - super users - 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) - - -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 - - -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() - -def role_members(request, role_id): - 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)), - 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, - right_list_title=_(u'members of role: %s') % role, - extra_context={ - 'object': role, - 'object_name': _(u'role'), - } - ) -''' - def acl_new_holder_for(request, obj, extra_context=None): Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) @@ -340,4 +291,45 @@ def acl_new_holder_for(request, obj, extra_context=None): return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) - + + +def acl_setup_valid_classes(request): + #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) + + logger.debug('DefaultAccessEntry.get_classes(): %s' % DefaultAccessEntry.get_classes()) + + context = { + #'object_list': [AccessObjectClass.encapsulate(cls) for cls in DefaultAccessEntry.get_classes()], + 'object_list': DefaultAccessEntry.get_classes(), + 'title': _(u'default access control lists'), + #'hide_links': True, + 'extra_columns': [ + {'name': _(u'class'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, + ], + 'hide_object': True, + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def acl_class_acl_list(request, access_object_class_gid): + #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) + + access_object_class = AccessObjectClass.get(gid=access_object_class_gid) + context = { + 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), + 'title': _(u'default access control lists for: %s' % access_object_class.source_object._meta.verbose_name_plural), + #'multi_select_as_buttons': True, + #'hide_links': True, + #'extra_columns': [ + #{'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, + #{'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, + # ], + #'hide_object': True, + #'access_object': AccessObject.encapsulate(ct) + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + From 00e51466863e803ffb22e093d4aea417d33decb5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 14 Dec 2011 09:11:43 -0400 Subject: [PATCH 067/484] Add acl app static media directory --- apps/acls/static/images/icons/lock.png | Bin 0 -> 1503 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/acls/static/images/icons/lock.png diff --git a/apps/acls/static/images/icons/lock.png b/apps/acls/static/images/icons/lock.png new file mode 100644 index 0000000000000000000000000000000000000000..ceebba9df33d7126686a7327bc3b58ab7e456b03 GIT binary patch literal 1503 zcmV<51t9u~P)P7F7Zclv5!| zN!v6JlSfl0O+h5i!+Cja@9yx=?8ZscICdN{_Q+$;?9BIn|M&m@SYnJ}eUl^!X_|cD z;+H2B#r1(KE49Gtv!-SC8p-4r@11_<3VpTGZLt14DO&(FD_V=vS96&SnF^g)G{MH{SFeYiOKqYG^=3MLEXC zCvf{tPYSH6sVFTeMqOT$bg;(C17*H%eUauGNcpQ<)H2eqlqpj^l%rDIM6M+5nd}2EQ7z z(DY^MdRhxJ0PqsS!Sa1&n3|4YYHAwyM@BBw;oUShN`1oVqoGi!dw6)5<_5)smT5qO z6y$qsN^vHQ2tU({i!G7R5e|ocq2DK|FFO8BIOECjvGC8_MT(-31{O#oRz{XH0gw#C z%CL@v;8nwX2%UCSNbA#ApI{;u11AGe(fV1HoZfvxa z&*^&HVJor10Ja4nVe-=zN;rx=wiV4b$}xN{Zpvak?{Nd$2e4$gVaje8Qa%=w8Zxif zU?>GJzL^HX|U;|hqW9; zwzVLSBv)0`^b+Q7e2jl5MzOTGAXpGgkjf=l#D;S$6QCF+Dn^H^o&xxa%TQQSiK52i z1mJoV-;;VY+f1kl1sf!IQocXXKnE(R!$ZAYP*s_#pyZTd2Gd{&9Brm-X$m014FrZI zbsCFk(6*9_C4)c10TA^MM*qSxF~AMx06cCL-F->?(PL-W=juIZs&xxsJoYtrJ_?Be zAMpqy2E$@$^Fi7yWpQ7T_;~YIR;L)?wSQ#r7JB-1_zLVj`M9~>jq3VVyFxk)2+hzQ z7R#X;TJ#hn^xV%6?hm9G-~haN8t4s=>cp~>ZwBsl2mq@L6oQ$$*efRh96ejd0C&OA zKo=Toy%-+0T~JM9%VhM~LN2gY8Q}1ZxTvCA2Ec_SS$6!dWk4cLsHzLqL5;3oF&hAl zb=^W=Plt$t6a)D_o*Q9UIkn75>Vj#DHvvo#TdK(m}p!rCu-`sd-kYoq;pJ zQVei6S}aEwNM=F^$!1{Q(Xj*aD7+6}2rv9*O^v7lG zZz?h1E2)5Q2USSR$SDyqJ;B1Ep8E%aHD%aQxO=m|Yfs!tY*$!h{Srb0kDwO3zyP$%-A&S?Yk2?w002ovPDHLk FV1i$&zp(%S literal 0 HcmV?d00001 From 5e76bc22f26895ae42670dd9e3d27e85f1a66236 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 14 Dec 2011 09:12:05 -0400 Subject: [PATCH 068/484] Add commented code for ideas --- apps/acls/forms.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 49a995c4e0..0ac08e923a 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -28,3 +28,52 @@ class HolderSelectionForm(forms.Form): #if holder_list: self.fields['holder_gid'].choices = [(AccessHolder.encapsulate(holder).gid, get_object_name(holder)) for holder in holder_list] + +''' +def get_role_members(role): + 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])] + + +def get_non_role_members(role): + #non members = all users - members - staff - super users + 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) + + +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 + + +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() + +def role_members(request, role_id): + 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)), + 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, + right_list_title=_(u'members of role: %s') % role, + extra_context={ + 'object': role, + 'object_name': _(u'role'), + } + ) +''' From 2d28f23b9aac6357629152864c9e7f7988e20bca Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 14:04:17 -0400 Subject: [PATCH 069/484] Update the new acls holder form label --- apps/acls/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 0ac08e923a..4235a2331d 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -10,7 +10,7 @@ from acls.models import AccessHolder class HolderSelectionForm(forms.Form): holder_gid = forms.ChoiceField( - label=_(u'Holder') + label=_(u'New holder') ) def __init__(self, *args, **kwargs): From 175a06182cbce35af99a946b80474324de1a8e54 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 14:04:58 -0400 Subject: [PATCH 070/484] Add the ACL_VIEW and ACL_EDIT permissions and document class permissions --- apps/document_acls/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index dc89ed3174..acafb97d50 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -3,11 +3,17 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import Document from navigation.api import register_links, register_multi_item_links from project_setup.api import register_setup -from acls import ACLS_VIEW_ACL +from acls import ACLS_VIEW_ACL, ACLS_EDIT_ACL +from acls.models import class_permissions acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -document_new_holder = {'text': _(u'New holder'), 'view': 'document_new_holder', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +document_new_holder = {'text': _(u'New holder'), 'view': 'document_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} register_links(Document, [acl_list], menu_name='form_header') register_links(['document_acl_list', 'document_new_holder'], [document_new_holder], menu_name='sidebar') + +class_permissions(Document, [ + ACLS_VIEW_ACL, + ACLS_EDIT_ACL +]) From 85f05ebdcf37050effd28eb6d23294fee52316a4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 14:05:31 -0400 Subject: [PATCH 071/484] Add the tag append and tag remover permissions and document class permissions --- apps/tags/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 6e8df5bc15..07f68dac63 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -5,6 +5,7 @@ from navigation.api import register_links, register_top_menu, \ from permissions.models import PermissionNamespace, Permission from common.utils import encapsulate from documents.models import Document +from acls.models import class_permissions from taggit.models import Tag @@ -55,3 +56,14 @@ 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_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, +#]) From 17b44387c9465432ffab62637397d15c4eb80524 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 14:06:12 -0400 Subject: [PATCH 072/484] Improve enclapsulated class unicode method, add grant and revoke method to the DefaultAccessEntry class --- apps/acls/models.py | 63 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index 9e5df58ace..6251f07b31 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -12,6 +12,7 @@ from django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import get_object_or_404 from django.db.models.base import ModelBase +from django.template.defaultfilters import capfirst from permissions.models import StoredPermission @@ -94,8 +95,9 @@ class EncapsulatedObject(object): return cls.encapsulate(app_label=app_label, model=model) def __init__(self, source_object): - print 'source_object', source_object.__class__ self.content_type = ContentType.objects.get_for_model(source_object) + self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.name) + if isinstance(source_object, ModelBase): # Class self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.name) @@ -106,7 +108,16 @@ class EncapsulatedObject(object): setattr(self, self.__class__.source_object_name, source_object) def __unicode__(self): - return unicode(getattr(self, self.__class__.source_object_name, None)) + if isinstance(self.source_object, ModelBase): + return capfirst(unicode(self.source_object._meta.verbose_name_plural)) + + elif self.ct_fullname == 'auth.user': + return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name()) + else: + #label = unicode(obj) + return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object) + + #return unicode(getattr(self, self.__class__.source_object_name, None)) def __repr__(self): return self.__unicode__() @@ -128,14 +139,14 @@ class AccessObject(EncapsulatedObject): class AccessObjectClass(EncapsulatedObject): - source_object_name = u'object_class' + source_object_name = u'cls' class AccessEntryManager(models.Manager): def grant(self, permission, requester, obj): - """ + ''' Grant a permission (what), (to) a requester, (on) a specific object - """ + ''' access_entry, created = self.model.objects.get_or_create( permission=permission, holder_type=ContentType.objects.get_for_model(requester), @@ -257,12 +268,52 @@ class DefaultAccessEntryManager(models.Manager): return holder_list + def has_accesses(self, permission, requester, cls): + if isinstance(requester, User): + if requester.is_superuser or requester.is_staff: + return True + + try: + access_entry = self.model.objects.get( + permission=permission.get_stored_permission(), + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(cls), + ) + return True + except self.model.DoesNotExist: + return False + + def grant(self, permission, requester, cls): + ''' + Grant a permission (what), (to) a requester, (on) a specific class + ''' + access_entry, created = self.model.objects.get_or_create( + permission=permission, + holder_type=ContentType.objects.get_for_model(requester), + holder_id=requester.pk, + content_type=ContentType.objects.get_for_model(cls), + ) + return created + + def revoke(self, permission, holder, cls): + try: + access_entry = self.model.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(holder), + holder_id=holder.pk, + content_type=ContentType.objects.get_for_model(cls), + ) + access_entry.delete() + return True + except self.model.DoesNotExist: + return False + class DefaultAccessEntry(models.Model): @classmethod def get_classes(cls): - #return _class_permissions.keys() return [AccessObjectClass.encapsulate(cls) for cls in _class_permissions.keys()] permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) From 574ef3c9c88f5598c794f128d435546d8eb00e5c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 14:07:06 -0400 Subject: [PATCH 073/484] Update the default class acl setup views to a working state --- apps/acls/__init__.py | 12 ++- apps/acls/urls.py | 8 +- apps/acls/views.py | 241 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 255 insertions(+), 6 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index f478d84250..a8554290d6 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -11,18 +11,28 @@ acls_namespace = PermissionNamespace('acls', _(u'Access control lists')) ACLS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit ACLs')) ACLS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View ACLs')) +ACLS_CLASS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit class default ACLs')) +ACLS_CLASS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View class default ACLs')) + + acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png'}#, 'permissions': [ACLS_EDIT_ACL]} +acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package'}#, 'permissions': [ACLS_EDIT_ACL]} acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} +acl_class_new_holder_for = {'text': _(u'New holder'), 'view': 'acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user'}#, 'permissions': [ACLS_VIEW_ACL]} +acl_class_grant = {'text': _(u'grant'), 'view': 'acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} +acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} register_links(AccessHolder, [acl_detail]) register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) register_setup(acl_setup_valid_classes) -register_links(['acl_setup_valid_classes', 'acl_class_acl_list',], [acl_setup_valid_classes], menu_name='sidebar') +register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acls_class_acl_detail'], [acl_class_list], menu_name='sidebar') register_links(AccessObjectClass, [acl_class_acl_list]) +register_links(AccessObjectClass, [acl_class_new_holder_for]) +register_multi_item_links(['acls_class_acl_detail'], [acl_class_grant, acl_class_revoke]) diff --git a/apps/acls/urls.py b/apps/acls/urls.py index 13de21e23f..2ee785071e 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -9,7 +9,13 @@ urlpatterns = patterns('acls.views', url(r'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), url(r'^multiple/revoke/$', 'acl_revoke', (), 'acl_multiple_revoke'), - url(r'^class/setup/$', 'acl_setup_valid_classes', (), 'acl_setup_valid_classes'), + url(r'^class/$', 'acl_setup_valid_classes', (), 'acl_setup_valid_classes'), #url(r'^class/list_for/(?P[-\w]+)/(?P[-\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), + url(r'^class/details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acls_class_acl_detail', (), 'acls_class_acl_detail'), url(r'^class/list_for/(?P[.\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), + url(r'^class/holder/new/(?P[.\w]+)/$', 'acl_class_new_holder_for', (), 'acl_class_new_holder_for'), + + url(r'^class/multiple/grant/$', 'acl_class_multiple_grant', (), 'acl_class_multiple_grant'), + url(r'^class/multiple/revoke/$', 'acl_class_multiple_revoke', (), 'acl_class_multiple_revoke'), + ) diff --git a/apps/acls/views.py b/apps/acls/views.py index b3ff2cbcae..25d737b86b 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -77,7 +77,7 @@ def acl_detail(request, access_object_gid, holder_object_gid): { 'name': u'generic_list_subtemplate.html', 'context': { - 'title': _(u'permissions held by: %s for %s' % (holder, access_object)), + 'title': _(u'permissions available to: %s for %s' % (holder, access_object)), 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': 'namespace'}, @@ -293,15 +293,16 @@ def acl_new_holder_for(request, obj, extra_context=None): context_instance=RequestContext(request)) +# Setup views def acl_setup_valid_classes(request): #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) - logger.debug('DefaultAccessEntry.get_classes(): %s' % DefaultAccessEntry.get_classes()) context = { #'object_list': [AccessObjectClass.encapsulate(cls) for cls in DefaultAccessEntry.get_classes()], 'object_list': DefaultAccessEntry.get_classes(), - 'title': _(u'default access control lists'), + #'title': _(u'default access control lists'), + 'title': _(u'classes'), #'hide_links': True, 'extra_columns': [ {'name': _(u'class'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, @@ -319,7 +320,7 @@ def acl_class_acl_list(request, access_object_class_gid): access_object_class = AccessObjectClass.get(gid=access_object_class_gid) context = { 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), - 'title': _(u'default access control lists for: %s' % access_object_class.source_object._meta.verbose_name_plural), + 'title': _(u'default access control lists for class: %s') % access_object_class, #'multi_select_as_buttons': True, #'hide_links': True, #'extra_columns': [ @@ -328,8 +329,240 @@ def acl_class_acl_list(request, access_object_class_gid): # ], #'hide_object': True, #'access_object': AccessObject.encapsulate(ct) + 'object': access_object_class, } return render_to_response('generic_list.html', context, context_instance=RequestContext(request)) + +def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): + #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) + + try: + holder = AccessHolder.get(gid=holder_object_gid) + access_object_class = AccessObjectClass.get(gid=access_object_class_gid) + except ObjectDoesNotExist: + raise Http404 + + permission_list = list(access_object_class.get_class_permissions()) + #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) + subtemplates_list = [ + { + 'name': u'generic_list_subtemplate.html', + 'context': { + 'title': _(u'permissions available to: %s for class %s' % (holder, access_object_class)), + 'object_list': permission_list, + 'extra_columns': [ + {'name': _(u'namespace'), 'attribute': 'namespace'}, + {'name': _(u'label'), 'attribute': 'label'}, + { + 'name':_(u'has permission'), + 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_accesses(x, holder.source_object, access_object_class.source_object))) + }, + ], + #'hide_link': True, + 'hide_object': True, + } + }, + ] + + return render_to_response('generic_detail.html', { + 'object': access_object_class, + 'subtemplates_list': subtemplates_list, + 'multi_select_as_buttons': True, + 'multi_select_item_properties': { + 'permission_pk': lambda x: x.pk, + 'holder_gid': lambda x: holder.gid, + 'access_object_class_gid': lambda x: access_object_class.gid, + }, + }, context_instance=RequestContext(request)) + + +def acl_class_new_holder_for(request, access_object_class_gid): + #Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + access_object_class = AccessObjectClass.get(gid=access_object_class_gid) + + if request.method == 'POST': + form = HolderSelectionForm(request.POST) + if form.is_valid(): + try: + #access_object = AccessObject.encapsulate(access_object_class) + access_holder = AccessHolder.get(form.cleaned_data['holder_gid']) + + return HttpResponseRedirect(reverse('acls_class_acl_detail', args=[access_object_class.gid, access_holder.gid])) + except ObjectDoesNotExist: + raise Http404 + else: + form = HolderSelectionForm() + + context = { + 'form': form, + 'title': _(u'add new holder for class: %s') % unicode(access_object_class), + 'object': access_object_class, + 'submit_label': _(u'Select'), + 'submit_icon_famfam': 'tick' + } + + return render_to_response('generic_form.html', context, + context_instance=RequestContext(request)) + + +def acl_class_multiple_grant(request): + #Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + items_property_list = loads(request.GET.get('items_property_list', [])) + post_action_redirect = None + + 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))) + + items = {} + title_suffix = [] + navigation_object = None + navigation_object_count = 0 + + for item_properties in items_property_list: + try: + permission = Permission.objects.get({'pk': item_properties['permission_pk']}) + except Permission.DoesNotExist: + raise Http404 + try: + requester = AccessHolder.get(gid=item_properties['holder_gid']) + access_object_class = AccessObjectClass.get(gid=item_properties['access_object_class_gid']) + except ObjectDoesNotExist: + raise Http404 + + items.setdefault(requester, {}) + items[requester].setdefault(access_object_class, []) + items[requester][access_object_class].append(permission) + navigation_object = access_object_class + navigation_object_count += 1 + + for requester, obj_ps in items.items(): + for obj, ps in obj_ps.items(): + title_suffix.append(_(u' and ').join([u'"%s"' % unicode(p) for p in ps])) + title_suffix.append(_(u' for %s') % obj) + title_suffix.append(_(u' to %s') % requester) + + if len(items_property_list) == 1: + title_prefix = _(u'Are you sure you wish to grant the permission %(title_suffix)s?') + else: + title_prefix = _(u'Are you sure you wish to grant the permissions %(title_suffix)s?') + + if request.method == 'POST': + for requester, object_permissions in items.items(): + for obj, permissions in object_permissions.items(): + for permission in permissions: + if DefaultAccessEntry.objects.grant(permission, requester.source_object, obj.source_object): + messages.success(request, _(u'Permission "%(permission)s" granted to %(requester)s for %(object)s.') % { + 'permission': permission, + 'requester': requester, + 'object': obj + }) + else: + messages.warning(request, _(u'%(requester)s, already had the permission "%(permission)s" granted for %(object)s.') % { + 'requester': requester, + 'permission': permission, + 'object': obj, + }) + + return HttpResponseRedirect(next) + + context = { + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'key_add.png', + } + + context['title'] = title_prefix % { + 'title_suffix': u''.join(title_suffix), + } + + logger.debug('navigation_object_count: %d' % navigation_object_count) + logger.debug('navigation_object: %s' % navigation_object) + if navigation_object_count == 1: + context['object'] = navigation_object + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + + +def acl_class_multiple_revoke(request): + #Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + items_property_list = loads(request.GET.get('items_property_list', [])) + post_action_redirect = None + + 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))) + + items = {} + title_suffix = [] + navigation_object = None + navigation_object_count = 0 + + for item_properties in items_property_list: + try: + permission = Permission.objects.get({'pk': item_properties['permission_pk']}) + except Permission.DoesNotExist: + raise Http404 + try: + requester = AccessHolder.get(gid=item_properties['holder_gid']) + access_object_class = AccessObjectClass.get(gid=item_properties['access_object_class_gid']) + except ObjectDoesNotExist: + raise Http404 + + items.setdefault(requester, {}) + items[requester].setdefault(access_object_class, []) + items[requester][access_object_class].append(permission) + navigation_object = access_object_class + navigation_object_count += 1 + + for requester, obj_ps in items.items(): + for obj, ps in obj_ps.items(): + title_suffix.append(_(u' and ').join([u'"%s"' % unicode(p) for p in ps])) + title_suffix.append(_(u' for %s') % obj) + title_suffix.append(_(u' from %s') % requester) + + if len(items_property_list) == 1: + title_prefix = _(u'Are you sure you wish to revoke the permission %(title_suffix)s?') + else: + title_prefix = _(u'Are you sure you wish to revoke the permissions %(title_suffix)s?') + + if request.method == 'POST': + for requester, object_permissions in items.items(): + for obj, permissions in object_permissions.items(): + for permission in permissions: + if DefaultAccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): + messages.success(request, _(u'Permission "%(permission)s" revoked of %(requester)s for %(object)s.') % { + 'permission': permission, + 'requester': requester, + 'object': obj + }) + else: + messages.warning(request, _(u'%(requester)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { + 'requester': requester, + 'permission': permission, + 'object': obj, + }) + + return HttpResponseRedirect(next) + + context = { + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'key_delete.png', + } + + context['title'] = title_prefix % { + 'title_suffix': u''.join(title_suffix), + } + + logger.debug('navigation_object_count: %d' % navigation_object_count) + logger.debug('navigation_object: %s' % navigation_object) + if navigation_object_count == 1: + context['object'] = navigation_object + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) From 67485f82a97f8570ba3e45c148a0b765e40d19e4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 14:07:38 -0400 Subject: [PATCH 074/484] Improve the usability of the new holder form By using more descriptive texts --- apps/document_acls/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 505770fa99..5f723f166e 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -24,5 +24,7 @@ def document_new_holder(request, document_id): document, extra_context={ 'object': document, + 'submit_label': _(u'Select'), + 'submit_icon_famfam': 'tick' } ) From bdc0a965b47d7d3899beacc922208f280367d416 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 16:41:31 -0400 Subject: [PATCH 075/484] Fix acls_class_acl_detail view --- apps/acls/__init__.py | 11 +++++++---- apps/acls/urls.py | 2 -- apps/acls/views.py | 41 +++++++++++++++++------------------------ 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index a8554290d6..c5ba0faf6a 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -4,16 +4,16 @@ from navigation.api import register_links, register_multi_item_links from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup -from acls.models import AccessHolder, AccessObjectClass +from acls.models import AccessHolder, AccessObjectClass, ClassAccessHolder acls_namespace = PermissionNamespace('acls', _(u'Access control lists')) +acls_setup_namespace = PermissionNamespace('acls_setup', _(u'Access control lists')) ACLS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit ACLs')) ACLS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View ACLs')) -ACLS_CLASS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit class default ACLs')) -ACLS_CLASS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View class default ACLs')) - +ACLS_CLASS_EDIT_ACL = Permission.objects.register(acls_setup_namespace, 'acl_class_edit', _(u'Edit class default ACLs')) +ACLS_CLASS_VIEW_ACL = Permission.objects.register(acls_setup_namespace, 'acl_class_view', _(u'View class default ACLs')) acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} @@ -23,6 +23,7 @@ acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'ke acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png'}#, 'permissions': [ACLS_EDIT_ACL]} acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package'}#, 'permissions': [ACLS_EDIT_ACL]} acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} +acls_class_acl_detail = {'text': _(u'edit'), 'view': 'acls_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_class_new_holder_for = {'text': _(u'New holder'), 'view': 'acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user'}#, 'permissions': [ACLS_VIEW_ACL]} acl_class_grant = {'text': _(u'grant'), 'view': 'acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} @@ -33,6 +34,8 @@ register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) register_setup(acl_setup_valid_classes) register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acls_class_acl_detail'], [acl_class_list], menu_name='sidebar') +register_links(ClassAccessHolder, [acls_class_acl_detail]) + register_links(AccessObjectClass, [acl_class_acl_list]) register_links(AccessObjectClass, [acl_class_new_holder_for]) register_multi_item_links(['acls_class_acl_detail'], [acl_class_grant, acl_class_revoke]) diff --git a/apps/acls/urls.py b/apps/acls/urls.py index 2ee785071e..1ef00855a7 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -3,14 +3,12 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('acls.views', url(r'^new_holder_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_new_holder_for', (), 'acl_new_holder_for'), url(r'^list_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_list', (), 'acl_list'), - #url(r'^object/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/holder/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_detail', (), 'acl_detail'), url(r'^details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acl_detail', (), 'acl_detail'), url(r'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), url(r'^multiple/revoke/$', 'acl_revoke', (), 'acl_multiple_revoke'), url(r'^class/$', 'acl_setup_valid_classes', (), 'acl_setup_valid_classes'), - #url(r'^class/list_for/(?P[-\w]+)/(?P[-\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), url(r'^class/details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acls_class_acl_detail', (), 'acls_class_acl_detail'), url(r'^class/list_for/(?P[.\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), url(r'^class/holder/new/(?P[.\w]+)/$', 'acl_class_new_holder_for', (), 'acl_class_new_holder_for'), diff --git a/apps/acls/views.py b/apps/acls/views.py index 25d737b86b..ac8c72ea91 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -18,9 +18,10 @@ from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template -from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL +from acls import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, + ACLS_CLASS_VIEW_ACL) from acls.models import (AccessEntry, AccessObject, AccessHolder, - DefaultAccessEntry, AccessObjectClass) + DefaultAccessEntry, AccessObjectClass, ClassAccessHolder) from acls.widgets import object_w_content_type_icon from acls.forms import HolderSelectionForm @@ -295,15 +296,12 @@ def acl_new_holder_for(request, obj, extra_context=None): # Setup views def acl_setup_valid_classes(request): - #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL, ACLS_CLASS_EDIT_ACL]) logger.debug('DefaultAccessEntry.get_classes(): %s' % DefaultAccessEntry.get_classes()) context = { - #'object_list': [AccessObjectClass.encapsulate(cls) for cls in DefaultAccessEntry.get_classes()], 'object_list': DefaultAccessEntry.get_classes(), - #'title': _(u'default access control lists'), 'title': _(u'classes'), - #'hide_links': True, 'extra_columns': [ {'name': _(u'class'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, ], @@ -315,21 +313,18 @@ def acl_setup_valid_classes(request): def acl_class_acl_list(request, access_object_class_gid): - #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL, ACLS_CLASS_EDIT_ACL]) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) context = { 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), 'title': _(u'default access control lists for class: %s') % access_object_class, - #'multi_select_as_buttons': True, - #'hide_links': True, - #'extra_columns': [ - #{'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, - #{'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, - # ], - #'hide_object': True, - #'access_object': AccessObject.encapsulate(ct) - 'object': access_object_class, + 'extra_columns': [ + {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, + {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(DefaultAccessEntry.objects.get_holder_permissions_for(access_object_class.source_object, x.source_object)))}, + ], + 'hide_object': True, + 'access_object_class': access_object_class, } return render_to_response('generic_list.html', context, @@ -337,8 +332,7 @@ def acl_class_acl_list(request, access_object_class_gid): def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): - #Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) - + Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL, ACLS_CLASS_EDIT_ACL]) try: holder = AccessHolder.get(gid=holder_object_gid) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) @@ -380,21 +374,20 @@ def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): def acl_class_new_holder_for(request, access_object_class_gid): - #Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) if request.method == 'POST': form = HolderSelectionForm(request.POST) if form.is_valid(): try: - #access_object = AccessObject.encapsulate(access_object_class) - access_holder = AccessHolder.get(form.cleaned_data['holder_gid']) + access_holder = ClassAccessHolder.get(form.cleaned_data['holder_gid']) return HttpResponseRedirect(reverse('acls_class_acl_detail', args=[access_object_class.gid, access_holder.gid])) except ObjectDoesNotExist: raise Http404 else: - form = HolderSelectionForm() + form = HolderSelectionForm(current_holders=DefaultAccessEntry.objects.get_holders_for(access_object_class)) context = { 'form': form, @@ -409,7 +402,7 @@ def acl_class_new_holder_for(request, access_object_class_gid): def acl_class_multiple_grant(request): - #Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) post_action_redirect = None @@ -489,7 +482,7 @@ def acl_class_multiple_grant(request): def acl_class_multiple_revoke(request): - #Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) post_action_redirect = None From 1f7b1bc9046a6e878b507c4edfa5db1ee7432c87 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 16:42:19 -0400 Subject: [PATCH 076/484] Update new holder form to user HTML option groups and remove class permission current holders --- apps/acls/forms.py | 80 ++++++++++++---------------------------------- 1 file changed, 21 insertions(+), 59 deletions(-) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 4235a2331d..0e4b68098c 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -8,72 +8,34 @@ from common.utils import generate_choices_w_labels, encapsulate, get_object_name from acls.models import AccessHolder +def _as_choice_list(holders): + return sorted([(AccessHolder.encapsulate(holder).gid, get_object_name(holder, display_object_type=False)) for holder in holders], key=lambda x: x[1]) + class HolderSelectionForm(forms.Form): holder_gid = forms.ChoiceField( label=_(u'New holder') ) def __init__(self, *args, **kwargs): + current_holders = kwargs.pop('current_holders', []) + if current_holders: + current_holders = [holder.source_object for holder in current_holders] + 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) - users = set(User.objects.filter(is_active=True)) - set(staff_users) - set(super_users) - roles = set(Role.objects.all()) - #groups = set(Group.objects.exclude(pk__in=[member.pk for member in get_role_members(role)])) - groups = set(Group.objects.all()) - holder_list = list(users | groups | roles) + users = set(User.objects.filter(is_active=True)) - set(staff_users) - set(super_users) - set(current_holders) + roles = set(Role.objects.all()) - set(current_holders) + groups = set(Group.objects.all()) - set(current_holders) - #holder_list = kwargs.pop('holder_list', None) + non_holder_list = [] + if users: + non_holder_list.append((_(u'Users'), _as_choice_list(list(users)))) + + if groups: + non_holder_list.append((_(u'Groups'), _as_choice_list(list(groups)))) + + if roles: + non_holder_list.append((_(u'Roles'), _as_choice_list(list(roles)))) + super(HolderSelectionForm, self).__init__(*args, **kwargs) - #if holder_list: - self.fields['holder_gid'].choices = [(AccessHolder.encapsulate(holder).gid, get_object_name(holder)) for holder in holder_list] - - -''' -def get_role_members(role): - 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])] - - -def get_non_role_members(role): - #non members = all users - members - staff - super users - 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) - - -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 - - -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() - -def role_members(request, role_id): - 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)), - 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, - right_list_title=_(u'members of role: %s') % role, - extra_context={ - 'object': role, - 'object_name': _(u'role'), - } - ) -''' + self.fields['holder_gid'].choices = non_holder_list From 79428117b8f2aa17cb0621976173bd55e5707fc3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 16:43:28 -0400 Subject: [PATCH 077/484] Add new ObjectEncapsulation subclass ClassAccessHolder --- apps/acls/models.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index 6251f07b31..ec360c16de 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -142,6 +142,10 @@ class AccessObjectClass(EncapsulatedObject): source_object_name = u'cls' +class ClassAccessHolder(EncapsulatedObject): + source_object_name = u'class_holder' + + class AccessEntryManager(models.Manager): def grant(self, permission, requester, obj): ''' @@ -258,10 +262,13 @@ class AccessEntry(models.Model): class DefaultAccessEntryManager(models.Manager): def get_holders_for(self, cls): + if isinstance(cls, EncapsulatedObject): + cls = cls.source_object + content_type = ContentType.objects.get_for_model(cls) holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type): - entry = AccessHolder.encapsulate(access_entry.holder_object) + entry = ClassAccessHolder.encapsulate(access_entry.holder_object) if entry not in holder_list: holder_list.append(entry) @@ -309,6 +316,14 @@ class DefaultAccessEntryManager(models.Manager): except self.model.DoesNotExist: return False + def get_holder_permissions_for(self, cls, holder): + if isinstance(holder, User): + if holder.is_superuser or holder.is_staff: + return Permission.objects.all() + + holder_type = ContentType.objects.get_for_model(holder) + content_type = ContentType.objects.get_for_model(cls) + return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=holder_type, holder_id=holder.pk)] class DefaultAccessEntry(models.Model): From 84410ac98e6065d96d5a39686cfec16676b847ab Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 16:44:01 -0400 Subject: [PATCH 078/484] Reenable label field until DB migration are calculated --- apps/permissions/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index fdcd26b45c..99e4179cf9 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -112,7 +112,7 @@ 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')) + label = models.CharField(max_length=96, verbose_name=_(u'label')) # TODO: Create migration objects = StoredPermissionManager() From 8baa84f96b494e0d24245b4389c2ea82184d7971 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:44:04 -0400 Subject: [PATCH 079/484] Add folder level access control --- apps/folders/__init__.py | 47 +++++++++++++++---- apps/folders/urls.py | 5 +- apps/folders/views.py | 98 +++++++++++++++++++++++++++++++++------- 3 files changed, 123 insertions(+), 27 deletions(-) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index e8aa591476..53f7dfb113 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -4,23 +4,40 @@ from navigation.api import register_links, register_top_menu, \ register_multi_item_links, register_sidebar_template from documents.models import Document from documents.literals import PERMISSION_DOCUMENT_VIEW +from permissions.models import PermissionNamespace, Permission +from acls.models import class_permissions from folders.models import Folder -folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user'} -folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add'} -folder_edit = {'text': _('edit'), 'view': 'folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit'} -folder_delete = {'text': _('delete'), 'view': 'folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete'} -folder_document_multiple_remove = {'text': _('remove from folder'), 'view': 'folder_document_multiple_remove', 'args': 'object.pk', 'famfam': 'delete'} -folder_view = {'text': _(u'folder documents'), 'view': 'folder_view', 'args': 'object.pk', 'famfam': 'folder_go'} -folder_add_document = {'text': _('add to a folder'), 'view': 'folder_add_document', 'args': 'object.pk', 'famfam': 'add'} +folder_namespace = PermissionNamespace('folders', _(u'Folders')) + +PERMISSION_FOLDER_LIST = Permission.objects.register(folder_namespace, 'folder_list', _(u'View all folders')) +PERMISSION_FOLDER_CREATE = Permission.objects.register(folder_namespace, 'folder_create', _(u'Create new folders')) +PERMISSION_FOLDER_EDIT = Permission.objects.register(folder_namespace, 'folder_edit', _(u'Edit new folders')) +PERMISSION_FOLDER_DELETE = Permission.objects.register(folder_namespace, 'folder_delete', _(u'Delete new folders')) +PERMISSION_FOLDER_REMOVE_DOCUMENT = Permission.objects.register(folder_namespace, 'folder_remove_document', _(u'Remove documents from folders')) +PERMISSION_FOLDER_VIEW = Permission.objects.register(folder_namespace, 'folder_view', _(u'View existing folders')) +PERMISSION_FOLDER_ADD_DOCUMENT = Permission.objects.register(folder_namespace, 'folder_add_document', _(u'Add documents to existing folders')) + +folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user', 'permissions': [PERMISSION_FOLDER_LIST]} +folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_CREATE]} +folder_edit = {'text': _('edit'), 'view': 'folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit', 'permissions': [PERMISSION_FOLDER_EDIT]} +folder_delete = {'text': _('delete'), 'view': 'folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_DELETE]} +folder_document_multiple_remove = {'text': _('remove from folder'), 'view': 'folder_document_multiple_remove', 'args': 'object.pk', 'famfam': 'delete', 'permissions': [PERMISSION_FOLDER_REMOVE_DOCUMENT]} +folder_view = {'text': _(u'folder documents'), 'view': 'folder_view', 'args': 'object.pk', 'famfam': 'folder_go', 'permissions': [PERMISSION_FOLDER_VIEW]} +folder_add_document = {'text': _('add to a folder'), 'view': 'folder_add_document', 'args': 'object.pk', 'famfam': 'add', 'permissions': [PERMISSION_FOLDER_ADD_DOCUMENT]} document_folder_list = {'text': _(u'folders'), 'view': 'document_folder_list', 'args': 'object.pk', 'famfam': 'folder_user', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'children_view_regex': [r'folder']} +folder_acl_list = {'text': _(u'ACLs'), 'view': 'folder_acl_list', 'args': 'object.pk', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} +folder_new_holder = {'text': _(u'New holder'), 'view': 'folder_new_holder', 'args': 'object.pk', 'famfam': 'user'}#, 'permissions': [ACLS_VIEW_ACL]} + register_multi_item_links(['folder_view'], [folder_document_multiple_remove]) -register_links(Folder, [folder_view, folder_edit, folder_delete]) +register_links(Folder, [folder_view, folder_edit, folder_delete, folder_acl_list]) -register_links(['folder_edit', 'folder_delete', 'folder_list', 'folder_create', 'folder_view', 'folder_document_multiple_remove'], [folder_list, folder_create], menu_name='secondary_menu') +register_links(['folder_acl_list'], [folder_new_holder], menu_name='sidebar') + +register_links(['folder_edit', 'folder_delete', 'folder_list', 'folder_create', 'folder_view', 'folder_document_multiple_remove', 'folder_acl_list', 'folder_new_holder'], [folder_list, folder_create], menu_name='secondary_menu') register_top_menu(name='folders', link={'text': _('folders'), 'famfam': 'folder_user', 'view': 'folder_list'}, children_views=['folder_list', 'folder_create', 'folder_edit', 'folder_delete', 'folder_view', 'folder_document_multiple_remove']) @@ -29,3 +46,15 @@ register_links(Document, [document_folder_list], menu_name='form_header') register_sidebar_template(['folder_list'], 'folders_help.html') register_links(['document_folder_list', 'folder_add_document'], [folder_add_document], menu_name="sidebar") + +class_permissions(Folder, [ + PERMISSION_FOLDER_LIST, + PERMISSION_FOLDER_EDIT, + PERMISSION_FOLDER_DELETE, + PERMISSION_FOLDER_VIEW, +]) + +class_permissions(Document, [ + PERMISSION_FOLDER_ADD_DOCUMENT, + PERMISSION_FOLDER_REMOVE_DOCUMENT, +]) diff --git a/apps/folders/urls.py b/apps/folders/urls.py index 26710ae0c5..46c569bc11 100644 --- a/apps/folders/urls.py +++ b/apps/folders/urls.py @@ -9,7 +9,10 @@ urlpatterns = patterns('folders.views', url(r'^(?P\d+)/$', 'folder_view', (), 'folder_view'), url(r'^(?P\d+)/remove/document/multiple/$', 'folder_document_multiple_remove', (), 'folder_document_multiple_remove'), - url(r'^document/(?P\d+)/folder/add/sidebar/$', 'folder_add_document_sidebar', (), 'folder_add_document_sidebar'), + #url(r'^document/(?P\d+)/folder/add/sidebar/$', 'folder_add_document_sidebar', (), 'folder_add_document_sidebar'), url(r'^document/(?P\d+)/folder/add/$', 'folder_add_document', (), 'folder_add_document'), url(r'^document/(?P\d+)/folder/list/$', 'document_folder_list', (), 'document_folder_list'), + + url(r'^(?P\d+)/acl/list/$', 'folder_acl_list', (), 'folder_acl_list'), + url(r'^(?P\d+)/acl/holder/new/$', 'folder_new_holder', (), 'folder_new_holder'), ) diff --git a/apps/folders/views.py b/apps/folders/views.py index 567114a430..09edaf3874 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -11,9 +11,15 @@ from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document from permissions.models import Permission from common.utils import encapsulate +from acls.models import AccessEntry, PermissionDenied +from acls.views import acl_list_for, acl_new_holder_for from folders.models import Folder, FolderDocument from folders.forms import FolderForm, AddDocumentForm +from folders import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, + PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, + PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, + PERMISSION_FOLDER_ADD_DOCUMENT) def folder_list(request, queryset=None, extra_context=None): @@ -27,16 +33,27 @@ def folder_list(request, queryset=None, extra_context=None): } if extra_context: context.update(extra_context) + + queryset = queryset if not (queryset is None) else Folder.objects.all() + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_VIEW]) + except PermissionDenied: + pass + #class_objects = AccessEntry.objects.get_allowed_class_objects(PERMISSION_FOLDER_VIEW, request.user, Folder) + #queryset = list(set(queryset) & set(class_objects)) + + context['object_list'] = queryset - return object_list( - request, - queryset=queryset if not (queryset is None) else Folder.objects.filter(user=request.user), - template_name='generic_list.html', - extra_context=context, + return render_to_response('generic_list.html', + context, + context_instance=RequestContext(request) ) def folder_create(request): + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_CREATE]) + if request.method == 'POST': form = FolderForm(request.POST) if form.is_valid(): @@ -59,8 +76,10 @@ def folder_create(request): def folder_edit(request, folder_id): folder = get_object_or_404(Folder, pk=folder_id) - if not request.user.is_staff and not request.user.is_superuser and not request.user == folder.user: - raise PermissionDenied + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_FOLDER_EDIT, request.user, folder) if request.method == 'POST': form = FolderForm(request.POST) @@ -87,8 +106,10 @@ def folder_edit(request, folder_id): def folder_delete(request, folder_id): folder = get_object_or_404(Folder, pk=folder_id) - if not request.user.is_staff and not request.user.is_superuser and not request.user == folder.user: - raise PermissionDenied + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_DELETE]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_FOLDER_DELETE, request.user, folder) post_action_redirect = reverse('folder_list') @@ -122,8 +143,10 @@ def folder_delete(request, folder_id): def folder_view(request, folder_id): folder = get_object_or_404(Folder, pk=folder_id) - if not request.user.is_staff and not request.user.is_superuser and not request.user == folder.user: - raise PermissionDenied + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_FOLDER_VIEW, request.user, folder) return render_to_response('generic_list.html', { 'object_list': [fd.document for fd in folder.folderdocument_set.all()], @@ -134,7 +157,7 @@ def folder_view(request, folder_id): 'object_name': _(u'folder'), }, context_instance=RequestContext(request)) - +''' def folder_add_document_sidebar(request, document_id): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) @@ -166,13 +189,16 @@ def folder_add_document_sidebar(request, document_id): 'document': document, 'folder': folder}) return HttpResponseRedirect(previous) - +''' def folder_add_document(request, document_id): - # TODO: merge with folder_add_document_sidebar - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_ADD_DOCUMENT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_FOLDER_ADD_DOCUMENT, 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': @@ -213,12 +239,16 @@ def folder_add_document(request, document_id): def document_folder_list(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + return folder_list( request, - queryset=Folder.objects.filter(user=request.user).filter(folderdocument__document=document), + queryset=Folder.objects.filter(folderdocument__document=document), extra_context={ 'title': _(u'folders containing: %s') % document, 'object': document, @@ -239,6 +269,15 @@ def folder_document_remove(request, folder_id, document_id=None, document_id_lis messages.error(request, _(u'Must provide at least one folder document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_REMOVE_DOCUMENT]) + except PermissionDenied: + for document in folder_documents: + try: + AccessEntry.objects.check_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, document) + except PermissionDenied: + folder_documents.remove(document) + 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', '/'))) @@ -274,3 +313,28 @@ def folder_document_remove(request, folder_id, document_id=None, document_id_lis def folder_document_multiple_remove(request, folder_id): return folder_document_remove(request, folder_id, document_id_list=request.GET.get('id_list', [])) + + +def folder_acl_list(request, folder_pk): + folder = get_object_or_404(Folder, pk=folder_pk) + return acl_list_for( + request, + folder, + extra_context={ + 'object': folder, + } + ) + + +def folder_new_holder(request, folder_pk): + folder = get_object_or_404(Folder, pk=folder_pk) + return acl_new_holder_for( + request, + folder, + extra_context={ + 'folder': folder, + 'submit_label': _(u'Select'), + 'submit_icon_famfam': 'tick', + 'object': folder, + } + ) From ec1c5d78ddf603ff5a5667fefccbda9eab885c16 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:44:23 -0400 Subject: [PATCH 080/484] Add template tag to hangle acl in navigation --- apps/acls/templatetags/__init__.py | 0 apps/acls/templatetags/acl_tags.py | 54 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 apps/acls/templatetags/__init__.py create mode 100644 apps/acls/templatetags/acl_tags.py diff --git a/apps/acls/templatetags/__init__.py b/apps/acls/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/acls/templatetags/acl_tags.py b/apps/acls/templatetags/acl_tags.py new file mode 100644 index 0000000000..3467a7aa49 --- /dev/null +++ b/apps/acls/templatetags/acl_tags.py @@ -0,0 +1,54 @@ +from django.core.exceptions import PermissionDenied +from django.template import (TemplateSyntaxError, Library, + Node, Variable, VariableDoesNotExist) + +from acls.models import AccessEntry + +register = Library() + + +class CheckAccessNode(Node): + def __init__(self, permission_list=None, requester=None, obj=None, *args, **kwargs): + self.requester = requester + self.permission_list = permission_list + self.obj = obj + + def render(self, context): + permission_list = Variable(self.permission_list).resolve(context) + try: + # Check access_object, useful for document_page views + obj = Variable('access_object').resolve(context) + except VariableDoesNotExist: + try: + obj = Variable(self.obj).resolve(context) + except VariableDoesNotExist: + context[u'access'] = True + return u'' + + requester = Variable(self.requester).resolve(context) + + if not permission_list or not obj: + # There is no permissions list to check against which means + # this link is available for all + context[u'access'] = True + return u'' + + try: + AccessEntry.objects.check_accesses(permission_list, requester, obj) + except PermissionDenied: + context[u'access'] = False + return u'' + else: + context[u'access'] = True + return u'' + + +@register.tag +def check_access(parser, token): + try: + # Splitting by None == splitting by spaces. + tag_name, args = token.contents.split(None, 1) + except ValueError: + raise TemplateSyntaxError(u'%r tag requires arguments' % token.contents.split()[0]) + + return CheckAccessNode(*args.split()) From ef1e9951775db8e607e1953a92e9662693bc8428 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:44:47 -0400 Subject: [PATCH 081/484] Add acl tag to the navigation template --- apps/navigation/templates/generic_subnavigation.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/navigation/templates/generic_subnavigation.html b/apps/navigation/templates/generic_subnavigation.html index cac3301f00..46fecb22ab 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 navigation_object %} + + {% if permission or access %} {% if as_li %}
  • {% endif %} From 714f773b13bc538c807ddc6255f8d81470cec7b9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:45:13 -0400 Subject: [PATCH 082/484] Add folder literal for content type icon --- apps/acls/literals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/acls/literals.py b/apps/acls/literals.py index 5222fdb4f5..50c6626b8e 100644 --- a/apps/acls/literals.py +++ b/apps/acls/literals.py @@ -4,4 +4,5 @@ CONTENT_TYPE_ICON_MAP = { 'auth.group': 'group', 'documents.document': 'page', 'permissions.role': 'medal_gold_1', + 'folders.folder': 'folder', } From 405eedfeb299febd05069c496908e3a227e6281f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:45:41 -0400 Subject: [PATCH 083/484] Add document level access control --- apps/documents/views.py | 250 ++++++++++++++++++++++++++++++---------- 1 file changed, 187 insertions(+), 63 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index 9a34963aaf..ab41c4999f 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -1,5 +1,6 @@ import urlparse import copy +import logging from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect, HttpResponse @@ -26,6 +27,7 @@ from navigation.utils import resolve_to_name from permissions.models import Permission from document_indexing.api import update_indexes, delete_indexes from history.api import create_history +from acls.models import AccessEntry, PermissionDenied from documents.conf.settings import PREVIEW_SIZE from documents.conf.settings import STORAGE_BACKEND @@ -42,7 +44,7 @@ from documents.literals import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_TOOLS, - PERMISSION_DOCUMENT_VERSION_REVERT) + PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_TYPE_VIEW) from documents.literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) @@ -62,12 +64,29 @@ from documents.models import (Document, DocumentType, DocumentPage, from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT, \ PERMISSION_DOCUMENT_TYPE_DELETE, PERMISSION_DOCUMENT_TYPE_CREATE +logger = logging.getLogger(__name__) + def document_list(request, object_list=None, title=None, extra_context=None): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + pre_object_list = object_list if not (object_list is None) else Document.objects.all() + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + # If user doesn't have global permission, get a list of document + # for which he/she does hace access use it to filter the + # provided object_list + class_objects = AccessEntry.objects.get_allowed_class_objects(PERMISSION_DOCUMENT_VIEW, request.user, Document) + logger.debug('class_objects: %s' % class_objects) + + logger.debug('pre_object_list: %s' % pre_object_list) + + final_object_list = list(set(pre_object_list) & set(class_objects)) + else: + final_object_list = pre_object_list + context = { - 'object_list': object_list if not (object_list is None) else Document.objects.all(), + 'object_list': final_object_list, 'title': title if title else _(u'documents'), 'multi_select_as_buttons': True, 'hide_links': True, @@ -104,11 +123,16 @@ def document_create_siblings(request, document_id): def document_view(request, document_id, advanced=False): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + document = get_object_or_404(Document, pk=document_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + #document = get_object_or_404(Document.objects.select_related(), pk=document_id) # Triggers a 404 error on documents uploaded via local upload # TODO: investigate - document = get_object_or_404(Document, pk=document_id) RecentDocument.objects.add_document_for_user(request.user, document) @@ -173,17 +197,38 @@ def document_view(request, document_id, advanced=False): def document_delete(request, document_id=None, document_id_list=None): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DELETE]) - post_action_redirect = None + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DELETE]) + except PermissionDenied: + if document_id: + document = get_object_or_404(Document, pk=document_id) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_DELETE, request.user, document) + documents = [document] + post_action_redirect = reverse('document_list') + elif document_id_list: + documents = [] + for document_id in document_id_list.split(','): + document = get_object_or_404(Document, pk=document_id) + # If use doesn't have access for one document, stop and + # fail the entire operation + # TODO: improve it to remove documents not allowed + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_DELETE, request.user, document) + documents.append(document) + else: + messages.error(request, _(u'Must provide at least one document.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) - if document_id: - documents = [get_object_or_404(Document, pk=document_id)] - post_action_redirect = reverse('document_list') - elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] else: - messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + if document_id: + documents = [get_object_or_404(Document, pk=document_id)] + post_action_redirect = reverse('document_list') + elif document_id_list: + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one document.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + post_action_redirect = None 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', '/'))) @@ -230,9 +275,11 @@ def document_multiple_delete(request): def document_edit(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_PROPERTIES_EDIT]) - document = get_object_or_404(Document, pk=document_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_PROPERTIES_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_PROPERTIES_EDIT, request.user, document) if request.method == 'POST': old_document = copy.copy(document) @@ -273,9 +320,11 @@ def document_edit(request, document_id): def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=False): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - document = get_object_or_404(Document, pk=document_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) page = int(request.GET.get('page', DEFAULT_PAGE_NUMBER)) @@ -299,13 +348,16 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F def document_download(request, document_id=None, document_version_pk=None): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) - if document_version_pk: document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) else: document_version = get_object_or_404(Document, pk=document_id).latest_version - + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_DOWNLOAD, request.user, document_version.document) + try: # Test permissions and trigger exception fd = document_version.open() @@ -322,9 +374,13 @@ def document_download(request, document_id=None, document_version_pk=None): def document_page_transformation_list(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page.document) + return object_list( request, @@ -348,9 +404,12 @@ def document_page_transformation_list(request, document_page_id): def document_page_transformation_create(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page.document) if request.method == 'POST': form = DocumentPageTransformationForm(request.POST, initial={'document_page': document_page}) @@ -373,10 +432,13 @@ def document_page_transformation_create(request, document_page_id): def document_page_transformation_edit(request, document_page_transformation_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) - document_page_transformation = get_object_or_404(DocumentPageTransformation, pk=document_page_transformation_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page_transformation.document_page.document) + if request.method == 'POST': form = DocumentPageTransformationForm(request.POST, instance=document_page_transformation) if form.is_valid(): @@ -403,9 +465,11 @@ def document_page_transformation_edit(request, document_page_transformation_id): def document_page_transformation_delete(request, document_page_transformation_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) - document_page_transformation = get_object_or_404(DocumentPageTransformation, pk=document_page_transformation_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page_transformation.document_page.document) redirect_view = reverse('document_page_transformation_list', args=[document_page_transformation.document_page_id]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_view))) @@ -434,9 +498,13 @@ def document_page_transformation_delete(request, document_page_transformation_id def document_find_duplicates(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - document = get_object_or_404(Document, pk=document_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + extra_context = { 'title': _(u'duplicates of: %s') % document, 'object': document, @@ -464,8 +532,6 @@ def _find_duplicate_list(request, source_document_list=Document.objects.all(), i if include_source and results: duplicated.append(document.pk) context = { - 'object_list': Document.objects.filter(pk__in=duplicated), - 'title': _(u'duplicated documents'), 'hide_links': True, 'multi_select_as_buttons': True, } @@ -473,17 +539,22 @@ def _find_duplicate_list(request, source_document_list=Document.objects.all(), i if extra_context: context.update(extra_context) - return render_to_response('generic_list.html', context, - context_instance=RequestContext(request)) + return document_list( + request, + object_list=Document.objects.filter(pk__in=duplicated), + title=_(u'duplicated documents'), + extra_context=context + ) def document_find_all_duplicates(request): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + #Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) return _find_duplicate_list(request, include_source=True) def document_update_page_count(request): + # TODO: access_queryset Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) @@ -515,6 +586,7 @@ def document_update_page_count(request): def document_clear_transformations(request, document_id=None, document_id_list=None): + #TODO: access_list Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) if document_id: @@ -589,9 +661,12 @@ def document_missing_list(request): def document_page_view(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + document_page = get_object_or_404(DocumentPage, pk=document_page_id) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) zoom = int(request.GET.get('zoom', DEFAULT_ZOOM_LEVEL)) rotation = int(request.GET.get('rotation', DEFAULT_ROTATION)) @@ -611,6 +686,7 @@ def document_page_view(request, document_page_id): return render_to_response('generic_detail.html', { 'page': document_page, + 'access_object': document_page.document, 'navigation_object_name': 'page', 'web_theme_hide_menus': True, 'form': document_page_form, @@ -625,9 +701,12 @@ def document_page_view_reset(request, document_page_id): def document_page_text(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + document_page_form = DocumentPageForm_text(instance=document_page) return render_to_response('generic_detail.html', { @@ -636,13 +715,17 @@ def document_page_text(request, document_page_id): 'web_theme_hide_menus': True, 'form': document_page_form, 'title': _(u'details for: %s') % document_page, + 'access_object': document_page.document, }, context_instance=RequestContext(request)) def document_page_edit(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_EDIT]) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_EDIT, request.user, document_page.document) if request.method == 'POST': form = DocumentPageForm_edit(request.POST, instance=document_page) @@ -661,14 +744,20 @@ def document_page_edit(request, document_page_id): 'navigation_object_name': 'page', 'title': _(u'edit: %s') % document_page, 'web_theme_hide_menus': True, + 'access_object': document_page.document, }, context_instance=RequestContext(request)) def document_page_navigation_next(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) if document_page.page_number >= document_page.siblings.count(): messages.warning(request, _(u'There are no more pages in this document')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) @@ -678,10 +767,15 @@ def document_page_navigation_next(request, document_page_id): def document_page_navigation_previous(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) if document_page.page_number <= 1: messages.warning(request, _(u'You are already at the first page of this document')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) @@ -691,20 +785,30 @@ def document_page_navigation_previous(request, document_page_id): def document_page_navigation_first(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) document_page = get_object_or_404(document_page.siblings, page_number=1) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + + view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) + return HttpResponseRedirect(reverse(view, args=[document_page.pk])) def document_page_navigation_last(request, document_page_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) document_page = get_object_or_404(document_page.siblings, page_number=document_page.siblings.count()) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + + view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) + return HttpResponseRedirect(reverse(view, args=[document_page.pk])) @@ -720,10 +824,15 @@ def document_list_recent(request): def transform_page(request, document_page_id, zoom_function=None, rotation_function=None): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + document_page = get_object_or_404(DocumentPage, pk=document_page_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) - document_page = get_object_or_404(DocumentPage, pk=document_page_id) # Get the query string from the referer url query = urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).query # Parse the query string and get the zoom value @@ -778,9 +887,12 @@ def document_page_rotate_left(request, document_page_id): def document_print(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - document = get_object_or_404(Document, pk=document_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) RecentDocument.objects.add_document_for_user(request.user, document) @@ -835,10 +947,13 @@ def document_print(request, document_id): def document_hard_copy(request, document_id): #TODO: FIXME - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - document = get_object_or_404(Document, pk=document_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + RecentDocument.objects.add_document_for_user(request.user, document) #arguments, warnings = calculate_converter_arguments(document, size=PRINT_SIZE, file_format=DEFAULT_FILE_FORMAT) @@ -876,7 +991,7 @@ def document_hard_copy(request, document_id): def document_type_list(request): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_VIEW]) context = { 'object_list': DocumentType.objects.all(), @@ -890,6 +1005,7 @@ def document_type_list(request): def document_type_document_list(request, document_type_id): + # TODO: access list Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document_type = get_object_or_404(DocumentType, pk=document_type_id) @@ -1000,7 +1116,7 @@ def document_type_create(request): def document_type_filename_list(request, document_type_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_VIEW]) document_type = get_object_or_404(DocumentType, pk=document_type_id) context = { @@ -1152,8 +1268,12 @@ def document_clear_image_cache(request): def document_version_list(request, document_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) document = get_object_or_404(Document, pk=document_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) RecentDocument.objects.add_document_for_user(request.user, document) @@ -1195,10 +1315,14 @@ def document_version_list(request, document_pk): def document_version_revert(request, document_version_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERSION_REVERT]) + document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERSION_REVERT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERSION_REVERT, request.user, document_version.document) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) - document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) if request.method == 'POST': try: From 367180a3ec8110f74927d1ae86da3ce489b5afdc Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:45:54 -0400 Subject: [PATCH 084/484] Add document type permissions --- apps/documents/literals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/documents/literals.py b/apps/documents/literals.py index ad9c9c7a88..a85ce6119d 100644 --- a/apps/documents/literals.py +++ b/apps/documents/literals.py @@ -22,6 +22,7 @@ PERMISSION_DOCUMENT_VERSION_REVERT = Permission.objects.register(document_namesp documents_setup_namespace = PermissionNamespace('documents_setup', _(u'Documents setup')) +PERMISSION_DOCUMENT_TYPE_VIEW = Permission.objects.register(documents_setup_namespace, 'document_type_view', _(u'View document types')) PERMISSION_DOCUMENT_TYPE_EDIT = Permission.objects.register(documents_setup_namespace, 'document_type_edit', _(u'Edit document types')) PERMISSION_DOCUMENT_TYPE_DELETE = Permission.objects.register(documents_setup_namespace, 'document_type_delete', _(u'Delete document types')) PERMISSION_DOCUMENT_TYPE_CREATE = Permission.objects.register(documents_setup_namespace, 'document_type_create', _(u'Create document types')) From b93b227994c7f8437581e9ab929ebad91704af50 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:46:28 -0400 Subject: [PATCH 085/484] Add access checking method to AccessEntry class --- apps/acls/models.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index ec360c16de..942fdc18c4 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -195,8 +195,21 @@ class AccessEntryManager(models.Manager): if self.has_accesses(permission, requester, obj): return True else: - raise PermissionDenied(ugettext(u'Insufficient permissions.')) - + raise PermissionDenied(ugettext(u'Insufficient access.')) + + def check_accesses(self, permission_list, requester, obj): + for permission in permission_list: + if self.has_accesses(permission, requester, obj): + return True + + raise PermissionDenied(ugettext(u'Insufficient access.')) + + def get_allowed_class_objects(self, permission, requester, cls): + holder_type = ContentType.objects.get_for_model(requester) + content_type = ContentType.objects.get_for_model(cls) + + return [obj.content_object for obj in self.model.objects.filter(holder_type=holder_type, holder_id=requester.pk, content_type=content_type, permission=permission.get_stored_permission)] + def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) From 65bc6c88abddc3cf9d58579e2fcfe557d1a7cf54 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:46:59 -0400 Subject: [PATCH 086/484] Fix typo from method rename --- apps/permissions/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 99e4179cf9..13e367e21c 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -2,6 +2,7 @@ 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 @@ -151,7 +152,7 @@ class StoredPermission(models.Model): 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): From c7d1f9aae163655e2075ef697ef7d4cc4bd7e304 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 19:47:17 -0400 Subject: [PATCH 087/484] Enable document type permissions --- apps/documents/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index d9f4da730d..653ad2bbcf 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -22,7 +22,7 @@ from documents.literals import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS, PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE, - PERMISSION_DOCUMENT_TYPE_CREATE) + PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW) from documents.literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) from documents.conf.settings import ZOOM_MAX_LEVEL @@ -103,14 +103,14 @@ document_version_list = {'text': _(u'versions'), 'view': 'document_version_list' document_version_revert = {'text': _(u'revert'), 'view': 'document_version_revert', 'args': 'object.pk', 'famfam': 'page_refresh', 'permissions': [PERMISSION_DOCUMENT_VERSION_REVERT], 'conditional_disable': is_current_version} # Document type related links -document_type_list = {'text': _(u'document type list'), 'view': 'document_type_list', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_type_setup = {'text': _(u'document types'), 'view': 'document_type_list', 'famfam': 'layout', 'icon': 'layout.png', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_type_document_list = {'text': _(u'documents of this type'), 'view': 'document_type_document_list', 'args': 'document_type.id', 'famfam': 'page_go', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_type_list = {'text': _(u'document type list'), 'view': 'document_type_list', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} +document_type_setup = {'text': _(u'document types'), 'view': 'document_type_list', 'famfam': 'layout', 'icon': 'layout.png', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} +document_type_document_list = {'text': _(u'documents of this type'), 'view': 'document_type_document_list', 'args': 'document_type.id', 'famfam': 'page_go', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} document_type_edit = {'text': _(u'edit'), 'view': 'document_type_edit', 'args': 'document_type.id', 'famfam': 'layout_edit', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} document_type_delete = {'text': _(u'delete'), 'view': 'document_type_delete', 'args': 'document_type.id', 'famfam': 'layout_delete', 'permissions': [PERMISSION_DOCUMENT_TYPE_DELETE]} document_type_create = {'text': _(u'create document type'), 'view': 'document_type_create', 'famfam': 'layout_add', 'permissions': [PERMISSION_DOCUMENT_TYPE_CREATE]} -document_type_filename_list = {'text': _(u'filenames'), 'view': 'document_type_filename_list', 'args': 'document_type.id', 'famfam': 'database', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_type_filename_list = {'text': _(u'filenames'), 'view': 'document_type_filename_list', 'args': 'document_type.id', 'famfam': 'database', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} document_type_filename_create = {'text': _(u'add filename to document type'), 'view': 'document_type_filename_create', 'args': 'document_type.id', 'famfam': 'database_add', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} document_type_filename_edit = {'text': _(u'edit'), 'view': 'document_type_filename_edit', 'args': 'filename.id', 'famfam': 'database_edit', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} document_type_filename_delete = {'text': _(u'delete'), 'view': 'document_type_filename_delete', 'args': 'filename.id', 'famfam': 'database_delete', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} From f91f5fd70f4d68d7f7a00221e9f8c641a83d43f4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 23:24:13 -0400 Subject: [PATCH 088/484] Fix get_image_cache_name regression in ocr app --- apps/ocr/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ocr/api.py b/apps/ocr/api.py index e568ecf6c8..958ff864eb 100644 --- a/apps/ocr/api.py +++ b/apps/ocr/api.py @@ -96,7 +96,7 @@ def do_document_ocr(queue_document): # Fall back to doing visual OCR ocr_transformations, warnings = queue_document.get_transformation_list() - document_filepath = document_page.document.get_image_cache_name(page=document_page.page_number) + document_filepath = document_page.document.get_image_cache_name(page=document_page.page_number, version=document_page.document_version.pk) unpaper_output_filename = u'%s_unpaper_out_page_%s%s%s' % (document_page.document.uuid, document_page.page_number, os.extsep, UNPAPER_FILE_FORMAT) unpaper_output_filepath = os.path.join(TEMPORARY_DIRECTORY, unpaper_output_filename) From ebeb426f24cced2dd3a40d04a70683c1175002a8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Dec 2011 23:24:41 -0400 Subject: [PATCH 089/484] Add simple tag app tests --- apps/tags/tests.py | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/apps/tags/tests.py b/apps/tags/tests.py index 2247054b35..612cd1803e 100644 --- a/apps/tags/tests.py +++ b/apps/tags/tests.py @@ -1,23 +1,15 @@ -""" -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, 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') From 5a6414e044c1df0793555e148453d2cbc89b548d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Dec 2011 01:21:09 -0400 Subject: [PATCH 090/484] Add document creation, versioning and signature test w/ sample document, signed document and detached signature --- apps/documents/tests.py | 96 ++++++++++++++++++++++++++++++------- contrib/mayan_11_1.pdf | Bin 0 -> 272213 bytes contrib/mayan_11_1.pdf.gpg | Bin 0 -> 212865 bytes contrib/mayan_11_1.pdf.sig | Bin 0 -> 287 bytes 4 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 contrib/mayan_11_1.pdf create mode 100644 contrib/mayan_11_1.pdf.gpg create mode 100644 contrib/mayan_11_1.pdf.sig diff --git a/apps/documents/tests.py b/apps/documents/tests.py index 2247054b35..72da245be4 100644 --- a/apps/documents/tests.py +++ b/apps/documents/tests.py @@ -1,23 +1,85 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". +import os -Replace these with more appropriate tests for your application. -""" +from django.utils import unittest +from django.test.client import Client +from django.conf import settings +from django.core.files.base import File -from django.test import TestCase +from django_gpg.api import SIGNATURE_STATE_VALID -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) +from .models import Document, DocumentType +from .literals import VERSION_UPDATE_MAJOR, RELEASE_LEVEL_FINAL -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. ->>> 1 + 1 == 2 -True -"""} +class DocumentTestCase(unittest.TestCase): + def setUp(self): + self.document_type = DocumentType(name='test doc type') + self.document_type.save() + self.document = Document( + document_type = self.document_type, + description = 'description', + ) + self.document.save() + #return File(file(self.filepath, 'rb'), name=self.filename) + + file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf')) + new_version = self.document.new_version(file=File(file_object, name='mayan_11_1.pdf')) + file_object.close() + + def runTest(self): + self.failUnlessEqual(self.document_type.name, 'test doc type') + + self.failUnlessEqual(self.document.exists(), True) + self.failUnlessEqual(self.document.size, 272213) + + self.failUnlessEqual(self.document.file_mimetype, 'application/pdf') + self.failUnlessEqual(self.document.file_mime_encoding, 'binary') + self.failUnlessEqual(self.document.file_filename, 'mayan_11_1.pdf') + self.failUnlessEqual(self.document.checksum, 'c637ffab6b8bb026ed3784afdb07663fddc60099853fae2be93890852a69ecf3') + self.failUnlessEqual(self.document.page_count, 47) + + self.failUnlessEqual(self.document.latest_version.get_formated_version(), '1.0') + self.failUnlessEqual(self.document.has_detached_signature(), False) + + file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf.gpg')) + new_version_data = { + 'comment': 'test comment 1', + 'version_update': VERSION_UPDATE_MAJOR, + 'release_level': RELEASE_LEVEL_FINAL, + 'serial': 0, + } + + new_version = self.document.new_version(file=File(file_object, name='mayan_11_1.pdf.gpg'), **new_version_data) + file_object.close() + + self.failUnlessEqual(self.document.latest_version.get_formated_version(), '2.0') + self.failUnlessEqual(self.document.has_detached_signature(), False) + + self.failUnlessEqual(self.document.verify_signature().status, SIGNATURE_STATE_VALID) + + new_version_data = { + 'comment': 'test comment 2', + 'version_update': VERSION_UPDATE_MAJOR, + 'release_level': RELEASE_LEVEL_FINAL, + 'serial': 0, + } + file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf')) + new_version = self.document.new_version(file=File(file_object), **new_version_data) + file_object.close() + + self.failUnlessEqual(self.document.latest_version.get_formated_version(), '3.0') + + #GPGVerificationError + self.failUnlessEqual(self.document.verify_signature(), None) + + file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf.sig'), 'rb') + new_version = self.document.add_detached_signature(File(file_object)) + file_object.close() + + self.failUnlessEqual(self.document.has_detached_signature(), True) + self.failUnlessEqual(self.document.verify_signature().status, SIGNATURE_STATE_VALID) + + + def tearDown(self): + self.document.delete() diff --git a/contrib/mayan_11_1.pdf b/contrib/mayan_11_1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5fba2c87c3517d3067fab6f47c2d9e85d2ffcc2b GIT binary patch literal 272213 zcmcG12Rzl^|G!;GMmB|HMcjMcdtH04NFsZWYwsDd36ZU=Y)VG9tgJ$Ic4S16t?V-X zZ>mo!-*5H#eg7Vh9=X>&=lwdb^E&4|U(fS;y)J{in8YP8I~0eZyYKlB4wx21YprjF z!^cOmT!N7 z{fBPskp>Q?)>iD`A3H*P>qr8r=iq3E{N54wZ##kDNdM0$!Cb%X4tlgZ2)u4q${1;3ZTyc|kl$+`{zG5?s9y}}1oUKcptSG3{eB9#j`qg+&lDV3g`KIsql2~G z_knW$ehLsjbob8`h}t0yO^?_Z=kK-8eY7X&KiZcNzV^@Xpubl<81zFo|7c#;)BtH^ zkNn=%f6%)I^k57Mw6q)&rVg}PM;Fjn&C~Mn;c&jM`C?T*LA2yKymK^X4U@@F(0R8vuI|tp=b9F$r3Z>&P2`g&q~?>mobs{i}t7xxX4H?e8s= zQ(j61ByTeVsS`#=F<{1g^Xs(0emgC&uaoe7T3`oD?O#j_?C636rseS2fLeYxEnipm zp%#A9*->qAeck(xY6}K}{PB8T9OAVe0TG}~Xw^ zy2Qq}tw>l^Gm5WrJ%4@$+_e-u@5lM#Y`0eMT5zY(m6xt$%lXW3vz2x#)6i7=%xCrs znl?NHd&HWC4xKJMBT82u#_zI7=Mr=?H)XR5Ix6pL`h2Xt=k=bvJpM94yZKpG-Db+@ z=~<*IJb=f+O!aL~OEj_~3!-E0I~GP0`AhdoSNE=3Fkm&3^0l4S^JJqDEyb^SPQo<2+T&FAxUhyf@_|@4-3e4> z9|^`g{>_#}Pi6|z+6E=fmnS~kKe&`a=RQ=&SFyYOYH`q+C66r%M;=1=)|4&U^Fo%N zAj(6RMwed~1h79Gg0Mp?I(DBrw6h=fDXxQ!|qD{lmadMusN`= zeR=g|vw(luC*X&B8!h~B$@b#Nk76I20ZA z9S%2NSyL->91am{J42-1;kF9W;*jEy<`C655Ca74t_lELq}AX8vx7iTU<>17hXacV z41u$QA;6Z#31^3KA%Kqw1Dg78aP|APd^pbkjZ_F2J2!A%z`!teIG_|Tl#3n44Q#p) zC_4ziC4FgqMLmcVdsb}#}4$O&PG!H(C~ce%cR=_7I- z-O&DTv-njmC^wj$3)ptSFa$fC3z$_92$FWzBKO)yx6nSKc{2%oN<>F%Jf&%)2 z0`m%-mQVyBAC&7i^Y{hcACc=TIQ$>V1&6V7ArOGRxY$8pFaSv4?C?YA@vGH;pT{r0 z!V$TS9$^2Qd4zGYBLFZDhI0X{k&_k*hq7~V{!U+C{Ej1X{d)HQU*{3Z$FbLJb40GAu;+iHFHSIk_`raDLD=DdhX#d$*b$K5>FbLtbVRPB z_~m~i7Z}0L2{=JuP6#^`0n8%=!H(eioxZ*}R!8JI3U~iEa)A)+ATB^%&;vEmLcwr$ zZZP~e)A-d>`z{yP(R~8IdxuBsH@pX-g~34VoWNxKjHwS#({IPb@t7J4qXl-agR>LB z*MEnpxsDpwH%tvs6MyRU{e!86(s3(Jd6#(mr214u_+$qqMZ{Hz*s-fPwBz=-nXRHoU{Re@i>HWV@yqZI0fBosp-_dB($@k9 zTH5u76SzHXmy|f}n zfn8LL%+ivv&Lud9$Z!TiL>95xC)DnTv4AX3^cWD5xǐqa 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℞JYo-(YOLJFS67Vmz8m3W#e`)EF4*sR3 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 literal 0 HcmV?d00001 diff --git a/contrib/mayan_11_1.pdf.gpg b/contrib/mayan_11_1.pdf.gpg new file mode 100644 index 0000000000000000000000000000000000000000..e271fe8df3852dc7bd8dfcb0a5c0950506d8f25a GIT binary patch literal 212865 zcmV(^K-Isa0mOL)Se029F0Ft_NQo#1kx=n)I_M5TM3Bw{9J)KCK|qj3Dd`XiX{4kS zkd{^?1O;i7QY7wC|Cw=+`E_Rgd#}&q^YOvA)_&L8Yw!K8cSleV;t}BM3VAv9QQ2L= zFT^9_G}S+DiE+hP>4L$!V4#hmk^GV^IlF?m3;+SF_07om`2jpi z03Ipp>(&4saR8Tr3C6|&YX=0M2M7w1VXX|md<6T?$6R98Rt{Jz2mABC{RRFPZtSrJ z4yM*tK=7X(p?-5DiN!cL+F}22g#M``$oG!Gkl#EhVr?Bw?XZ@Af(3^D)E)Fs?hwDZ zld-aQz*tydzI^qEJLFH@!M=9~0sZDq3G3isYGwQfGRR*g{ts91Ke_rN_a+!CW2}X> z@gKf^o_)lheEpt&ajX;0lg*c;{o(EBQ-J*58x-<=RoI#8J33g~{Shei=Tm_Cle^!i zK+FznX!_k`LVuop^q;Er_v}lGT>IS%?B|IGgZ|{^_sq+g8epyLv46Pwi@a;XzQmvi z0PskfIsml4_w}F51NiyLc;v8F#ttR`2nqrC_Kytry#;R3;p}jQhZV;fSQ}!=aMtz? zc36xhnaj(%h(`Hl(6O5<9%L+z zaZC@7EYP{TVfK2zu#sID=ZJXET|uu`ITk_`do1nm_O6|bh%c&Q=hF4j0@9ubNs`IX zw+mQIE5}NQ*3$&o4szs{xz=*2B%&`?Z)dz;QlMxpyyEmWDw4jfM9Y{>@iKdoZNuQ% zSyRq8FH>$fZbAu&BU4l1!!KjXGxB1}=q2}qY8WO;X{XZ?Nf(y2Hd=uIW>AmmB`NV1 zn1q4z#WoVDfQKGXF<6V?%8dBgD+W8C>m*Kk5bCpf#(v51e-iauwh`ZD`?{+Q7Qmx` zF~*Yd{I-1ozRrgt8IK~?-rCX50E_z#^4o8&;A#&eYV88h{8B{-+&+UuL$t|o4(xE2 z066UHXM%!&-^N0JH`X5|z@w(F0YHKQNH`LRLO=jkjusZ$-mR2D{?loJBM(js9RAOy1&;c2e&N43 zE%5Km4&?0n?~srmvjqo1emPr9BYf7QAS%2`?fNN6Q>u>E_wWiU8W@-2xgjG%8~q_V zy^h=5m0tC;ar0st8sc_=Cg2Ug^6@?CYqWuIn@5*jEGFolCCXxj&z5$RaS0OIJq?Z3 zqcy%|MR!pxv-B$R>C-FVp5>4Qf9SK*z1kt`A>G1Pp1U!u6mlWVRy$9bhNanOJ+WWZ zvf-uLqt!BW=yv5DRlagRVfVaDK2N0ogo-w*Y7z27lbCS0cKG(UY&uazlg zW)7={2;_AzQ+w0b7K5$IhUl96jfc}#uj!Isv|M-urM*OUbQ!&fsdv}MZIV?}fPw>KWeIVqW6;(Q({ zo^@JopyEW#c=f^u)@XhKSWWfTF((qv?qbxKUQ*%P{N@LX^^+QG*|F>SWu737iRCNM zkhxL0h4qR`f%3ibwY{qr>?F| zE6H&?pw+VE(QHwA$FP+7%H(JJoJ*;!9wQC>RlA>FEDbxKFW`Sy+4aW-fdv0-L42*VKP?C(=f%^9N=H*XI2K_@2Uk4@QQF7FG`1&qqYGqEwBWi7Dh_(9)7o^Q2 z%_GAjrV0M~@+Ce4+&V*ofglhJw}l~r2;5=W0))d4&(=XQ{T(jI{~8wzjpK{BZ5Iqj0TD>ttb#zeS^ZhQpa*e5|L3@nNFWl& z?Z7bHJMOfEp>X(M$e-YX9mECupW{Nnfk+ezmoFp`1P0@9B7lgmOZvazf*-^M|DWT6 zLxCt9nFk|~xYY>7;e-K^(4XZCaS+#!XaB#&1%m?7P&f`343{q$4krYczn|p`c@P)! ze~t@^Yiw}K91Md15x5Qw1_J?6ke}rXbr2Woe~t@`0zz?35Eu#p!ce$*grI;Zti*OSSPyCxP@V7m+=&9Xh~fuI6Ood9``F)HXI)^7{40AQpmvYFn!>n?^z0^6}M>#3^j<}T|McDEw$@#?ACKH zwmYnA;T=Jr($x!_xVLn59)A+9>!?`VDgig$uW%J9+bX$}9u3pOpT*bRv)y%j|H1A3 ztZ#E)=d=!e(*@gz;?9d(A>m%2hXmW^;l$S>-7D{yuRJw9Zn@;4wqxALVaC8|mciXk zK#$FQKPcjxevST<_UMA*qbL1E1#Gy0 z!b@S1sY3NNS+Opfu-DD~c~HRs?2)pOlpJ;<-f2ZGlR6gUyLUf3N;dhUSFREHOo;lT zmp*rXR=@5%&#Lhx{El;8L3ywkY_Q)su&>bbhR_((nu^VJiKqx_Sz9V|<%=1H405R1 zrKfo)H2OB^I2me?uE+PRo#6TeHsPb)*!hu0@qvu;b=ff0C7reU3VN*P~1d-d(?4-g3sSPS#RUjk@ zEI28{)<%`}+%n@b(?l9q*inf*NHZSOVIO!SrS4j&tw%w(DA+j0__UW4StggE*B+*8{8RVy}e07?bf= zH}M&DDuZdrz{VMNf)d(_5M?)D6yBgoCtjmh-NDbJK4w>6=B!<@*lt)3zKyv)l)kW7 zm0{$;Sw0>0j=Brv)v5C6srpS}Np;nC))5u?6W}(tlENI?=VBiSr(?whpT&U)>gOn9 zrWmnMS;4N5qW6plml9jUa;d<4a~Xdnz9zZ3bLhJ_&qxs2$io@$@>WXm2XFy*;4NB7 zegfkC)X#3xL?G(MKnh#}``DmynY516b15YQ`@|ND*-^`El+?&FmE-#BE(`&g3i*> z$xC;{WLeY0VKkc9e))O5XW0aoIY{ar=y^IvWYIV-8NFJz2);*CM0m7Hy>KQVnS7#K z!G`c{d7U&>8#VTRMjD?Uf0GuO)1FA!n*1Y;%6B5E7gN^W+`iM3yTx{=##~G-bNQvs z3gcvWE19p* z;X9#xJsfZK`SG!qD5*3!sFFYM@_xW1T(@g;&!@gUxbgb=dnV+*!sc@ttxd0Q$SX-o zr}`I4H=Ox&&P^e+Fjx4beOKDxO)FHZeb}21_A`_^XoRM-HF}vI55~!g*51KhiW;pB9AvD{}s&%n1w8sP0vDXslDmbK9ZOx0Dfgy#S z*URDJ9?l!DXD9BPhlsM@=a6~t{oYKL?+KsSnKv>pfji41C#xzQWy4&b`?`0F(8g#W zPQUF;ql&tEhlDp%m|LS_*Tzqh-sYsYigdMK?{nqq(hVbee|16R@ix~H)NAeK5`6Lm zz30Bs7f6ZEo?VJ`m^Fk=q6U-1mI^LjSSfdSYxKnLTzj_3Re5sfrNXheNEWX5H&*UV zFBI=IBun5;ic#ieeZE*OOAD)z4pq7Q+DvO}Os}jAudOeep*)XYr2GD5^-2#%NQ!53 zz)c8YUuF9p%W1Xi3gK+&_kv|L$pT0%OokuyZ4}ctJGC{++-N<*n86x8_ZU`}{GKqn zFJ}t0ms(P97UYtHrAhHECDy#(&?(Qj{bJ(?QH=2u4mnT2l4kMd4I0fW`-Cs{&C?Rx z#TR=*1s)-_p0fbU`~0u2Cn$^NhQ~1PJV=Bxl2eVQ z=K*|N=E~!b&<+nQP;L<;qWa98Ep}yB=ritp7>Ku&WIjXFm)e&8s>S`x5eYSyqASax zO~%$l{dbd7+g=}cX%h6{PZaW<;g=5ixH2y6noL~V*5cgzdKZd+8d_s?hCrTPhhFSN z@;j3k5IqCt7n4KBpR%snZ8^Lr1rFbx#zzYoZymp9vB2fL>~GBlVCC4}8rXUKMlE?W zn}vV!gzQMPz}8}j4)*SzTT3*C!gKSanbi_e1IlAPWNr6|9TjyT{%m)Kj=_eN%Bz-&7pbHx&o<%?s+A7xXtT=x<)o-@KrqKPWuNzwAX0Bl#cz zuE+SD5rr za9sC>M*l;+_Bg<}p2g7)3v@O$H?{mS=Rj*aW1cT>HecR&uvTARc&^$wm>OU#bPY@} zb{GR3Mb)*#kyB$U)35iCe+m!vm(tcROa~MOgu~$g1QPKzEC}u$iADhsC|nZ;{@b&m zZ|VTFaOL@W*?b9WXlZ`{>0gRnzk(D51i>Hx1RMKo|%LKtP~CFb*CR{6$^`AaJDs0Yma`e^r{`h%ZVG1PDj}-z*!fmF~B5|3EDN>O6%5p-3nIhDHJrxFEnN_}7a} zI0&~EP=9mv{*7Q%zF@c0wXilYzhru_=>Nre3qeA@-tqhv4-^CeLgBD~7SGR$9{n#) zP8b*s{8H**APTp4!r)*a1OfrTaPX0!zkeG2O39=D#pww{L4nXOBJY3j!l5`?148^` zyx*|8SzB8k2K0Y-cl0I8@GrPwXdvo~IE*WIIBv^_As}DG>qAvxX(MZE2i$PjA1>R_ z|KgN{;204aSC9x45Q0k}6#eB4$MHg375rPG^hYuer^9-@7RHpBE}&T~_H^Z88; zZOWVqhAON_exB@UhN#Ojv4y+hv^q%vWQ9a@+My0_icFuFT^S+qB#7eeSsm5JtvYfS z@$>Y)$-%lGvo|cyjfQ9KU9v=pza5F+Curun6mQ|O(DwSqOh`OW4dfwh+5q95J{hwg zyG=0Y$Nk_yyZJ4Bf9f~EAkaUP|J3vPwV5h2GMM@kp z?LT#2AsX){ue}@H5SGGmw535zhu-ZZ+0MDkb+rk#pQ&7khP<{2ysG5t>ariyqO=>- z+$f`kIC+MmXPt!~uirI|b6Y52;EAl4j<^dHV<8T%v~xK>Y?>Sw_v{4@Efkp z3={>OK>H3rVw^v8hh6mMPS=8_1aFl#Wq@pSXHWXa;--M&luMAzEb_BL%1Gk2a0AY< z#Nma};e{hz{p#$i)LgV5F-(otL}x3CY%4x)zBSB$&VMVy2y&H8NVY(}O{)1bOINEq z@~W?%n^f_l#s%OwNeTDW2H{*5DRR(qldi9@M#L5-?pXIrcUAtC3mP3S_~m@(W=~$u zE~5(_&L98eN7%E{U?;_anQX-@cHuw6(r(E0J&*U%b0ayG@KNN$9i|GpLb~bZc&euS z)q;~)4CPU+7blB92-&BUg5sAKq73wVDvXG9iVRjN<}X`GTHI{u1C0kmuib3HdxW1R zVYabP$u@BZcK6Z%JMwFrz0!}(ZIy~nCd?R>SNhh)kCtj1 zJXh+R)5;}|>Y@H{H~6-8@S1N_B>0k%W+3Y1ql&ZkQmZO`o9`5*hDVhGgB8YQ9+SDP zJN8<;s83N?!&AE_T+S!ckJ6oR<$Tgh&?G6Y}dhTz0C zg$tkAZ3L)vrWc2X2rHZFR8Kl4vG@vU8MM{=ujz}%#?*PKUf1_!7rY=WtM5TD%qhO< zaP@+4Ud~33s?_s7ACuMC>6dbdcCGUX%NpZwjq_@TQQ zx3jYl`&J~u1u)uIiexXG(3#|w<9%08o9A}e+)D2thc-90rA7Ix^ioD%=mo#avC)Wo zAfN+N*3>SVN3iGdV2iZq>SfD!Y=K3*1CQ*m0liDdZcsX7b-Tr|-pkx@-Xou`sYxLw zDTd}{4GK7jlLLS&adefGtX_@?q=|x&_E|+tqyeG2;M1%L zo1iy?a|(*kqh9PC#*)lSyCU>En|+G={wIC-bGtnQX$t0|$HkxN%r%u|yAY){ zoAUv(4^?a>nkosSEHrFb9eGvq6q*x`H_*-~WtEb*1rbyNPk9=B>d)tSF)sJ@*nH4R4u)F&(Xlf?H#^j zW<`cwWM1|)hat3W)%2xkiH#?3Mdv0hZr+P+7uj+`Z`>2bYZM@8ey4RtE7P>RGVt24 z!|nH~oZ4%-tEVm&ncCgc8oi_0Op{%caS4|0G2324&l{C<1lmrfh9;NdtfZ4Hk*O(ZHf_TOs1@dy6$ZW zvGbVjvZ0`i)eLsO4*~3s4`1B8%oW~>TzV8sIJAVh!_jZv`^cF`e@&9HlKRfzaSi>s zsb1GecT^GC$~#kol{0Ml-5p`;mYcit^5w6G-K*$!=>#85dDggX=1v0EAxKLf# zt-REldacHO|Jt4M z+Q$*6TD@Md7qeu)_{dUYQuVQ={zNp_<}|IV?NKWA)C_Q|7e1??$cw{{&mTL;AC6Dd zkH;tCmyS;`7<@pm1%tlv9x(Wu$_fU-e-Ku`ee;i%N-z)#K>?t+HWmUx|E^R*VNf6# z{P(+XLq~lJQ!4{&Tr>EkbF#!bU<@%1m`nN?ds74Z1C;+;RR6Sx1>=~*7vvBesmCP_ z3`O9mHV!!iN4b%IpIrYvT+TTn7e(pkRkkJ;YC_-oNVx!0>qVzoE$rf?s#`d6znZk5<+a?}hWHvmnLHU! zcoRU*u5WJ`rE_x5Dt-%7MJDD2l_q5>6xCgmDEqLVmpg2q-Ck$1pjR=!!J&QS+*3?M zOKxT82fcewGBOt}y5#u!eJPDfN=NnM#e;RzF~!Ai*JU+U+r!ShM{aH;lS_zkW_4{B z4i=pp5egpeH>DWP*H5_iP^pYk+V80p-_ic1Mcro59TmdtavII`oz#1ZVpWwa?%S5? z&APASU#rQkuDQiNf1mGEyL5@Wp+xJheWF_jQLVNigVBv4Or>_n_Mo4>=5?CNe94RY z4^_r&J}M>4?)lD+AFDRUTV^MXP2W8V$?ad7aoZRe6NO!Ol9a9IY}H%oKdbXe?)WR9 zu#|T4N@_Kss>bS`1Rn>_==-#2c{w5GCBU5mz;#H*xW+7X6p?e zx~_Sg7(8KkBrmi`|3ww=zyx~0Zv8oDC!W^nC7Pg<3}C~0+mq{h*y-a{xRncZXL&DmOlG&v#jU%vGEz%W^U6hz3Io5DnIO_=G4GwgSwmlwcyW8=#(8klP zF~gd}9bwAGg$zp$z8J0RwEl*gtO0_+l2|WCe&O;5M>wvs&Sd(v*GLdW$u8qPBAciv zr`;XrsA?rNzgp*x_r}{beAFipf3i7M@?rV{Vf$QXSW9%CKNqJQnou>FNFAIW0=Yir zr6NlBsX?BswQK_oo*NG$o#G;V5Z|O@($u5`*wSBZyQzeMlyKo zt~dFV+NSs=a}=BX>2~CO+tw5O{9leL-IaN9@~wNxQm4{2Eh03C_ikH0RPO~tQe>8h zTK?D#KaaTDa>q!vSa+)_}CwGO{=lK!Hf8eAl=Mj+U+=dEB%DCUx`DKD)f=n*-zzf`!u@8*^1-u zo1JUke#b2T2?V>_8vn57&Q{NmfN?^k`eW0PeP-($?x%E5@K)Y)sL`JJsHn{ z`9$2$`}7+iD3fxns|)NpRIrRA;r(}JclI?uzt*8%I8ouLn{3q5#7X;H)TRSJeuykW z*?aKz453Ymc4rgdR;11ob>H=~Awl*@l!CPxTPW#78M12Mz77~U8NaC_k@-S1SI}(D zzUld8wD-QCcXXREkJ>3az1o`}&UCd2M`3l(5neQ*?;b)-Y?b+oY6V+?2&;HFTVkD} zs@9uVtW0F9<2C6+d$bmgU{ z@Ivd_-A#U|{x#cG-l>m4`h{ziFAx>k@=>X6QO^fA@i)wj_uJg;$$LVoTy=sN*ZG9O zrJRq2<~@e@Kv!9=8I5b}cGo;ay23p2DEcfiZ*jVLa0vLEUIXjhO?9LFY`x0)VJm%{ z$G9P_C-ZFAr>%7FhOxfD+55bm#ldtOtMo^aDvQaFxtyrzJRW4*Rr|3Y0|kCSc5<;B z&*VZi*s==7PO*08y70`Crysd?FZ(&2N?z#Tog^tlxKq>Kk{nuzqrMP;5Z%xi2}f&IC_PK0w8EG5CH-MU@#mz{kzh+{V!_$VDLc- z28R8j+VY8-AML=%|859|qk#zYA$HJzNcngqabbYLsK3GgAkf43AC7eX zBL6E_lf9dWpdIgdsHb{EzE^r`OuOF|CUDOvK~B|_0b*i7BTN)5zq8{0obVK-ywcSg z@XXmK&MUjivLmA|BQ>j@ zqSH?)&-2cX_wsPu8sDj*dD^?G0#***jE$_Dh8ssEo(erGVz@Ee+`}+T$&kWx^ahjr z6WQ}O*hSCF*QHl|T;<%n9I?NMp`D4}%2b8x#2DHX)NL`;YwMAp>Y1E9vI-SGZKQJ< z)PynX-4`*P7=)`@vEb!4EoNJS-l83b$;;$29Rx zm<;ww#v%JR3+eM~xu4!@*;C>hk2_*<2{WNzHh3(WA%ZF+j_PA{I)CP@fi-UyJ%ICM z`ZWjtkIu@2u@4@>D#O!}UJtVKKD`@!Fs3#+(-%~-O=!?wAgJ9#`26mx$49DfU;kt- zq0hqIYQ{M;1X4CHBw2_g?IX%MS4Mxdr_x(L@k+U&-?2w=vr-6`hq2|tt;l=r(Qx`k zfP~`*}z1M17;CWg4G?hE4aQ@YC#p0LSd_^}GKFy}h!z15dhePao zJEht&wh_kG7jw*!W;xW_8Vroit6`Pw)*-=_77FP;MAsY6)F{(@md^8@Z7e&|Go;tF zGJBjoSpM|vXC>S7pG?+;X?G!?KCFYV{;)MKlUDQj`rY^UsI@AEg{}O}I$|Q3gk;%( zpW>9|LI=}NiP>ry3}x?K-J02BXoE|Z%*+R`4F$<0Kiv$dfc3C)===9x2+FYGvApsj z0Wq9ebeSlkZw-Zb@QSQB7tI?+X_>gzg)Te2@G*)t&BVXxEx#}?t1=$##RhUEq7L8k z0$F7ZaGk@&7%p+uDo%4&!52~%&2J;mf+bF7^Yj|_Thf=MGD^Vs>1HbH_pI1T9)?!F z4y4QIu`HW7p3h^<2&iftVtjs%ImAS?_RJan6OU`)5)+Ri!qj}ZNTS_D7}L3npNmpS zI6U63-wWGf4FYdYI2jBq=;Q4+U=&?Q_v+5GcAFk^Ci&QWq4_arV(OA+c$(6vPG)}U zj>3-EVukp ze>6npSYPZ#)8NmplZ5p75b13DV_Tsf#rJHFoMf11@54D*UnZTNbyu{Yk zP=rd_3cWIDQ@)^eyD#hhgTWh2wwtIiwd81GUJ4}YE##=oE`BS`icQyy<5&9ug!jJZ-djD5TJcxkMOgoE{z%EOC;Aik7^@XPDEDUV)> z5?SO;Wg4#YI_RCeiu)3k5 zig^-`DSehlen1fU_RHtpxwHnxiJ$!(054x6WaY2vT$O&RPl(sWG46b3%i8l(tITs# zi#c>&pX14kZ`;1z<0`_mypX z;t<1wtm>d47z6~vz=s$fWJd=KVNe7R20Cm+)PFaG!eBrs=ny^zIjHs>FoeKSKrres zsNlav$i5?Ce_xP;B7Y=g5D4U#?_|q0mL4V|81_B)$pq!xqH<9!2$Bb;eM3%4IZi#L zoARG~uh8LhV%Xvcsw}sMg<40b#uH)_#Z{}l8wFc8S9ZEX{0a&J3Q|@)YwI<4#jEI2 zy-!$;S#yW0omrzMzwgMRxkCT2nY}S&I%-NH?vmxyrx1o7-TFc29<0MiNIqGfxY1RI z(NmGPifFg-*;+-qKRo=byR7qS!sC&>@P!KIO98Bu?kZ*V?pq8M`X>8Nn}SFlZxrvD zS%a6G;pOAwyH0_(TbAh1sUS&zrNIzB6?`7a+t%{-4vguc(MC}tVxg{XQODEE!@?Q# z>q@ml8F)%d$ok84!pWruc=@<&#x#sAUeG4*s2G$MGA!&|mc%@$l%?OUrYyCYn|$hI z+U!NWFr-Mku|}v>6QwEyuJi*a#55?{kK?^lBW!)jgz7z!P4B>KbL&xF#5FJ7NY(9RN1G5-VQry*#%u&2Dd9>PD8NSm0hGj#=o66OsK>6*g!^LX4}{}fdpj$j(e^FBthufjUyN<#Tm-`hYii}&G)CR7tcdiZ!@1Yq zDR8{lwCz}ppdDnDlc+FU1*ruQD^e7x!h}ay?<~1+rHbcm+V#^F(%ncp-t&}~v^4ih z#M5cX9ghOWxd`RJ+-t)P0!Hk*>@QwNKfWDZa)D;7xT34t@#2FA_gEHd9#fN1qznjA zpT011v|lHPGBA_s*2?9vs5oGUjDm`-rtgF?2GHbOlq`par#Gx6`jBHRIi$`+ULW3f z347}oY-4mko>0mCmBJcQHjz*!z!lr}i`w(voD zBPVlm%4*k|XsoiNL{y^4(lmq9qV8rdw&4k0@269s7W`wclUVeF{KiE$ACb`aQ5XZwFFjl88BE_=d(wR!*8TjB4Rq`sh|g zt&~(eJ_hw$3ldF=7S-47BG zDfLm)6v}zTg6q@~`);jZOJ?9rDWe;eS~Sk@!LnG?Nl@81nm+QCUkI=R|32%?iLAzT zu_gXnC5|w=jDlL#VbOpXtBl*~D$UFhZ*+~|RA;E#yH^}fZ&fjXV3aim`jNWstJO5_f-$7g;Gab+6W#vlMCY$rHVUiEPu) zdi`))%YXNixzJ5KLA`S?6MX~W{SbfO!} zs0KU0dtPF-3(hVRp?ou*#F5@G7OCUaL6;L+ zM1^$>9|w4)#VeT@U2pqH74M%5WgE>5n;bo_l$&uuDGpVdY-!o-r7xH8CRZjliu*EU zv5HD@pv8yInHsYTq$f&)ydSl(-F+Ga`#3DktT`YNQzRRd%9brlWHfn^+NYU%ZA^+< z;ZeM_LEdL75hm=E!W+hJZ)F4{b6&LAI`zLBB-OjW?ZE2OIZ;aO!1Xa=@)jxM z2J;&v=}4*QeaBMLEec~BYwAGdM?-J>s?quDW38Fl439>iRWr4mO84OyB)w$WZmMK6 zu#_W8&o5r$4T9fQ&zEKH9bmg3x%x<&H|ZJ^e*Nrw1#@N6d~#0qKDG+A`+2c$724DL zM|H#|PQPswKg#+10+~q*VLWJ3d_yKUIaL9~c(*)$c42ySLgz{Z=M(n<@`Q)m>B_nG zPYMhde!a$hUolYaQz!mKucgyD%zt@k>f@XWux1IX#?Anbdy@K=Pt!lX^vEs zG9v>j<>=sYw}Q`51JZG^J$7D`vfr6;SYAA)a@RYA^eTsgVCHV~wUwH$ltpSWQm zYY(rQx$ffDrt#U*l`Tr$L)t|C7`bo+cbM$*d`92Jd#{z+j<(HFrD)Ak?T51m>}py! znXLEw;d_&`uI(D6$$v^y&CA9IyokT{VEObMlB`Q$ZdYuMBwA5AIWF#|q>!+6W!aTW z7a|k6>XwYfvfoWNFuV2}L2m|ll^0s}Iq83pb2tYF_Y3=yjf0j_a`#D{_}Hf;RBorD zB5h+tuQBB}>LHqyh$+!{)#C%g5TPTaj>E}f1Ky~askzD%<53L-{m&`^1VTBX6pwsP zd(=YeZ+fnUJQP1d<4>y(pm2=bnnt8Ag*WugA%`JBM&)DB`D_`725KGiQdv|FOD> z{z}il5YV?L^tUJYKTpVip3wh1VTY)p=pQiu`i(ad4n*K!Az(-#8ioQuz%U>P$Bq#= zI*LX>{=OP&Xl-DBh#ZQw;sFDpJSNu84%R$|SQ`s#S4&(<4$7nu&_53a27v+LaQN?` zzz_%^9QXW3q5MbJbuzVcaKu<(t(<_?cE(?#_`-bc9e7Nw46!ai69-F+0}(*~MFhC| z0Dfu75Ks^h1cn1}tqTx^!c7JY1Vn?;|0n`OtiCD6>MQz#NWuRCDI5yKmCheXQ7|A1 zj`&wd9rYcp92^f5&!PW9?ni=wAP@`y#}x$%{G~U70U@}?363iY6a@D7>)Y7W!NgJj zD@r?SdyJi_wH=Qo#ua15gRwI(F?GV)<6iA?UDClAp#MAuC<+Ngpx|FxF(3?$>rNrK zwiXu@1PTR0(TIO`Wr4B57?@xWEsP&;cz(SwPzWFrw;_Sy5L_RO#zDm88~2L9A%#Hy zQC&D=^^GuJ|NbTG2eBUP$G>jizo0oB)GGdDhugPtJJAm|(1Shv0V4z&0)*h^<;TGe z-r^iE1f!8aIQkH|0S5kwA#NQWDmOsCmsAc{4Zgp+`3nW%*Hi=8_qqJ-8V7;ukt0LD{OBHlt}<&OEQ${wPob>kBu2mT+6iR zP+5Fb=mQWIzg8<$%eS{2)-u%AG~~K4=$QBUr4u)$>v6~Yg*2=ZC8m?RQR@l+X!Y@e zt4rkjaZ{U%BQ2If0?P`oE8LA4JOp^78y%Rl0(751Jkn+h)6acaldjhjKYF%Rw{W7u zZMeYt51;icTf)=$jV~g%l5|)l+zxr#DS6G~R4CVy+C)gvJ?uh+Ey%W|mBgf4{b~ z7dKhaDSF+QXd*JulC1|7p3Y(FW%yhx?jeh*gPiN<@y;t8oQ~BTQHltib= z(Wqa>TbR#9X{!@5H5#$p^0|Rh2V0DF5l|l;Rn|^kek<$640jtbqC%EwAU2JuR!`B+ zflj%e(Op~ZhokSwt&bDxu6Uj+RnIUBQ|wC2<7iI&e1q0{Kpu}Y+kM2eP#c^GI~7Xm zA77WP-0A}=iX7VoU9`eJm^e>!DxAF0#_Z(71#@J}3LpAG`YaHEpEO&^Be$MCQ}oV7 zaX(#8L!9@1P}W{aWY!VYSw}59tv6JoQ#LM^l1Tj%BdSLQTXUEw? zox9w3;>Yn7VV`BY-@?d4#r>=OP)pk))D!1ZU6RabuC6zro~oVi@8RA?+%A=7U#um6 z#-2oS!8&6q&E<`S1^N;*Rm7uZO8@Pb!3IDvpm5`H&O)$*c`5<_$s^-b)$+ckx7jq4Ly@ zjC5~}i}f;wlbj~$w_4)&)=#$kp3~^MqoAR}JyjNAblu{@8>d^2Q^KDX7wHxdM#4p1 z*LrOpAtpFS?!FoD9kbaBejb)~r-1F_i@A-tynfGz4|TnU!@XDXfN_h+Jb zU)07y%O5$r?#+~_76_2-zweI}e~m{0@RKx+%XrVde}}nlr0wm8b^XTaO4Bpg^VbJ? ztlP^f0yZCduFOlB3MFlR_NuSv)$HYIc=Uv95FlcoIdLr^8x!@( zr4!lRpYx=Ks~vefCL${8SB~fj*#L*SbEZUUn*ofDr~Oa+>2*sI865A|%OD{ihO}DE zHd?|qH}3YtP1_{Ic4cw|+Y9uC0cRaD@`E$DqvO@>Sn`g4~Z_0X`)6&;5 z@zi>ikeB@`Knq%T9Xu9d5i z6`Xp+*G4B_Zgg+u2v=yL%jg3y$Ga~pxt?9o2$IU}q~D^RCfmJYkTTDVX9cJ^hfiji z-@4h3A9KQRbg_4%J1Wj^h%d(e94Idh-&gW1@!hm%o!-OT6itnujKwu$Lv=^EgSsdQ zsi{I36KS+zVni`#t`%uSyqRAHs{t+ScFzW0yr>*qrBtMN3QuW~p}^)wuE*;94Vg|% zMl9%!UNu^Sa4Dx9j3rFqez}3VC%0vRbgrDQw(sDZYR=@F!f!W-UVb&}LiqW{vZ}RQ z9Dj%T(4GZ8A%oJgrTg8*jHA(1zhJRQk9X?ja>*ch9^a9H7zhpd23(LkV#LbjLV{uC~oz zRZU`@=l^s!Z-eEfH*rP~)rroCcxqHo-#pWU9dyAWLmXjjhS&xBVCC|?BOB+;lMZS4 zU_bJ*gAL!;^X<b=6UnDFC?>hcuh$9~;^w+lMN5g}69S03TARq*F z7;8DmtqvH%aHJn`*tHDoAWu4I2!jIQkV8g5RHZ&Vt9}z9WaEzaeWE& z5U6m-PYgk5APRaIROo*<1mm)b1RVku2Kj%-%;1OI=imzImzi0enx_3rNm|cYRg-K= zA9=M+;Isa@P>K;&(sOV7NYe(7c+Od`sB7c-$k|vJ^ZWVNx?4@WSh+!P z3QBm2p}f?#z_B|M!=|Zd8v2kTnu(*5sxltzbo=VYNmi=#Yzzf_e`&qEg z_e`o2@<6sULS(u|JvT2X$mf^vFjD(UPj`HDEZ{5L)nuEbJ9TcYDKhwq0q;YPZC?t8 zH`jt}&)d0Qv=h~HY`8g zhSICSgYHix!xBO#w}*#97KN@IZyFv_rs~pZ5LGdEFEB z#CF5wD06Xk!dx_~sOQZrsehD0Ld~D))lG`^2vW69stQvpj8NGwr>2gDKWo!%hTXWtW8Ot%HL_SORi<%eB6ciZ z8$l8ciN=FtfK%;_lu~^qP;S9cpj*aVpYFLFpOq&sY%Ja~@Fe67S?8%;5~CukS7pAl z4gf|#xxd`64L0`d*f2;9&kbC!bl2NHZsQ9T=U#ZNJkhM930M~yS&2Pytie?Hda0m- z8PnEY^J__Q-+|JA)T&!=KIL}3BL_dZd~e?dNvylG zCvKE-+OVqKP_}yxpXAk>`i=pAYXwSjsBf1$6p~ zotG|tY*Q;UkKLS<@d6XTU^hjZKY`nWSI!>e>sl_{Vy0 z19UCmR#Rx1;x!fur!e_6vd5<8X7Qu;TE>wU6r<^lyXF)tod1Vf7L+LuUWO4Twp& z`wB^5+!47EwUky^$E%oX`JS~4(((^<2hW|*?3yIrqq`*#NR}J$u7EziO{ua_NXa&x zWsZ~YT8y0!_$E;fR%65v7QfC**(13pjL7Rvku2;3KU8@fvVMdI;$ldj@xJEuoW$0L z#j@ROzIXiQXJ$Q9yOY$a*dmg<<&=|5dzbtR;ICmeQy=y0#2bnbpFCdFu{iB7Itpop zxv|vrytIj$*0g#(?W6ZOZIfhrmNLd>CywiLbmjE8`xr>5piF#9Q5iV;iX?Eo&ZpC!J;ATBb+q4ag}Q z4{I_EZ(*(8$49@O1O?+*5sqrWz#t$3gaSa} zP#_3*EW;pRARG+-+q#mzsRPi$^_y^a>6=>ZX8nV>1V2cC;J+v?!4DE3_@8API06QQ zfzdx2A`TLu1BNgp9Ed)QtNmA`IO2px0O9CE><|Zu(?LTB8i+s~A}}Ei5~qWPATW+q z9%6S;cspPRLBfC_*daMZ93;*M4Ph``h=&;-B+ds7zevJ}L%1R0AaOom2u8tyNcdqf z{$w_A3k!%s9%A>CvH?TB%>E%EB7aggxY-9CHv90OtAu~SKmSZpk%%t}@82M%$nV+n zZ^RUg`ekDJ6h}-m5VW3K4=1yf_)lCE_4a;@M%dQg=7AgL)XaqidRss{o)Ra)b~gk7 zMHEhmXB_e@{87TZv+wvOsu;PsiMfwyFgPvjC}#Wm9J_p9kB2Cp@u-1BFYW2`H@QcW zZ7zl-AsVL)G+WY7l=F%AOOy(ge9UL5NsN$)kN#xq(2~-n){qqQo>(%)oTEmTmrf7}3|Rv@JD2zF{E@!?Wp zN=FQ+sifu7%2hWco4tkR+Foyhj&pry!E4phqAVH$JVtk#Am3v}_X!cF9%x*~gj5hY zPY}JZ{-myOVaXu-?1el){s=d9=qWNY4ks?j2cp7$H;<`Xy+lLZLEY}riNzj@d~}_a z1DQ_k0`O_cZXwS{q>YIe=rgXkw9*KMGu)7iBPW_%t1r4W=8rzP*8TDS@aEQGQLb&< zHzA$UAP6WSH4M`O(xG%nihy)?NQ0m>NC^m%(%l^bf=El3bV*5fe601n@3-AIi}!Y| z=lS0654PE6WA?d@^St)Cj^BQqq{}CDZ4G@BV&wF3SofGOyE&+%cMU1jlte2BD+*Z> z$c%E?)98Kb-?BDgnfjbNf~b44mh-(QN_&1vMyTq9IKV^T4abB(ycQ7oO<^25 z7M)yjbVEu3Wd>huIK>S)ZKoc4>Y(PjlMN{z^_^6ljModWr5Oe^#Mk%QA1`lQ7=G;z z3X&uKf?=7^uX2y@VmIVoW!#G1ugOUE(%BMO9r1P6$3R*yZ!GQJpAqyP+34Cd*uUmp z`+fl>jA^+csFMY9sH~;f?{{(6%TSrK{Gh@`o+X1Nize$pD}#j|j!M`U#9N?Obg$aN zUP?NOMQ=`jjK#tG=utZq(WR=XmqEQU8>S-+K+aqNBz_FV#~=9G1F;G#1T{M zx9TSN10k$(e-uYLubrbnZE-VD!qSmF!jyuwdtpypMHJy=`qQ*ee)P3H6H`hmdI0c& za&H2Z9S5f#;f%Pqy&QSwKXeX2zk|zlk0qT!Np0Iqyv6cKoB9UoJnm=Z?Yj!zJ8@H( z_iS}zWu)C)qjrq#jS|XEY#`i}S*!~uEV8}7&R3^G9~KL`nL6m4HlsSSOHthMPyXe3 z1-1SlMN-Wyg%KFVUKr*40Wr58r9)7tOONL4e6obTv&)}S)#Ut`@ueoYU|{r=m>KX? z$UA1vO$c30yT~2RFSg>bT`V(sKMZRm0r;~6NcZ)wTQFDI*1p+T*)rvi>0is$UP`R* zn|nzdR;p(-7BfsP;tCjqlI=C9J$whaHp2=BBn+~|Q3q6HyWg%zyhdx}IWiLv`6)3g z9!NEBpfwV4jxrRe-%iTTn0C=|+JMb#ham|LmnmO6AHPdZC*B;Or{p7*JfzIJ$YbdD z8lsXLjkGxubtDnzEnZ-qVr0Wqie6)yub>OUZYhsoEa`vW7Z z_9%DT(sT);$O)Dpdt-iTmU62#$h!dFkCmH|)sXwV@+;-bqa5U?6sPm=)cj{Agx-jR zGev08-`3~YjWGMKM)n=4@hx`;A+}WqT1;F5cJ;J;RV1GUn{~f^KJbw?s z5Qv*&Ciu-Z`)2`v16|-Z+w8vy|2X4<1CX~hcKFRUds7HO0C;XYs)FBavp0qRr}-58 zW}CesghD|82<(;-4E$!Fy(t7j05HfcLd4BJdqW6;!mcs(mR&{M#H<@aFcJy?-mIJplf)!ZCHr-jc@)q z8@=^j{Khss*O37RyUjNLdM|E=o`2z)|KS7<`L7rI-=G8J0srl@QMLaKI{liunJgq~ zW!6;s{`myjpG`sIbbc?Hor3S;RhwR3NMTQnecNC%H933ZfcUtV7~JT~P>n_0jk#cA z15L9~zBsP{lkfp+ym5yz{`B4rYHTbW%wlo;NP0KaD|tA1tZInIbvH0gvNlaoKh#cni${&Ol+U8VuOnP0Lv}0o z8>xs$+(GZX$k6ZSuSk z+RNNl`8i*rgRBxtX~|KjX!yqC%3Hdz$q+hIB}HBMydsUs#k_G(4qYhT#>)f^z@MHM z8D=Lt`Pv9ws$>v4e{e9(+ZnbX&Jn9;nWFc z!=6~`(E54lZpftpMjJBru|=&)gDLw($1C&5s|RTj{S%LD8@M&aJ4xgZ5W@R2SZiPR zh1H`#y5uRwSS2C#4U8=vMEM^``_Nv22o~%GLtHm~LeeEG8C5*ym#`NU{3A0vS@~^4 z9DZV5Ja|tK5Hk8HT1O07^1$3ek>x1AZT-UwFRZCTmxUl`8^0%fH;3<4?ZH%4LB~PE z72$~>!d)vo%U}L1uJx6$)rqyJVkxSa60ghCldy-*bMF=mXD8*TKxX$f4~@Sj>`zSI zzZY7xG>?|03CrK9{WNY_JJ&UnK--T&SIOxq&~`7Wkt?cnY1ru8%%T(iFtPCI_b?ra zX68#KLh_&=3+Q#JOCxGhSAE&kTBNQk1{eAhX=h!F4JAFJJxr(T9t*DXlX-6!#7ov? zKXQ!FjbtqK7VJ!&XhO7HV0`HpVb;&*&|+}%{+4EHQ0l#kl$6Y?)fL8g60y}d{$&5L?NvuAWH91mk@N@@`RNj`lx3MF%n2W_Ojo zjH>sH(ZT(N^`>k3wnHl9zxJKm=>f^}7kWS-|GV^nyxDgCEZ}d@1M+6u`8VP9g+ahu zL^oT`4bk;e8~}vg(&UggTh2`(7z%*hlCzOFTh0v~^p7bE_?Gbu@@CJuDTKfQQ0Of^ z2YC}!ZVEv>*M0n!?ufjJDmR1>Bo6>_3ps#*H&NxL5C#O?QYi>{lT>c%cwhiH&tGo_ z2>2g8b4?rwH~)ikWf8!Z2=$bg;f884p@Hf5zA&~$m@~@}@0{+G~AUFsBhW?c~ zK)~M^2Lu5DKs>jV`Wxebc)$Q8^tR3Ujd8Ad4FH7w)v6%iZ;Zop4aW%JZ5;Qn!vD*7 z1mgKu)BJBd`eU2__5tOj-6sUG$B~-CUTL)%m-Nfei=oYk1-2Q?g`C75IYrzK9O#S3 zFIW43oL z@cm3)=0;LVz1j_NBIgu*rNTK_KKU#pbtA-xV+Ydd!>(&8+4V@;i_!xSOwASN+#EnG zRy)(sNB4F8e1q5~l=%TQt}`_Q`aPv^hpk3^wl|l3BoevE=%h7`KuEuTfBQi0UWV_z zu{w&oLZK09c~erXN`&Y|ygx1^Py=&Jac9_G$pc$*8DWydFLM;NwHgl9m9=+B*m|cAl`@AK)}-a)ioS;Rl1deu{$Q$}DLy4qjW; zI|i~`&0ncsc9;ZQLW$~#?=R^#QXv}~;wH^U9hZ}SozIP#C%w;G_B}Tih*n*?42xtp zMRR_D43AIgv>!RFDw)a13}pV{U(J&)OIyY1ugnztw(q%HFm>_R;k$#S22ofhPry+P zq_C3{weZg88ovxd4%Lds`cQ(&2nOSFgE`5qt*5w?b(|tPBfS$lv0E*ey7ArC7vHAr zr;0}QYwxsD=0sYKC)0Xu$`#^TC1n^JN9zB~u^D{AW*w-2H{C4h))|}nzz|{K;qg?R zq<=QzE&M`25&upV#{>AAM{o88KMD!^;ret{^Q=s?C6a4Wh$R@Kz7A@1)%b2N?@RA~ z#YxZ>SNzaUW#fBL5(3Xt?5C(K%gfNrRL1-FG3_xGLn>`sN51Bpj92rO9rdUataFFF zk7>l19B}VjK3nk})G21dEk#Ikf7*3zERP906O2Yxi5SfgdT+(HI#^>s{lv1rvfTY~ zy~jkx7n>yh#r>yyz1%rrU6op2l*tJk4Rz`WX0n_TN+SKr)2-QN_x+^9j6*s5b_B+~?pG@|pESv% zH`BdXZafLX-+m&?mRc&NtS?RGc`K`IiZs0syA0g6*bZwkADNcEo#$RT%~-diTH^FJ zD|W$9SwhPa&7gWOv(GQCyQiG&Y~pe<=ESf1%|q%_^(?(_Ee@K(C`!`nr)tbKKkCXG*ahkQ`G zt(IR)agjWoBH;NDKD`Mq=)KmQSO-t07Yb-zLHe(J2jcnHrh6;j{nwN7-}ny11N?9D z-F3J5_vY|l1^k}xKs=EDB)pyPKs?a@EP`G4>03^G{%EBCS$Ey0k+*bd9{6u`e{|_v zh9;n!r)W2YP$U?DfZhTWJjmY&Aus?Ce2WkS{LexN5^)U_x9E6&qk{thV9+f~1c81d z1R}1n@D_pr{YT4OQ`+?s;fPy66!aU*fO!xA2=JEM2>Oj}K-cICM%;ovpx^ig1VI4c zxA+b88{b^}0{{l!Cj5Z8*#BEFbjc<6spzBz0%cg>V;~O5}HQn9f8}M&@^T#jh zmigs>J!<~{f{?bDu;c^;{4KT;93w)gh{OOa&xbmNXcPFGS5 zE+}nnn~Ur|KjZIz`Gr`t)YeR={B`TkqP~+}f^JJhw-y1QzL`F@wEY?gnL_tQJ_2lO z^%&Zsk=AWLh%8&AosWZKcf!BaGyH7tj~@eQ%91n%n0$J!JxtGf;R?mR0ZL9`rP?b@dc&nu(o6crOv>gIdZvPaO^;kMI$jnx6lm zX?x@ow9}u##P!Ty=hS5~XD`4!j?|mIRQ1`H3W>d)gLxw}`G)EJfzv^0^9^>rbM~@w zSeeBxI3Orqh)F64VZ4qnw{AV|dT&u9LEStaP9*sPY))=a7k)lp5&0tPfsI$AFLu5q zxT<}mTQeka^24hz?5TvO9)m)5{;%gBJQq1uUN^WHP!Pn8$K3BwWeZ*1Gp{q+p$$kT zLkX4D-qty%y`0%8{EV7Kb|nA4ld-Jg`v|?ql$nnDpFYTqpJusGe*Ka4kN zCRJ=KJ-VGP7p2UK#yV%jO{{Uf*QUCC&r(V+dD@{yJ|G zt|uf z7*I)Ai%Ck&%f{ZvCKG+;)+(9Wb&M_eF8WR$v%X2VWnFzXqv8x-L%ty0_bf)y8Mjj$ zJ%swvhV_Qg-sm#27;PNo-jsSKyqXA^oY zv+2eP*UJrL$2-N}d%|xNXA$rALFaVw{6OmTqpM-mC&?6@x1~>j=+%RP71dNdl=%Gwe6gpd0Db**g1Th!Z`W-r^3&o_yxk>U{h27kq}wvITWB3*Lj^Pwr@|4jbK5 zGx)oLZ?x@`*!R!^VNpbmE$u;)+HNk<7$l8V- zis506P>-vA`28o2G5DqR{1nAvcvZg6&-zd$tLX_UnP%QiohkCOk(S7}6yxM^;=y)y zWQZ)$A&K&##EXlEHpvy7_U92&DxY;5niL&9WuGxovC#}D*ThFb!-UF&X zoQ0#(+3jB+>3lw;d~R7$e+x5$|Ft3C&WwLPNdKJ~!Jz*xGlFlnV=(ydF(de9JN`G} z|M^7mk0<_r7Qzq!;4LF8@XdC7QwM|qK=50@0erI^-w^&W7epX$xgz9dJH9Cd0|7j@ z3|l~uoBjBP5OTdl@GYlbAjnOQyD0=CZyzW@ZgSiWAsBH@4!1!L8 z`H#l=gX2H|AnX?8g#5-h*B`jPkGGZj8{_;5a){eD=QqybfkOb$+dK~WjdOS)5Wuzg z7R&wXef+--R?yp~ZOH5O{7tZ`(6F?htiF4>rPKVuiDgIz8{OTwDT8vwbu=Abk+|*< zDT5ar{soM~euw(W)g^_x_XFnfm9d)dSZE9-bz`x{uNc<~_}4C+50BQ%_TY+Z^S4t0~O!+5R(!6$Xj(W#1oa{e?l*C5Fr&V*Y>{*Ab)sE|j&)a;M8&k8fgve(OxCE^4 z2nZ6T<%tDGsZ7qj46iEHdK2iy`c5*k#)#gM(E(lI)khjQ_Q%7tk7TL#Zx_#wn~ClL zMuUZ|&!)bd2Ut9>VXW@c_74Bf+`vqWz@N5!Jn2O3~i@JcwWut2ap# z@Bu{$SZ%}n!k+{_&A1e z`})eiSmXGWiq=B*FDIw|d3)y5rFMYj9m2|1SuHNx$2jP9s1{4DM$7OHqbXH=^_Gq| zOYVD*IiXR7!+YHC6_d4d7PScrFnC8lm%g7MTTiubf2!25pN$UP({UOml~2c9pKpDaW@Ie5cd>lsmd@)!?E73O^!3F65WU?fL1iZJA?+hl zYJY#;$31UoNo60!}H59GqKZ^S(NoKYO%tAFpLB^QN9N&pFrL{YntrU*yNmp^K z-lkEO=zoXEOr-9Z^8mIbP;A6F>f<7Tl&aIU6A8y@m(ur+wG( zxvh)o$rKiPQU3BS&w0LPf>`*VDPrj%wuy-kCyJux@h|dIV7->zdTDE=RSh#=N3B`z zwC$WMUx(=nT7|av5f`=!=8?GXt)>O>iTRZ2#H0)$M-{a>mh%byGDe_TA6k@dUV}T& zDxNi%Xiscpw>tzGk4WUc@5xWxL6v^ULaDE2#coj$(uJXM&xyA1-g%2BgU(b&4!Ix>2wZ1@gHsR z7uZjnz4eTz08p|$-EV*H!7}`sS7sWVG{QS&BW1TlrREhG4cKU%ayC$x`Hn{sTGwKR z(<8>cG0{%QQiz+ZOdtenRA1vP5@iZ<2*~%N8T|#r%%0PCR0|EyfqUD|f1h;wKBoqE z4^(HBeoIedPd(zq9iX~XVWDC}kFr0k{q|O@8|3EFXDze0;uQ3Ju2L!Sp#)UrUOz^X;C1LUEiU11P?o9TW+SQv0JW-=r@p6&nw~K zH(SFHrNBbh{X6R4vns`~p4pMtIxF$RYv^JUQFQ}q?qU9TIiAL*i#LPDV97DP-hvhz zZ$>aY%)g|D{^Zg7pW7)#BZAqRwkQYZ`9I|BBTGAi)t|OhI~OnYrf~E{mTV?{@6cF% zYbsK@-&~m}vLM&;xRfc(kWc$VF&nm_MW;m3R}HZs&R1{v<_hGL1lGJVW9j-aM3ZAP zOSV*khRQwfhI;FS@Lq5Xg%aPLGz<3q9^gviaQsnX3aOq?i{BA-|K-Sdpig2DwX9uO zMFw-4lby!&<9WBzA9FtT7~l^KHAzZRAIL%KJDNLmt4U6|f;MGLVc1=Jtj8S@d1fS% z@m|4sN#!T`f<5+w$$qw&eP^eG9@h6*2OBUoHZs25`Iu2{kK9%E{G#y;nl@wECMhxN z%k(YkVYwWA?a}v79f9Z_sB~ekOZT`-nL=@msNIs@=+WtpFGwZ8ht;C)bw!ci@yRK) z>}H;eEvcj#Bo(RR3R*1XI$)J&Hx~o5jdc2gx}+5C4fhO|g63zAM?cRB!r0e4rxhBS z-0NbA`%H)qC}Zj!vSxP=XGhkuyz0qcNZBg1o3fXF{McmoK8mcbHh)6r{?Y@SS)WykPo{|2cC!Tn5UCrQfl6{2atlvF?>^ivWAWiU<-#GB zBfBS4MqRNfQkft!7Uyv~Pu6}}e$)Mq5mQTW$TC(C2*<&zxGGabS6riX!y8}~0>ecfpS3q2sj`Dj9aavIO^ z*!KHI8%_s}A3(5pRiShSRo79U@0PRx{r!X)`qv3F^uIk}hTgQwZb%z;2t{LT{4k4IvL44uC>#;Y8^FHv>3s ziEA2%L;e9X!fs*4>#7ldpBXjnCo4%jkBVkRjR~R8n(K8ygZ@Ld;NCBR=6oKKAnKqu zhLHNV40(vA%MCr$pyQ6a6pD`OXr z=yv>2ckFzzwz_}1+7*HKg071hfEt`Q)|vO|h@LLb`#>$G^&CMS|> zcsPAb73)TGZx8(_@EFTfzTvr6)DGsI8_oI1`IY+n*2#rW_%0@y&0Y4 z#^X&I{~z8oM09o5`+G6LVSbTE{QWV>oh*G)BWY8w_SbwDoEg3;i@pT)XSLRMJh2xm z9BvM7XzPkyL^37#W2(ENN;juT&lpQCM$`lFJ_s6bn@CKUcyS5oO{a=5A5X68_6qOv zP0vYm@+n9N1~vYo>kCHf3B~PP{q7{&RkcR@oaXXjwH=w{U_$1-_wv3XSlB%yTHx}| z&b9T_ULLDbrTtgIkIKhiP+;NHmkk{?ac=}iyrs`1r9g;!9kv>*_f=yHq|{S?E$!rO zC?h*qvDMFn<6e|57>?LWMv)(rvZH@pwK|^LjP@OWzjT4py=77<++<$c7s(Y9K|em4 z&E&3V;E~Dp&}M4k7}T`%9_Ihxy=lQp6>-<61~dNt<^WM#3DDOt58g{dVmj_5ww_vw z%g=bGC`oYif=9X$>zWY@#b0cj@Luq|)T9lYg?@^tP9kUFu^-%agUp&IW5}gTZgf>P zfpnulUmde7Z1@8_V%h^4r)<}k8I~HJChA#j_&5$c!Ug6IJQa736N!5=q0r>*(#$<> z`+j(wh7KcZx3D*OnBVM@vd#Z>-xSjcYQZKow~Wv{#5H7Rs}HffZ=yVemE=i}ZdNEN zTJT`E3#nYR@9*-Ju_K6%NB^C!e|=L7cYvlwoNfli0r9@I~^MLf=*=ks1V$#)aUW!rP@z33i54fmdX z-LIVE_DV6s>a6mY=E=sfbJ=({r`m&^96~CS`yn*~)8A=#?VDcpGUHq3j}qZFzUq_H#6?iB7d6NO;)gg~590?B`Wy_SU9EdMS={I)2W5WuJrjmp($k z@f`tmYLA4>v#qQcHV^9st1Ic}>5)o<6Q6TThwkZSGi^CH-~?)Xr)e6U3=J|LFA4`nu{G1v@TZJLBh_BJ}R8rag$yglJ)S2FhVc%8ddcKfWBFf18AR zC2DIYYkRsLEpy2UG}Q54IM_PbO1Z75*vA1`w|lfho0(*1pi3QD406l17x^er$|Na#ypE--;z4)r&0#T-MzJcH@+GcMHW&m8X+u z?)X$irsgbv-&u(WoiD_H16T=1dDb5!f@c+Ul*+Y@yYjWR`jwe|3F&28ZoK!Cb;e)}joi)7s3rKCdsU%^# z4js6LFw%u`p_nH4(+^)H=MTPk%1@g9?;0?bpNLR*I~pGKt&)3xwtOZnFpVeUx)-y8 z7R>Iuds?^|jx}xJW>{YyF7YZa?2**q!U6^#nH|SYIbUy{SqQ9l^B&(p4f9S|F_qNx zrZzPda;cKgCGBafZ*)tvibw2lX?G=0j<4kaB3JfT5u&0tx3~Y*Hn(v2#)42aOcp5u}w{y_-oS1w|~4IEVi)oz`>6S`c(QhpW!Z6 zBPy@^L+gapp?zmIcEwgx0(}q2M9p)L{7~kH83Y)o76t zS4pKPIudfX{`adrosPq#?uz1@(J1PW6(yyy7I%|`iH?d~F`{q&PT4TB7_jS0=2zBy z7X6F^DWvh$fgzZm3Kn%AFIU*O*~`-_j)|{vb1dwpvd~xtE{l$u#xOdIXqb@&Er0br zSyp|i<2w^N&Gaf;_61JgN_T?9V3_{%>6&LzM=#q}p=;gps{^c86e=%YeviSjK9KM< z5V4n6@VewVR=i65a$5Aohb09nG|j2z)gcI1wZWSfTKmHz>I5^nY^Kx^)di4rmVX9|m zXl-ONke-s|@W7yt?7`RDZ- zn>v^{>H+kvEx8SJjbE7>8rs=&J6c)mTU$BZs2g@O;=%rA#Dm?8c(5Dk3Bhx{_qW6@ z*zZHo-^e}J|A1dx5Bd*65S-_h5Cr4_|NRi85jBV)_Dt59EAS}E3(!B2YMI>ltf0V$ zA%j_I_BxGBGqB=Vq?Ed}$x}17h-rg(md#FDmHzZ}J!V0Jud6Ic>)iGgPZOb@`BI^t zVC7b&>TJ=AKD+|)YKK;pmp?K__|7o-8jXJ?elD~9*?rzN;CZ@eR3IUro6hxgeAZ8O z=^=9+GqU+(Hddc_hj_1l9VMmwFMxm!gTkgp$MfS9W(UgY7O9}%SM-lLFi!Bg?0ts^ zYGd{+m!;&S zxtQXZKSVavTbV%#)ELaqyZ5`$P$_`}s#{Tu)hT8!{ zsQ=NlThf(Epw;2}s8_D8(o)TxN>_tBNg*OFar8BKf3Byk&KS+%pH-TvFi68QeQt9;toGWm-5EpdA=2zgzr5xU<*i zvsSxsGT(RZUb8Uzpc*(a66;8fv*_>CIJfH@sbx-`B-ue#PKh0`G9~+X6Ez)L8h35U$6pKy3cA z-~fa!fv$x9u4F!w;ptP!b_z-%hLbOP)3X97#VOEb>9|(wu265Ta{9p7_`>}#ZyWgp8E#cUoj0l<2ZvBl ze|6aEoLisSNe4;MhVe2s(2ePa6+u-Gi8ov7^i?$J_a0@{^Y~>EAMGGfSrEEXsXG$Q zzAWm=yhXMmp0r^h?pADIdHKucr9zsVAx>a1Va;nd?FY0(88{SNQT4K+h?gw7K=VWY zIJt}*FdOgxHDoi_Xv`B# zIz}N`=0{^CBwQ?emk@R;WY;f6|_OqSQb`2r}HpRyu&(6WR|*lFUKrKL46^9 zMSXoOG+)}rG{8hb5n zO|#~C(O2;4`>;y%?lS$=p9ww$q?JzLd}B{Bq3D(tG-L_j*6m zWW7xdY)nAKGsYjz2X*Z6`0Nck7J#i3yE&=U%0e*0Nvf=BZEhLW2 z{$5=;2YcJ~=3~c%?W;k@C#}oN=V_l)*@vv`<%1LP&IOue>PM%IoE%+F$d)Fhs{pUw z+2`-Lh6O+J3f!s+x)2NR6Bo6BsWAy>Nqo0M%X5^S4&iUJS02%hCKSH z=iwB4Df<$uYl-jhu9N-!yI>PE8v6_H(ztS$ujC%@skQ7)27VBjPZ_vBw+PYrnet{y zg}*WM0!VbfCW8F^9NJrq;sBzx&%pA9FZnzx7b?X)_nxm9IP>T!&xXF58+~o^RF}7} zxo%KW&MtD_a2`(umi#2bdVlyHf!31-Jtiv@s*lPNX{pvv5x*Gjsox(T&K`U+za^Ls zVjjX4QqbD=TdpM%=C$#42|PT(o+|y+4+}vFt|dm;8VG{;zWtJ6b(M%hQ(M%@_r3Co z4i`K(E@rmL$bXeKNfvT)W^J$J-9s*&-l$KDv%Xz$!{JnD5Z;16N1D)qL z)wJfXt%N<}+djrHYOQFi?dfvJDc=c$|CL=#@h=G|>bF##88y0d2IZMWbm6(&_||Z< zh+P8AXER@3WO!kC9)OaBP5`8we9k3HLtfzrmqf6i7yeiag7_6zK#F^;4A>)++^s@o+;c-TIY{-E_-T$p!= z6m^jj7tfK&QbnV@Fj-yw4lu`$oFg0*v`XtgSirinwm*iGTHHMah!zZb&OIF9xbmsj!EywT*6#!TmzJ-P1z~8d)pFnYgg^_=Yg+XxWO%{g1{)>fS z@c;FS_$w2`VE+Ti1cLzZYaWBZ5CFtAM1g^SKql-OI*|Z49P!T}^O`a34K1Av?QTP1 z82o=wB@%Isyw?Z}<^g~a*BA(d0l;ts0~i7VfRNySj>0wohgYVS#(%P~us%=`sK+HL zEG*7rVI&N&u`=eh(6uu*yt#n?QS^WVpx4F#@mzB=50n9X&Grx=m;nSr0N^~xf4+e0 z@*S?R^v?x6WaKuqv@x`^zBZeyuHB8Y;WrOL{|#GdLWf7aE>=?E z63{TVA6`H`!IUt`#3k?Pk;^?j5GDb`caHZ^9z9V}>8d=8vAl5KIXVm8485n$6NJuM zyhWeiUn0USqP_9_DCa=;ASR#A&GALuVNmpXD5*r=dS2D9;ng5!OW`g*2sMY7vi&a; zIZ4@J|4^WW^Tp&vLh$-oupj_9Wu~eAV?MQ?upqtqcss!|19;V58gcK*$fqe4b#3Bi zYpaH)$Ja_Hv9rjD~Hm3QwG|{ z^M|};KG6M&J<3~<@TtTo$4Vn+7%4uIlStEU*F(rP$x5|#AcV_5ATUaWx476bVZ_-R zdAi6o(=mSOaw127Aa6`J7Vd^5vw1NUS85BF?!JHVgM!?P1s8WBJQ^}l*i!+hc0C~OOFj8AOo zj`Qe4OM`3FXjo4gjzk%8dk#*~jm5E=qDgIpbS=e2&zQ|!MEat(GJ9S>Npwn2X>SzS zOqV2-$Uvs&Pox*Ibh%Zb%7u|GzR#k*n!*roseWp9;)2{9W#3Fq-&4lkl^1%}XCy24 zwf912>4P0-PzHUk-GF9j!WlXuX_wjZ9e`_u;2U3Cgfh`qp%sg^-O*(r)h7Sfl>Mp1 z1IxMvWjvALugfoA{(SS4x9bke=9HmJFQ)h2_d`oZ6r_5z{{3hrg)s4m-0zuDr4pKS z@tLQlbt>Iz)N2_+__>uP6~9I*eeZn@39PfVenZ$5Lh{SXi#l;^+W9i2)83owYeFEs zOm7IgDAEU`#w8bb;cj}_u7wFwd|KTZB>lX7J*WslUS~e-B?6+niY!0^g;|9eu zocoSXYM#=hko5rHDU^EC3s*^`Xi1?HUB);KArZ7XZ7N{h54De6cX_2pw# z%%r|CKI6>KhM5x?CYrmYKs3yQw0O6_B*_@-a=n>AS!JnzhHprKau#sPNp7j8iI*aV zYZ46Cao zQqPqm+7->F70&W<$*aQ@4md`ZSqQ7O)J$zBmBEm&I|l8@WpELikc%7XJZkeJp@>cD zApP)|x+kMgUIrpyb*S~I_@@%83n%hQC>DWUFCRlud_(V3`C?;?RnW3Zq^=8|bx^rJ z!oS!`wH15V5{7{t;ynardRZ3yn6IB~Ilspkv+7GnyR%Jj+@T0%o36pCof$tTNm9+x zwiYG+-PdO5@~#gsO+VAo&QYZ3=gc(~!cm>?Pq3?eTFYiJa^jWDj6iko6Q|l84z7S# zF&;L*-jTMb&JI(wd3kRLwJ>af_^kvTcTm`wxR?J+ygDxE{zg+Cul3gYYu^n45N1t> z?PHaGKD5N)DrZ`tIJTNhG~oI zfJhgoFCojBl;uNI4^j~^Np)(W+JNt_6L`hlcK|lZ-S_%2mT;b6^CmvVA+>t*LQq}l zM+)OTRzq53M~Uy?z-|Lu6Y0rQT=C=T9(MnRSP6*;tFn5p;t%!Z+%8fmIIJM0?9oyT z4Z1}?^r!Bpp>_-2@>tr(tROkm=PV|&m&O1)mcK}QT9 zD+%7ot)iMEY)rUQGG0EMM5;K~Az$c;y!g~pEpv8IInQaiG>K}~2rKFm;~w3gnigsy zyim(Zv;9u`jfSUEapM99sKrqa<3>yGmD#v(HNV_e+M3+5to6f|A*}V-3Xr`bS$9Jb zW4&T@+L3Qh@&%5_KTvPaU-DULt40s$LeCl6yF1iJHL?8Jc9EXba4oL*$m^IfChoR) z^4EFu&3J+U{w1Ek5&zwI0{>s}1P=deEP?+IVhIlf3V>V_9^{&v!PjvFgaBW^hhE1L z1OW68dH)aGcd;=A*tj^DSX=!WP5yY#tzc?lVg2eRE&mTv3K9vp=6MD%oCg3yKp8+l z2ml7;VE`jQ04U-gMyVU~dNX}pdwav1i3GuO6Sk3m5A6|u$ppyXqdnp;dEnngU?9(R zbcEiL2@wBHw*R*=|K9|C*e#$BghBr<=r?F++E2nLJdcWIHPb%?EM1g>Jrp>Z9pRPF zG`8eeemXOdkkl~ZyuGvO=yh?Q7)3HXS2YHnC}V+ghp_j6Z{@RJpI*q>%qS$SzcJ0WG-vk1b;g7D-u6xixtG@@;lIh zidMA>xtTdF#V=rN^9^nRJnMjWCjDAG$MgkJ3O9xJWJTc?$@W*nrBlmJE;45zdjfsX zJAGR8;6k2eq!d`7y92;=4EzdV+|d+B6|>;#08&7$zh`N6|ERQ6(y~wAL!Q}w`JOM7 zNR?hWqCx0LMstrqlt}1YU+*l1dd5;*&E!sIhD&1>R*Xl8U#dpseMBk)&$4CxKpp1! zXUN%TvE$dOgMK2WITG_p-)R3BCC=r9=O`3=v_>WUgQD9g+>nF*CCr4GA}@{U{35{0 zdfsG$|Es+&FMu`0t0}))boX+>+1}>P+>#=!!wVM^hsxt&8v@}DyKx*WPiGiwdOqY0 zi#6E;*84$ElcGePKxOyaEAEeN>-wfyR|gz0YsR;B@-^D@l3Qc8$WHqh$c8t!;7t9X&w-SIVDZk*Y`U>siGOe&;TKs7;lef_+~PKS&L0PyTj-fvYp-($D0Lnx z>>aV8H`|%jM&Y99h`2Kldp`B@?#mpV-RrjV&VNOlJUWQ7+fz7Ce2?*UC&q{8TZ@76 z3aU6Srm6##e-U= zi-&yZy?mHOE-udG+&Lgc>mkDvyTzb$Xxq4TWXtNxIj}o>T0XY(J_|Cfn+wul_W05M zGp47qdZR;3tfPW?Ndb8L`fW*=XF841_WtmLg-JyHrTpw%*jUhlZG5iw)hF3uwZ*R7d*XLCCAJ4S9L>n3Cd3tS-+rd zOylUM<`UbfZ6h8#vUiS!e|SRirB!uieULP4Rh0g?N?)A$puz*ZpWd$>EEB0*G?8>O z@gzz%^kE0pNXgc%{OTFaVzMN|*Qti-7Wja8=kF49aURlc$Famnm2AkUt28sUzEuyv zDGY)?1IHxq0J+vX|x8+*AE1 z@nIwQTh>P!%~|@7IAvrBW$oU(8H842{y~dzMd(3{vqOY*_oaJm8v|8TL&3!rVacHg z9777!M$;*~G%FjVA_a1)BN&C!iU7sY%Q(0Y`&~#Sq zUR_(?Q1i@#B<<<3;2gtLyD8QeFG_=O2^_uMFP!q7)_Uw8cQo9;L^iQ*9RPFlD8$}O zCt#+ik=)6&I!UdkoR4mMG?QJ7)sSY%XGc%m`o*H+4ubj+Go2mv2D?vb3+<=sw&|wn@m1wbC3(vX zzs(7mN^zLO`=lQS7IQ>f;~|ts7F)J^oGDRkg9PZI@%MvW0s^tsw5*(E-bOsgb}@Aj_<64g7R06_UGlkreG2X#N3GJwcKX!}!r7X-#P06p6 zW%F~^7Z)PE+!7YJx@sr$rFK>^y~yPzgP8pnJV}+4#}}VA$cY^tvC;TslqN#$h31T+ zGYA=fo%AfFspWETeR7Y=_SfptIbbuBj#TY07vP|JUsWiRd<0TeH|9_l2W2n$_Z$oN zliab@h`fAlzt|+vC!@qy&Wk$s#*xPT3vns6*dwX<>X)SLxHGKw_zC=(Dm@PZL#6AD z*)qaE3=#Gujq{2ml6Pfd8U=HG^rh!h1xlD!;_R%baP`x1(+-_^9H_a4Ea;bT$R*L& zB~zVQlF01Y3MhYy$QY*3omflHQEr|fLBpXI)bHqV+`GRYRISBUOhV)uK10QQl+T># zRsY;8W;@c+T0w!MIId8eV#pUQL9*CUodV6sGg6eB@IU@Jr zk<5s3{8PdEjjGuGDmomefnKrULAyzsb5_T2(b3m5D~p2EVOK3UOtjMQp6S73hh>eC z#Yp~8S>uqJ5Su7OVV1w@y_QVD#f>HzD#Y|Hh>d{$9a{cXp6(aw$5DbC?c);LWgphv(djA4<|9qm01ly&eq> z`*{iCYtZZ0WH2P_dAd3VA9=~mMt|?~xc?6_XaK76cXGNz-X;P5Sbzc6q$E2xFrHfW zm6wNHSN~yrs#c=Mi^K~D(~0;jH&|uGu$+DIvU;JFOJ?PSnGP1*ARx4PupffSbU&yxC)LrCXan{@Awdj%{nl zwrx9|bZpzU?W8-lJ66ZG{X6r_o0)UY%;|Zm{{I*I#a*?pwO6fOb$>tWy5Ohcw@+%| zAxT9zWF+c7;f*sB)i3?q^mfVl1HgMcU7?(QdE3A-zer%4sPLmh(m)7hVUoeMw;55a z_*mfAws*km#4<|SY3(c%uJK?2l>52a>om3q6S_v;X(eGDEx1L2JRKE8m3BVm9-4e6 zB(q4VqPHZezm37-gkMvH0Whf20bS^UjLRlQJ+hlOE}&eiP+T468R)CK4=uHY^@ea1 zYjnxOJ~?_)3dcy%kXy+kWaEJz4DB@YtfPBU@h(X-V#A^Srf>wyj;voSCo*w+!c|&7|J)MJyy_~N=QwNw>=>yfeX~`w@5RE_m?JGa*$U{ zAgkcKLCYWRTu+mQS2T~wHi(M$evT~0q@@hC^7TG_h>HoSlxsfq1YKq_vGY&YZXOle6H2lmcust-dr_q?&nvzsS;}e$@S*WDF0pifk4%_>@ z8E-Dfc@R?y8*M3temR@E>su3c>ZiwNPEOytwQ4aE*Y@`}cFYnL_2ny{&{HeeTa(yYS`2bo;<|;fgUeDOR?+# z8+P=*L1oD;?H{2+Z?Dn|LO{@w`uLRktlE@ypAH;qizFV70+5bep)}1viDAD4J%M0`zB@x3DDJT_ z^>g_X1Lkk}KV5;aB`r|W85(0x7fP{3oLZhdTC=KaFY~O9g3*S=lLzyB>A{GB&~@yDcKR#fgk7UsU(_)AZLRPe{xU8uEwWbp}>wmkA?o zPyEOPI>MVlDfw440Q&&i*_MiXTS31?meki4ePPGh>Knn{3WIXq#?gp;QopU4dfSG@ z+~_7aj2H?`^#WVeBUu5U&+Jf{=R9&d+^tD`f z<=v{=#H6t0-t za&FxfPqD4}6b(%sTK0Fb6FFbCJzEWP7M|41bfMIL=%eU zhn%**MkAkcc#fZ|!AAQIT-L-!-!hck z%ty|XxXm{r-&NFa;7Sr-%(0(x2G1v*i|u5C&Q zXBKrQkmyQZ9IIVwi%p7sQzqUn!Zc$qH;{U$SV-<cq5v>NIlT7;K-Im$amJMle^ zK8hq{o|A6}V}(84*mfPY6W?`nMn!8WR;n?-nEmQ717pY-$+X`9eufb4IfR5xL?HkjgJqpF|fWi6WcRw_ZD7 zLq2dF`T<_d%45W=uEiz?*X2?_0}~cCKSm;)4rd#TZC0fKf(Q>q1kCcJmnI4W1o-9P z;mGLuE(fYch)&ZvxjUduZ7dPrDiu`^Y7bn7n{zc!ncnug1fCDA9-<`Pkf-MrS@;^e zjzb1da%c#*Mo$neS@g|~toE*qNI0(={v8wvCSnvP9mouqWfX=PEQd3u>!?d-Np|4Z zbqP>fA4!iMrb>=H7WnP}h|HpjRTOn&hNW79Iru`h_`=T|cJ^&-{3@}|!FM=NH%`hY z9qDV>fKN*UtErSC?qbnY1e`L*xg_$$*Q0M?yZM2K$U(0(o;na0gXWo|kn~gKbB*>-b|OhSOOYwloDy6Qm}#N{ zup+S8TJ*p9?~6xoy32<(cjogXdzQLs_~J{sLEhV7ff{i)T;m@t*||BLy7e1Z8cvTl z(WE(LKjflN!kfFVAS7!S5Ymth1UixLdQ_A~#W2!zKFO2P5lx)@@)J^Xt|1Q&)k5NT z#f+<(Y%OCPZ^Hli!$TMTe!3*u%;N~JEY|Qv0}11BZ(z0p4CGO2&JY_93e@b(+H#CI z#7g>>2@j$XDLo-&t&}EBAwr2LyTc%)I{=&Cxi{)thXI8ED25P`w86lmk4%K4O01fY z!qU9{B)$kOb&qLfP*tU)8mHoq&SI&eNUR%DvJ*<9z$iUGzU(4_x()4@?nyAnIp0cv z?NkM4CDF!wOXJZz9w3iYaL%gV=6JoX{RVfjKf`x*K zhoxx$CkKqV%2A);1xu%Aa^dgX2rCy-Kbo>44w?pk5#gm>(U7@gU|4Ue&0T!#l~tmp zwhX-t?v#ur+lpJ~#FKv2k&=@|HRmDiP$bww`eprqYM|*ev}M+sW!nl#;r9j(aNas- z9e2V&FWB(Jg3^s|ImW`j6{zv-1m?Do3bBTC#b+TIE61%e!@vsDszsT?zN}gJVe7q6 z<2}6^yVZiey{Ebkm~{KaHKh_`*34-(>3>2RNQ0<>Qj}qNsU!cD8kW{qA-hUum|mLD z`u+-}^1EHfI;r^Bna@c_w=|XQ_>`vO0f=biMkh$yde%2&J*qGuM*;PL)~p59%m6x@ z{Pu!1Czs$w+H>U1kNn-&Co#CYv)QHV&`*LN7>-BaLbc^ihXAZ8y>hvw?8;1-5jxpc zECv(?c_%*;_kQixQqL-Ki2f zG^fNeyOtYdCh-uaC$i%6&sjxYSznF$c)mCA(ft&ezG=EwyQQ0S2ibtOwZ*q~zqM|v zi+VOR#C1-hOGzP|P)}WI-8o^7tw1w}V@fbL-`RwhV=T~kWBiYy-QeSW>WUTLD;rC1 zWqx|!e@^U<&n`Oi2OT~m&5qo#ED-N2RGhnjdQi{Z9v&y+!lDUo>H>Lze!As7m*nHN zFwA^wq-}kuA(+2NsWF@oC>2X*ka72&7I1*G&^6XOfW}a#9-Be9tq$LM1Y@9e{}6l~ zg0r=J@v_jC_f|GUX<5#X(}P0a($vGn6gZ*kch|ehD-eB)@TLIz>M!kf#KrU7XYlF0;CDoZ}V5W9@OcVr$W6d1?jkWke2wPLKM;x;YYz`{#uQ1uxXHw^^%gJ%ggL1 zl6O1JP5!|C?m=FxRfM}5?WL-Ud&R7slhW7}v)jlGmVh-?xJz|>^M zYjaYY_AzN9QnKZd!3P~hV3GjJOlZuD>nS1RYAJ{q_T#+g%5U&gsyq7V3QfDI5{$h! zkOiO_s8V0jv%Uu>u5Vp*7DG9imewJKD5HlH zPd0#Z@D{?HYS1{!&PhyB8+=~^Q9C@A()kS{EM~=IIBRx8 zI{TFm^Bspc6HVc};=pDF=UVp8S&y}&TXCG1tfyNpbrv}5Aw@q+U)UTj^&{bgd!USE z15JN+7q5|Jcq3M-fzepKUi@$km9-QMnlSaskH$Xe^FYzW^{*FpsmdX6RGZf5lvwP= zdUsO1ld1;sG^SiunaFgKDb4%3uCg%o{8XrQkf;sO-}3sKY8t(w5@`5o(rlHjr}#z- z9RXVCcpmfW^8iln=&yNb`8TaX@sPJUJCEW`dgQXqGtq!PWIzAgFI#7FGCdby`Cg1Q z)*B5F69Xq7Ng(Nj?3LQ}@vR^x1CTN%`IqITN5qjS*9X-n>HDj7flSTE-S$G>63x#^ zNXK7VbrbB-iZe^C&O_zrZ3CEXZFbX|8g9U-Vmk1ZUjjAO)EBbEVDXS^C<_)BlI}W} zLEUk?X!au;LdxR!DU-ZW)#PhiL|kg8q>^!CXEtGEHdwRFNZwC(PVY~q?_(n~7l!Yx z$U22#I~*Dbf*fHo(v-Px|s2C7;+>(f-22H!EzpM9r zb=J%4h<_0-8!J|!Pc9~`8EHW~scHcfnEEqf0mOx_Id_x66@#>?A7yc$BR+>_7GGTy=6TuBb?zcyo$EnTiEjll2g>-ircN zOv%SA=F)#uYDLK?!($o@SndqQfMAnjnW_p+59u3jn+6r|*+CG|?*+9~%|$b_qxtA! z^>akjfNmTPGN4K5`*14=$N&f`&C<-g>-ucC*?*1*+n{@;l{2K|m|jcPk@7)ZeSjVp zXczxAeOVY;{waO`^L78<(wBvi`QJ=m7Dl%Jo@xKNfqzb47Do2}t?-ZZWoD*lX8OBA zj{m)om6eg6?QaV?|Mx;>4rY4xzm8Y_^Kky1^!>kI>{*zY{w9h!e*a=$t)c6j$%*Fk zSo_P;dirOQ{jQHRYR0u(R#D6R%0|m>vXJ9XAQGs#lJC9@N1(Wgu?hT|7?RxF+>h&D z;A|_gSC4bS&CfSKx*e%Hrv}m$bA*G)?z&;b;zB8JggVB*hFZ z4iG|6-jdsA&(z5{XypaW+|gZX|H2{-c_tL$kln!Z(S2uwQVZ<#hnB|8D3_(x7@VaX z5`|6dJ**AE5c<^5$X`>|f7Sb*Y!P$VZ(l_RNeCI@XM5J0d-3BDxcS@~b$$lkyKnYe zJ#DL=F2X#2tZqLRff#ZOP=PfZLkwn@qx{u~Q|Q+7_pmxzaYV9>n@_43F;ZH|`_1UcW%CO1zhS6rw0AS%TViA zkQ!3k3|I%AgeeYjyFz?n()9wGqyamv@#d_Ap7TKYUSmD8ePmWxa6?u|8rvZmmjQ}I zhLXQCsU?UrmBV+I4mkSvR-=8GUm`MO@WdK&T4qLuNi+>)feu=LoC(+Q$b`7mIKkd03 z>xIJ%=0?iEk1(+51p-}vFE-31yg1IOQ<@8JfFo7NhXVuHgNzAk)5eIl1IAVT@sTH* zXtBZ_BAdVf^{OP7ot1>~+4OT=XCSJ`MBAQln(8XzU}5>(DA zwm)5LGcTL$Hj>-+Y$e1ONAMP97JP`@vc8Zni3n$?3AUQ*?Ssy0D(Z5egh5lRE|mX- zCo_{at*P`5w)!}mp&(PWhgoC3FF(Dp^+&D}&;wWReQ|Ph#G_4Zyq&*4`-)D>kDq;h z-dem+pLK?bk6l1v^JYug1^n1^Vv)0vr-D#qxOpstTLp%-Yt00Xg7|4|a~{q4ic4FK ze)dIOY3SXifTv{aj=lIky(pBcXwWYT8l7Sd&y<7A1bS61yf#`jAt69A(a=!7-P#}PD_h$gkxScWM9@W^;`xL)7I(%XAxjp`q< zDMln?-&h8)?6V^j(wFi{xHUsWE}orM$bd^upDvsP(LE|0xxZ1IJak>AGji^V6HO-x zYV4MRULf2sQ3vIXy27s4BqKS-Z8g{mXfK00DD3YwEzjPS%qeN2y*X*@JJVDGB+bdW zs=i0yLSK3NoO>Ll8u)Y16WWn?WhWsgZv!9s0Gmgg=c?##{{-`XO;jJs2`7TTJ*l8A z2@#ZsGM1eLE>?XV&5S=q7~I9Oby)X+j47Uv%WX>z#&@TL)egDPnDR&IE@gJ#Py#>k z?wL`=@Mn@Vx|B+2{qkB5kLk7b>e_gA_X>syr6$UJILmBZvxjc|9`TS$Exh1AtA>FO zDf-=I5>*ep)p}#NB^4woE2zPV&P0uu3X~u_pFZcgvnb55cD?II6669D%?w%#L32NN z1)3;XOWmda*+^c3>lE19H_3&@Ku+0HdzHtckVR2*)r-b=ug`i(^(|k$@HYCn&K@K- zwT9C3Lx*#v7n-PXxT&a(v#)Gn?rAiql4iAKE8O%59~Y%%2THG(gM(jvuxVqqx4hb6 z=y@2LOYGzqiXUu;?`kSvTRunb7LuQ7pU|>gC(oDT!mCRU2zX-hy+gKGeEC;I z{)sPKzr`08CYC?*g^Br3CivF|eupny|0fju7YO{{@8?YHe}e)}Cbr*3fu^nVDksuM zj{bIfW_zEE<2yv!YYN589CeYbq_?weD2z6+uI+g9nZnDdy{UAIsZ56R3%CjC`73|t zf2yFeF}1Q0lf}D8_HJ|p$Fh>g*2dC!cp*Eyy87$6vc3OH$}G>FZDDA^#}Ay&?&JNP z5)EA?23W_Wf~1)v&+7{uNGv8DUaStw6SL3plgSkq*N68Bu$mAv3>`clnll#*>!H*VFfx!&?9gpa=H(?+vDtCP3H z2L}!wGziXe3-96L8S>#3bPY$=>lh&teS;C_7uszjgPC#T(2xsd$1bNJ-Jyf0t7B&x zy*kI~!u_+8n`<|x{$y>+sr%AA;_dP9{p4G&rH~l%qSMgJatj$c+B01hM9lsHJB}YZ zWxrwKZslp^n)_+yk~-m18>iF&R8irnp^-0aKlpb6ub$H9Ky!_chCU<;gTUJKO z5WDuQOO4#+hyIqVP{#tCMAQe%7HEfhvlR+5%la79_13-3Fcx)7oPhFs#(C$h)T}rI zNt82a3g{RGsTgOY4NeN7Sn+Lt{IBB-j1;vcik> zFAQg{fyPNdrE>~m2++5A)kwX=)Fi@9-U+z2`n>Uy75O>f+r4E1b0IJ%6euZpWD9my zKY8n9XUu+d1wr^*9VmAszqlBF1z-it+{7AN_vh0{D-+CAzyo#sU=2lGd*H!?_HQh@ zW3Rxgt~)`gY4x;uj{a2%N75*KeVg;7oyATorGb|hNJ1R$5hX!32%17*GIwqv?5p&{ zY#SAkoYh!^ceYbM>}oI1Kof6XGz>8+u_dmp&_5P6c_}iTrHZsTpC`q6!1pI-A(38B zf=BC!292k5C%$pD@o|fB3YKRW@3;AY;+D#_{`hr@?tr%v>%tCFWrA7>EZ8)=wukvM zm|kj!s5+RR($vCZQlfWKg{0H{QEb-|d&0E%$(?86Ghb;w3%knODAzvfLgkkH^s!9E zeW}nx^K8LjQ02=K$o*9aDm)j{JoH*~tYF+n^h~=En>Fn1D>O_iWcdaqNv0=42|P%) zhv>%eaH*t)-khZ%+z(NlHslDD4+G2wLLm2%UU*#58%%F1-azzWMR;ibeDWq0;>UgHDc{6Tyx5RDwxxyV~?)U9*zj# zHCZ7I2|Kj-*6IsP&7~s0`L_6ucy$^^^NDDd2u<-@e&o!I6GU1f4ZMnVN<{!X%@ZpO zf)wcp4%YE(krm#f531At3?aPt^gh4R_*UN+nVhI+H=z%COEij1$&qWg#*ziInbOT! z!t6V}#Y(BxgOlrD)$F7a#d2ynqS(b5`#roA5$aKVeelQO{fwrr4Wiy6_m{75l#rH4 z&_EUMhb@i?+8*IyP{TWkySbwh6^heuvirnMdKRvnoXI@#u58bfn`1BAVgE8hh zRVa&ijv+6E<1Z5p1JclB(~Koff--g-;E^5lo96`ISTR=RdxbNGEmYvm$SQ7Zh7g5o z%Da_7e{dlYqa^n+hv8wfCum@^27f%etdMsfxHo)+E~G&oDGx2{A_#h-kDJE7e{&_` z8_@oA0W6B!hr<0{P-vPSzojiE#~+-h0>R@!w1$V}!TNR^7%B7L2 zY$Ea6!}CM&=^An@@gA$fPKfmcxf!UR^3duRE28mSjtu!DT1HTTV3l9yVM4m7_M1)U zTHK&t2Cq%cBkvH`PdyAiV6HvGJYb_ zci-=+*!~$G?0>-r6YIZ? zk3V-Z{K_A?sta+ngHiDcC?;Xb%&Brsq6^iUfBuR7E=jJ zo7RRoOUmOiM(9zCwq&B+ldVU8jW$Uu-IeY%#*|iHdtei6?SAH(=_z${`x?A0sL2_L zp88cR1Q^+Ir|2Kq8FoilmCH}89lgdT(Qd}WINLV7LcK1m-@Do|3&(jYloM3j3OpaW z)3g(U48#WnQY_a>_&#j!KWuuqUvDQM7E=syfkEhNur>UVi_LR=8>6rews2F9gOqp6 zSCVmR1cL32)^p!o%mDS(HBU85$XhKX2R|YET1>U%hz35R;xtd-3}F40)owM z7k2vJK9*h=-psn&y0bnT+Pd|oeRJseC#D1@{vd-rgIZ+gnztOH45r%%5hbH;oH$BG z6lKkB4C5zfVVd|lf7^QaF-__?AR#uM!wY52N?dAjV>`+LFEYH$Of|=8Xh`%r!_QJ= z8WoSjb&=7K&onw56eIhkj)PHTc$WS8WsP5!cN|20c-@x3qXWY3*H6heZ}y?|TT9q4Pm(1;;-YmW=Q$(N+#OWSdQDZ1+NE3S9ca|I{L+Rv{#FI z{9(BMa&E}YO-gto@tW!uplqLtVV4Y|Ee_;{+{1fVs3j#&31Gi9p{N{!@H=O~M-@QU zqUGG5IE5f-W@H=#jL&ZIb|8JQ{y|U|&6A5v#z@N&oAp3RX&XzuEw-jfjz){Dh@res zi!HCWX%0Pj_K!Cdz2mhc=_u`>HjWQh-cr9DwI9o3Y7Qk>@L-TAy01cp4Y=*KJlKp& z_3Tppd9>up&^{bZ zzlt9;lm!p-w9ljc=sHteIBogR;Kup%?Y>oy&iL%h@XE=?Y#3aUxKxGA!QuOrsPa50 zqlO57WG0`QME_3&1!Z%6vED&)lbpeY+F`aJ$6xOf@Uuejj~@7eivtLt&H{*hgj(4i zD1fwgP|@{N&8wG#vUA#{rs_K7jdnqGm0)B4%3=O7Q$J?phpiYsdop;vBre*LgFLyl z7Hh2;^lli8n$$+ZEjs#(rNhQZ!h_b-P?eh>xX05u}Vd;-A>avdXD@~^Ds>9JY zRqTb>vtUD*>7}J=jOeEmHfHEL5?aAreW;;pB;V!=^!Cx^RA%hMZ)~gAt19unqtr`z zKYStQp3a%rg63YBPlqvM#8#%z2IXH__M3jNf&4-Xa!L-;SoiUv_my<^t`{Oh3{b7f zHWj);c~b{bP)-Jm&mEdDzE%t&ok4_Z3xxN)opo=iLe9#8tCUmZTPh^WsQegOrXmXg z3cvErR!!djJfVmywzhVIXg=*#7n1K)ZJVTgzKT%l-Ht0?iVz-Y3wKl@ntIdB6H@fo zS0(WxaMH^hJt&LPDD|4KsQ3sf<5DC{i5es{q-rgd=CMhL+Gxo=xbIf%+t4GSJ+SyiLa0N)m95``BI8mLQLBoZ0y@P&7x{T+*zjG z2xDVuu)$PTw!<-EVX(dU!D&?ps8is>EYAt6zL8*hX2EZTCk^>TVOl zi~=t8pbUwoxgw9_89<5Jh*yVHB!=g%iWm(nyO1Wg|i+&dj_+@IRR`-BcF(~ulQ zgU4Km$*<5~5+_I8;E-oZ0wup&P(LZ4KQcS^(7rPOEV(cgqLTdRXdOTKyeizBf)l296VY@6q?ECl>Ya=(>1v+au@v@6D6 zok)GuT!>Xm^NEK#J!l1`lRV`f#wa(R+!{CeP_5ZD-tH)oqFM^S$UmgorX=X4Kmp(01TFFnH+n(mlu_pOk`F?ZuNd-=(W3t+kw9d}w%zKTDqkDzfe;uTsn%FhF z;=s2B7w^j}Jf+a^9ate~>+cxF^^c7D7b^b5D9(SEQOrz#W)#$dwkJ5}3O->zygaW(u#Gfd@cy zvb>%?!UKpDhSGa0=i*`?cRh0-p<`T|@J<(Y2JNoTiU~Etvqkkx&JonkG#%^e0|#2& z((f%jgVk~xyL6wYP?9T~G3`@Q*D4WjET!j5ewapE36GaLo$*aE?Pz>B+AKA1ETnD_ zMviany!Hhv%|)s0a`2@4Gy%hx9$HL~;cj7;%GZ|>W+JB2@eLm#2<1nm_#fK_eP;FRjp?3P-r z@p)!?hSNjoe@=mHvrKUFu=Bq3n0mR{)#K6Q{r)gryEe`-{h3k;f$ZEJjW3a-r>5-5 zJmzebwedndJ+w3LunZa^K2Hoot+VT(p)#F3r7()(ubPp(>`y2M_Vt+v1?4(!QzmGaY!WLN>(XKqk%!)F8lO4=c z{{mHwvc~09!(DTo+<+J%lqLP%Jb|m43-Br|z2%A44^>Eb%5crzD`Pg3@r%pXwM3m+TF!o#I>j?(bTs56R@(C(|mqps>F`{w;D zOm@0k$*;zUcl2Ve8`a#&R?b!!*DuQ8Xly~DSJnw~hUlHkfwA+1@FQgB5}clNr2+2f3-844JRMzb z)%v8;_SlSEHFPwZu*V4N*R*^!=_^f6#+XM?B#JNxUd4GsIP&uoBcG*(5sXwYCl9?1 z00>EkHqi?AAWiZP88f+v2;rTt%OTV02(rRx1D<~5CQH5~DW)Be|0Xb61mW{IMxnrJ zO1a#3e&l%5>oh}Zm>4P5mv~66W%UZ?BwT!O&dbG+kHQz%+Rm|(D>lN z1WOg*B2rZ(9ERLj&?q>25NyMxf5S3j(L$daU1IHDW#+FDEu4BnLKJmQ=-GQW62a0b zRh@o@hgn2d$H~6oGdhH^l(#n{e?Fs8dZ@M)RmLUOom#oFV+Iq44&)h8Xc6eOyy0A$ zS)got-ZK`e#{l^P=6}zq%e2T+R&fWKu5bzWLVbE5H`*z97x2W?ZD8El^N9Kg7`2XS z0E7T=1(U2^ns`xtge<%bZ>+Ci@V448ES11G^SlUR1X}jF7E}FEqaFx+3mAjB=x*1x z56QKxGpz4y+kRwiX<9wzy-P7A&8BdRID4H*e|U>%)XtR{R_GqNNm?o%?ZI?SLhqDW zW{@Lj^J@lgC*UseWL|s*e~g}|^jmGH4yw*R^-zgNL}c?!GloWXwDimdLFqEt-aNO` zfjX_wxj-ej0ayHL>F*@?s=YmX?z(ryTQlq+g(&7MUFhgm;8oB()w>983a6BhTxDDa z{%R@7k?44t(SH3by14@{Ar9~G=FbUd!{BxGxIN0S0*usJ*%kbyekRlxjAi{|)5}pf z8BDuNvx8kyWjYY3Y3FdF>l0W>^;qU_lAD?3pOc&QFUif!{BI{W+n zF{a<+!SdDZ#*62fH(baSZJ?J1m@d)*y*i*O?dua7I9ASg_yUI>O~}%NY7!0FrK?Ox z_r!0M@&5RpR~!g$Y%uoV;Pjp-o009 z`&_q^pwFgqB}?g#lID^h--)gW32;K&F)Y;6xWUb?FQI@RUel~kB~+RJ#)dIW(d@tPHE(mn`-K zmKWRgFs*Fq&;$zph(etNg;LI|iJz!jlLdI{oSG^E(*Qmo0WVhhsYj*hX)&R;u+|h$ z6XjLlXOHQ4z}nclbB&ZxZ{@Buq&? zFe)h{3kR#9^Ja5ZbuHi-ka`vDxRMFMXo?8E#+#ynO6b9QRUhC$tXK#*4an&9FoB8} z9|yB7S${<(;co%?>~uAUU4FAz!8*8AUZVVNXW?!3%QC!M05#@%627Arm;N~Xfo-RS zW7JArVWB~1=(fUu{dICsPOxZ(o={!;ey==RMpVeq3TTnPk(^u-f*N2;2i*EJs_J0l zS2Ne7&c)rnr%XtT8L8;e?Ku)r?TXFv0}Qul3&j{}Btt~MuVuIAd-rumi1Grzce|)N z_gssbM`lwUqu<@2v^VpNO!U4&I7OV<)nr!q=#PnNJd&h*3*t2eRdJu3v~*h7h4Ux%KKp}U;Z6e7u!9U2uC{# zLn27Bk@Rdv4bwntOKkC}3ixnd#bo?WpC;^s!R|ZUJ*wEcx85x;$ou}7OSrg=3Yo{6 z^jP?&!BzNt-Bg@b!IUsXPnVLJ_41sGfl0}$zU~rD^r^QE^#_mX?OEUYk(xGJ;Qod= zei551BqN!EZo2^-(bP|&i8h|vFG@+C>NS$3GqBmWdo|$axLE~RbY-dYlrZaOc2RHP z*}LhD>6rN8oN8~~-Ja$WzDYt}Yp%QHcr6CtHlQ0b^AB(%9a=F01};(!9mFv>4G*A) z9QTG{`kDLgRQDJ(hGaxDGMc&0}e z*8eX1IQ}{NIRBb`?EiN5as4^_IDRwx*#E!HJ{Fe0$vzI&-){I<2v6I4L~Z0HL>`(V{2lDpNA1kQL)KYF7rX=&BC zdfwT2xqO{H)fO>detcbYF%;`T2M49ZdZ@BA@@c3Q8g@T-Ej?T%x^#KBFo>P1rF3$Q z*<}vo0)^XttN!W+s|-bzB%m{Vi&uMV`to7H%J<^7=U85|51{r(ZI4Gcm&omDQ|rt9 z-l|i|fv17EP%{DZ0{X$xOd;`|upOp;O_0Ben9$*8w?DdP&F%w9_($VqXtK+D`h7WW zM-AUp1RBg9hST3D z{DuH1F#TY($-feW$)kja6ncs}2k&z*+%w3u=0%@nKBN>sRBIIIKO2%!-nY-(mN2)Z zG=$%oOuc*CnU%2BARs)U=UnK%A-9oR&tA9LD^x5X9X%lX#N2Y=+Z(XhE`T8Y_%(zx zHk!LJ6YLpP?iGCa*_XBeX+W00aA)`J%5Pb!S}m-Xo=y->o_m8}ID0pSa1{{@?faE; zcQ?s_A|^%L5EwcMcqThr&f8fBzl>{Z1I1vKI&1;5r5 z%YY0F#SpwexeryK_e+}{VZIN{aRzgmC2E{^AOv;Xm;}sq%@L5;Y@FLyk-AiwzrEc zx0pZ2TzcK``E$)kWUg!cVolEBK+gYi4tVX#BW!YRCTw2E^}IJb0gHFMd=72wJe{3% zVeZ7zkES4`oS$vhiLv{{+R~X4=P13b5#Q-jOM2>_aqRZz57Ta0okwDGc@fHUf2;Ky z-ibfGREMw?ySA=)UOT>9(v^DQ8{S9YQ33e8?b1N-niXtYS8}#@bmHlMt=f}!J3b7N z+e6I#8LNybaOFnT=K8d|>c|4&|GB!VoBP4mxqt13~LM`ODg24 zq&j!WhH@=l?WnW1SfL8Hn`9-Nks1p6-pGPf6u~Cb=+`WsmY-!kOOm}|FmkGRXLO=z zLBB@AXc}J-z3LiZG{U)T3k;Zab0G8$<06&Sc52ZWtGr?ISL8vcd!ZH5mO@@mHWXTu z%zU%V?3LVXN94dc6ehD3`8E$N(ivS_uHLE5VWc6vey1+RbvkS(PJ2!!0Jl$~=a_-c zB8iY=M-?i)SiJ&r7=oAwXN@1t-6csB%rW$}W#sS{i%4h~22|Pz>Pyyn6)cO%)40!$@E8lg=6?t1nR6Zip`w##wfbCM|jy z)fsiF`OveT4gSY6qvlL?`&)BqXZcaH2IaolGC22MF+MVVd3tCso^|DSxwu=93VDNPN#!A$&dHyHtHG{GLPZZlTZpeRuOYj$8BHX0tiluH-K) zx|`AaM(``Uj}#0$gp+aWE=D#L4QkszfReissvR~bf1nJ~CC22-wj*!YeSr{NA7@lrd|1hb=`f@aSeT`DD%7uB~zb(6uRn-sHNGSn7mj|NzFs2#8%!$h3xC3G-z?-Pr-D_vnJO5_(=vv0{ z0<$N5ZoP*eu4d__@4Lh9lYEZQtK$fra@WwZOvi7cH4Azo{N=(h?SF(o|)s1XZAnT!S=`3lwFNn{#cSh#?sE3L5P?4Uq8SgWb9&TZ^xj_ zpsED;j}MiFi;IIZHv@yYrHh5D5xud!ErX$jtAhiBgQtsyy&avcp}D0o^&dR=ulr{G zlYIVln7<((7N-A`eEx^t{qHG=mFuqxVrKs1KmAPwHEY@?uC*Y4_Wi=k(l=EIlbR+48n>jG}vtD4zciCfzxBW-kdce!M6az zZ*F{jb#Q+5Aqzm)gr*M&l|{Nn&u2xL<0QSNfgyI^Xd5DynnJ37eag951cww*C=6*b>xwQ z&^KQQ_$C)bsz4Qk_eAxT2m|}AI^Z?)+q!}^`~8Hz?8Nks6Dn9Gap-6z<9CTE)b37i zx~DoBD)>(=v%mqWdX~Nrv~LFHSf)3g%!dou5xkf*6=8qE)i|oCAPcg z2U&Hhi*J8s;~NSxGBib<3adV$^IUz@+Dcbc_IrbGXjC+SgHvUsG>o<0(2a(E&3N;@bmCy%K z0GeCB8*Hu&abce2B+pPo_47=H$oxaLu2Wrc%xXqpMR&JV>dcevifbTSad|Wpto(4O zL&$Yh?;6rHEsIbNtZbZOZ)d}&p$4vLq23H6_${s(%Rql^Z5(Y1ARz=X5>5*6iX52` zubO~`=+^J0FMKU(i9%qKdx=KCRC0VBRu07z%+${|2ZbP_itT@2jNA`hD}Y5+56Q!( zXJYxZ!77{4(iqaT*wUpcR(>rUdD~?f*|4c5UkG@K44=0Qfhc0aNrbjulPNppkfl^b z5_vYGbuwjagxT1dteE;zQ0%?crmyi>iH9271!d&I*-m#(MUu{00Bcwq$nZEhv!m&} zwsm){IHRK9ha)IRob&%^GZT2I*Y^LTq)?U=Sw|>K#_Wr|vSiPioxxzj3^UfsUfBvM zLY8ciH7c@XDNAKZ_9c>JsqAS({l8N>zw@Z)JeBi*y^h!2%yEBR_w~K*>;8P+cL=?#yfH>XlHeJvTYYg{I=zx|-dsSK8f zbSn(}P?iz;sLP?}wjOEo78x0vS0={L`Kn#Kkm@ZBYYfIjY=z`%NLza-*@)+d>kn#+ zTy(kW14RvOdFjS|!7vfqP{4?CK&BepyJVDgAYk}_(z!y-c~LPo>oU)AE1Jlw?4?^T zf4G`~dQ@G0_skcs`-zH=D_pKHo$kuyd1HNx=v61dt7EU9&S|nfy)D8~k=t6*!Cfp-=>TG@@>Xyh zF}~pnH-_hD7=MtIKF;9b{O&}NWbzY7^RmLk0-qN&R}ZIjhAtIqXq26ss3I<1=y*^v zR!+O~$R%O`&7+szC-qI-ou1Z%oXU|QiIICBlvJ>Px=!C!;>ncsPE~6#HTv2`libXE zIuraJme{55 zDLY;Eq}bj}R(#K%sCx2=oqCD4((>%tQoj9ylSU0!AD(e|>qZCLDc***y3z9Hxru%M z+i8(Oc5Rq++^~Yv5q`_dL)yE_?)$M!*qGemt4z^#yk70wJ-ATNLMyhHO+Y6|03ta@ zk}5OZBmY{33B)#lqhU9S+f`5VN+W^f&ObVEZ;WDr?5Hl-CUpGNZjBJm*?r=bK4~L# z8lT>H@{lU`j3~QpxoA3G%U`;Jzla&I3@0)++eIK-2kIv?HvVV(u>z!QN1-@ zp^?tJ2H7%t8`_LIp~0PYyl~f-X))!nh?Hp3@wDdKr}n=turThiHw^P)7rg;S3us~o zT5mA%K!^D!Z$pYqY;876+|_&x7v-ARbNB6@MdsY)r?M1#nwuF3*Xho?ESHD}%C0=_ z5kHZx-)(=-)3@b~VRc@!xe;-0MsQHl6m_NFCaRw9kj_kyJIqIj<#B+Py-@WfWUa1b z-VE>T>Gqp$FD0Uo&7qsT(&ne!?^{j1vpbROwXMs3v87L#Q75o>hk)4;Kf|ciHzpbC zc{6+pC2S{+Y4*6fOlhLGoE~ic98bR3QDx_WEPpUHF4y;R>lN?Q^QVQ~l|+yFfaUJc z9G8ytQ0_kz1QMSDSDyn-``@apeLGVa`_vlwNE`w9Lk2}jVeB`3%58S zEj>^(qU{lRuY90)6lj>1UpVXfzjSXfIaK1fls*-%&$U@F#(%*b**~sxr4X}Asr|u~ z!W}Q`WbYiEVi|g}^q4=b(CaB-MUnn4QTp>rfgC2F?nr5R)5)`+S{v%UdbcRZR(-kR zBV9frU$<=Y`7r&13bMcJn_GOZ`gxiJ37He0wC^?1q-F_!Nb=jZi7QN7a3pbX+u64B z9h}`PJFOd!WzvRtE(U!{aE9jz7_3My-QRpjYVnnWl>bdH_DVmiyZJVSUfqOxMf#Ji z;k2DOdGTKka3OXGhiAKNyXX?*5`CfUi-oP&kaSJUr6RqU{CYwNo&0|1;JWPL4%4(* z!7Rb_>tHR8#E$y?MF`!1ECMn<*l)4D? zuSs1b@&~E=^&4PBt&Qll5wkX8zm14*k{G_G_uvTV+6Y@4zkiQd8<9Ve(8xcR&SjUS{K=mMgHsQgd@Rl zG!P052nC7&!H^Iz6tE#sFa`_%lVnO#Y+b-4vcvl9VgEcvI06NRV6h+s3=T#DI|YHp zf+4`75pV=h3cqRifGCNc1pL<*?n1W`6c1Zq-&5>8oF%C%up#4!wvGg%gQN@K zjGWgO0%8N!mAccgNW@=D`TpkrbSZzUUh1l-pY5GVUh5)8!v8#CG*A~1AYdpIjKrWo zSO^$_0$u^I4g~i9Q@9A|25JRLWdjImrv+nx{tT!3aWonjA%HLc&4~ZGwc*G>k$B=M zz()#Tr`IpyN67NKIfuirK(U}fPzVf+!BE$P0b?MD|9>qGv4J{4LQr573`jTx2pWY3 zS_lRVdvs1~5AVF;k#0c8gRGLMB}zIH(r2J_oN+mUQN+zHMU z@HZ)85A;Din22|mB2(PKj_xkb>to-@5srj|5lA3*pmSr8z?Q_oftY~<5e}o$vEPoJ z;tI4pZ?G%LmPGnV14sV7>rufM0`p7Y>pyP%ewYUXq0k607HH-_05c@?pC=+w7%&V5 z|H(wyKTkve6S3HzOj#*0d}Ni70-czq5PRU1Na(iE;LTgE zvs}YsDEqoZ9+Xpj$J%@NE@Ir|{S%W02KJ{&a`&ie%##A&Ben8%s?c zmDKEv8dYNxWg0UH+H<T+llPV-Cdbs?4TD+O^HTwBmkpX+t=8659ibAb8<_2j8cP8=n(-vg+MVAU19#SppdHA^u(!r(<9)wF_j0S zNs|Q^@`~)vSLxK=k%cq7GWJ2rPFWxppZPb!=*KV@*> z59$dT&|rR zIp4pNQLZy2J`cWY1N?O#s_un!^Hep|4pl(Wci9ZY|v(_fj7Ii zrsnQd{hV4T^8s&osiXGg=%?)?#K#I8uXeV{5T5XN6xyD=-Wr?o=CJ+vll^5Dmu9QK zoOblA$mS#Cw{IU0-=tg6@x|NC?7jLsZj*-!rN_pF;RuFLVP9V7uI_X`M*{WKL2On- z%2S#(C6uu%*I$JU!2I>nS(H;+Jvh$ZkDf4?ejAP!uO2`0`9t@p2y=J}OQT?A_A1}_ z>D#@reoy;S74*c%k!uDU`ThGfgN<4<*r+vQjaoC-YaJDiS~J#by%&yJdmd`- zd8oDLq1K*<{>dE{Vgoi72n4Wza1d}}gOO0||5-pRU<}}YV8Ok-yuj{&aiI|G@!nrG zhbx(M9Qa!lDc5hpNfK}8LRqh#&>QfMYcdsuh5^bC3c{kmXe=675frcpzp0%zuma=; z-U1Yj219{jLqd>XC=>~t@Nh5$Lp`VN{_K_O^BZehVNAZ!@oTcuNPYoW;B zU<)odK)8^kDPT{qgEPS$r|3Zah8p(zXg9zZpnxcZV=*8E5(V`83jV7VTp#KNEH?}WWDo-VD^xffs9oS-{_RkIlG@|nB3>Wu2D~;D zhz|7?2tdCk7zW3HQC~?7u)|Or+hKMGiN{GE>x12Zx&Gd~;J}VTz>t46FE|tdhQog2 zVEEU*!HRs{4qmf6c9spcLN46;CDsV*UhfJ@7-Qs{7wG-6{s!w=|!9@$66LR3n5`A>Y z0Y)kOG*Q3Z^-J4!x74mePUg6Mu@Cae5m3%%5kgC$v15IX3f zDJQj(wvt)Ll3!!W)8OQkrYB;3H*?lXH*b|SNPf#Q-Gg&c3#=-!28pkq&y(L!c3ZdF@LngnJx ze^|UZInAlZ`Si$Q{?WzwU~S9(p1WoR!jfJ>t0aqt$*zhc(cz_Tj~kA`v&QQa&-7re zw(7ZW*Ni^f+Va}jVhah;08xk@@Vl_-VNQV>cb}5kf!W;}M$Y&y?L7ge7Y|L#h5Gky ze`gg|?e#|P?seH~XIz$>UzWH?-!uwVnUg{sbK&vrJ8|XU?in^amGs`|pzg}EK6j1_ zi1O(ubBZ~LaNhc?eY{#{qPh_?)-XD=M{60{#L(or68TZL&PTT+>G7oQN{#Nm;mKD| z5%!S41=T3d?W9);SL4D`Xh~oEXiyfR@7mp)yM}HF>rM0RRLF3uyL9$m*D0unkaM5g z{YMSfYT5h*ZXGmt_(;U%SHiOrIWu!j3q?HBcAKYmglhV7K8l;yABlLkbjV%6X#3^T z=oE+{8;|gG+k&?)-L!OPSDV#N|LSXf#*+3eMi-(4RBP;G9VEO!#5TyL1g4%G+B~i1 z)w78{iyh_uB6IWQARE)@uCOFd;CNhOY1p-QVM~@7d_$~*S24+eXoV%Q} zRf-*hmQ1^j5-5O)B4{iXT5jcT3BZ-9DOTP! zzP&f&y%Gh%KbUpidg$_YF)_@N_mabk$8-sfc_b(LBs{zcazyATw{Fh0;~-9be0Y7v z_7^ny(SG{3;-;tjPYhy)604uwN|V`a%I=4VN@9%|HOc^?s=;>*#^cpq`yLN1XBu^? zlbHcRyy9u)Ps5aw*-Ee00cnY<$Xdm5bqRj@`!r z{QZIA*awA2XaY;5@|djPbtKRC&gV|~)=TfD1UAN*(d_5#FfR5TElEt2OJO@d`2Mro z>7cQPy`L+;WCcj3(|q)E^~Z&oOKl5U;!)inzVj0OL5Itr!Lx6r7KopI!XU9fYS8rz z@@pIaPX>ua{V9V)udzh*8cW2iF+|K7L&U5xM9dmP#H=wy%o;<)t}#jM+Hx}^XA{D{F09Swk1Q-GdxC8WWa-%h3Yj+$+bReyf z+OO$eAMgf@EewGHV*$B|fFQv@MS$RdW5iMsC=>;T{SG`@ORv2%$-%?tzvp%%rgkm2 zz(W9q4Ad_Yj083~(1E~!zy0mheoL#QE6#xclrHcqU|WLJ(g$5(X${I8Yu4$Zz^_svRfeJPGbTHqJPT`_Hnx5r4auWf&R@MgtZA4g)F| z34&oEU=;c{?d@6t6I_5Z1Nb4>I)O=K2Pujznc(U!MIhSYy}_=IuIr-5ZouZk0DFtT zP`d;ij0FrI;B|nq20kMZU<~v(5!m+|lfN}O7aZB?IL-x6Ss(L84w3H}hataiMK}}! z94ZJ94EP>{{>{$37PCFh<=cN>qjtvGND*v-b47|maCTZ>*w_smDpb^r`id0*4+*6f zI1FeT7!VYJ2E(Ag&u%=yRG90D#}of+3&C!H=YCH$6iPMOR0NFyBY`4^!mz-({rm0t zYp?j$Hohj>^?O$VKDgkBc9MYW#Sgh`Z>xzZovXO{^&U-bZE#$D`Ce~>Py3*AP3 zF|@*!m;$%DQVkF3yH$lrP*A|g$7XDbS=xS&xg>mKKY3sWHbI{BZB~!;3<=cz4^A(1nk?@0W_$ zPD_<0U*HW4icVJn37sDr_()$*Uo3ry&9*%y+(_p>qu$7!Vq7`&h%c!NQ8m9u-#STtX^Mt?o4PPVc3!w1_UY@y+q@Q|$FKK1)RTXfZ=!aCx2XNl z4zgXv^A)R3kMW#+1+Gi2`xp3F_oYck`$tUG*tPq1Fp9k{6jw*(nu(p!-g?#~O#0)y z;ca~7^U1ysMHGwqCcCtCaE;=fJUf~s9qI4+?{sO{mef8ZU01&=PWIkq9p9n=Gcl{+ zIJ?s{9SKC3)XZl17a8k!=iXuzIL7x{EE+w?m%k5A1rc@R9cvyO&k@Xi;sH6`@c5d* z0xFj_@$Qjtq(e@%?gxm z1u1KV2iaoBUIZef7lz%cxciBdnSQTMtMP8pG z-n4M9EI|_ns6~3DHq8m+?(oG=rTZXdl)Z1war1jQM}iif+3&qF9Xc_bxQ$bPA}27s z^)tdZ&^bR~Vn?&ryBqI8`5DnnuTKc(2BtuR2!n#^x`ohFfiRV6vy~gRv+%Sq*Qb{* z7<5$+D_jVkxRV1J7*E)hiME%~lKWK2Ng7*}ie$%{f=Uk^QFH4QHc+T7PfOs6K*R*2s93PHF1vJ{&#SByp3@gT z-CJC-z0)H+WW?v3oAh|gv3%c0M?9||ofCU;Jxj4S{_W@VQ!Ep*7>-ZiqdR7yzU?}D zM3>L!(=y;DGCw~vaEm%KaW>do>bzX<_LVtakHZJ=HOG+3Uf&)408=&6dhpU%Y>Bu2 z{DW6HH^qW1jDkv?zp!?4p(e{Ne_%}>>1CLVU%BfP&4N6?FTnZYu3XK_qgCg<50rM% znD4-byPXL+z3V#6zF*L8TfDj29(F|Tj<%UOoxGjF*{b?8p-efh`=pPQF{no_9)>U6mTDL9}htujC$Aw6G9 z9(xboRUd4A{zzPHg6Q?rAvD$JAI`9_$q}D(btLZGiZ_zz)N6E#e^QAE=88h5c-oq= zTZ%=Oc1SR#$Q8C|c-3z!Vl^t1f8|5Ddi4cX+i_l@SpG?G&yJG83r0RC>hK)*X9A8@ znBAuHHkZqKmpOTXGbc~tPeT+wJE zrW>MGn9&@LS3%`Pe2LOjy2P(4RGo9IOo&rqJ&Usykx zCFj=ECbJ~MOMDU%`SJo%{Luau-#KeT? zxreJ24*Oqu+W`6z;UJ(t+Lm<)=iAx#9|#AK5r2wsu-{M(0s>tdVQV9NZA7e%-+vFa zHlo)?%-Z-3=^&txwQ=ov(6#45*PaJmdmeP{c~I1khzI*GIC?Y$P~(6qr{4FWfMC#2 zG#HKfee3pLB_o+c0aO@nolg9g$3Ir*P%s)$Iw&+03<2IU)eT|bfQG_A!PwuyQ)@~Q zM|L3)!DJE7(^TbOcew2*g-uebJjzYr05DW_Na%+$c1$eqYutRvV(+RwX z1K5>hOCo(WpzDL(fTMsxsh4L!us}J$U{DYO2o?@#SQHFHrEPy?-fWyn4i0OE)0IrJ zCphD!phyT7aK=as8i_z5(I_|ujat8qjZn6=oFlPRBLsL+4Dgu>3#ncd`)?Q{FPt68 zp5pFdZ~sI3|ApO&L?8j*kEIe}FoyaWNqsH94~3}d$2mLOc(}U*p3Rkvr%>>A-(Lik zzfrz#SL$1FC*z0|dpw!4enlGqa(@v-EEp!)nS1)i-df&s{g{9aHlSc3~XLW zk}dg%m$4B*2ZRiC7X%8hqrjemQ%Nlf4nm-*p!v_x5yjgU?C9~=E&wbw@Jg&m&g-Mz z0Gsff|pYxs^ImAI!bsglJ@#F{R;spwyio<}<2s9Xq{>_7ydO_hpaCh{u`5G|J(ZkhM z%GJl+kwldIN+Q<>{%`O*p!XoCHxy7faOwh|fnEy#og0d^WZUD2wmvo_Z!i(>zCO&2 zpgK4Z4i=~dB(N-*NH7xl`#NAPUa$?G>`Wk0fMD16KIp%2fI?9iFqV3cf`Ngl z%ZH+|Kr{UP9fzYhf&W&(ws>be*+k`#9w*&S~uMIgG9Np>Dzp8j2skas1BpLOi9o`+-1r#Y56p4XK!4Oh*WSp0ks}C9HLa?)<{>Hi$ z!PcSBZ@%mo7%KGd2lCIk=KrzGzcbEXGopGj7mL&Q**B%{Z>t_e9^~+0zSY+!#Lswh zc*r4WU%Ow})>1kF$wbRNB^CmOV%$seZ$nX6oD)ehJmdP~f&HL(cFhAi317mXWxCHI zgRu-e!DGqvQi*Mx;u{xl_=<#!_S)80Jt;kbeDVaLoKP#0IB9RW2vy>kO%^HH>UoMGfhKBp z`SIMRFi~d4&{%8t0s}qv;8+V6p?X1kJZQyu+&39pn{Siy9}PK-?AleT|SfNg86@lICQsc1$k#VzGG{ zr5s}DBx;?!&nKqoRr&6{-7v(yS2)37!ADYgkrA0G*JZQ{8qZ8zEEHSPluBuo)D?wY zC3M)_8fi9iJN87#^cEqRKF$6k(?Pq_n@?2qs$pK}=JIP_)XVJLzw?nFeOlF#cOBRF ziSWIDb=C6H!?9EDp`E$AMWT@V4cX2-+<(aUL2r_$wWg0)0f`~BSo4voO^lZhc56eO z()^b;?dTohm!uf7XLVFI?MkarF-!5MFAY9&DZEY__pT-+~tD3Hy30O^S^<;Tt^(S!fui~6(4-L zMI%_+Hzkv=4P5ic>(%ER)A8q;g0Y7^vP?tz#nBeq)w%Zp80Bpo!i)Etz$p4uhPqTE$sJ&>CgZr3g{ zLVqVsrc*HaoGpDz$t5iHA3W%2|NiXvu?RfdL3+7LmW$~7udn1ie>i6(a37K@*J=!RwA5K$ zHcsq_B15EOZMBC}eP#FXTO}7TXmtyB1v_T<_8qRcwz60zyYzAKNun(i_cky-+J~!_ zx${%qBSYsZ7fU^1e^z0SO@UKMz2)+r*Xc#0$L;3Y6OtWlA5)AbJo)y><3(MsJYL+i z_v+0vE~Ce{RbHDeb#}b)@G{ZyLTf35_R@+GaZlQmWt|Kci63=>BRsIyW7>X`o13ES z<}Td$u2lV@gbquGrP2+nI>sTO7Dy7o1bt;_>Wd# zJ$L+i_WUPzgkk@XJ0f6fd=R$A2VrY`5Vpn#VQYL4w#FM_YrGML`GFUHd)7wj6#@!| z0xN_8BMgHCp#a$pfg}G&fVhwVsbpvKGj;|07eE^ljReEdXut`;z!)?fgv0<23fCD;>eanwhwU(3JX7!W8bNQQ#oFf!0bSQoeTpC26!C^%o+p*3JLlf7H!Q^0?~L~bJK%hXB(kCd^}Cy|zTTlgf%*XArQS>Y!5xaL57248b(gh9<4X8m=I%HLU?Z#x9{%?(Np)Xv z$S=7sIOd<`QCSKKjD(KTm`LZwiIM{5TQzck1^$c27zLSO;{?RsNdyL;S@1 z!C*i`_(kvc($tJHh}!M}3=(Q9V zThNg&?>_Zje6sX#VkcdtO~j-H?-=fJqVRrnSzqG4m7?7$o+D;XO9nRBmJlcB^E!Sq zb!TmD9@d;9PStfkM&`Dtp6iQKH6Pnqda;Dz%1NT~-Gle{ciBXS@IHH{ys6n?+jizK zmqyPLZjj~?UmonNH;PfVMmUM$)T35z(Acx9&SoU0j=^&*rl%zqTHbU(K(mdPun>?& z!~7g~HeTa)|Fde}y!_I%bAboPFmtrxMwfWtiv1OPAm>irl+_q;I@r1O$R>1se!*ks z9_=s8ojzx;y$>Psi!>jQ;?6s0s&_H2k9Hw;D)#Ed16m)IJ{4Ks3fW@zisups!{&_I z?G?NFMuXVLVy@cQ#6}!IGh@_Yi)mbrEzWkUX~lsFPh%Ve$Z}nK@t9Ac7R+D9th>3O zHEH&x%Fm-tm5ATD)X<(roRVqr*0)vZ#JZG^SVlC?O8L)9$e5?DdPBJd4!yV~S!?AK zm=s}X9(pU8|wD}zOkzG&25cfUq_!pDOfEK+*hb9Q!Os_a9Yb7ze9rJ2pbTZAn; zpF32=AGn7BXS_c-eSv|C9N~V)e8F9OTQD(lK|?@Re(tmXo8z}g&hrXeoE$iNGxE3# zZ#!OMu^rPFQuI|JuoWV^Hy{0c$MgD?+4_itSM9g;V`OSpCTdiV^`3pE;Vb9w@9E)b z83yG~SkAK*G;nn5n_;jt=v@FkI;AvB=()$SJ_hxs{@_ zNy+@$-RDACM6*=zk}=-t@vL6a@Z(RXX_!+{+Kg}bn@;S1Ys z2&s-*;x#Uie3h(c;BcFdtFCt}iJn8yB3>SHXJjeV5qWGt8`=8E+fnQI!FYN;!pI|ehPPu78qpht zE<&k$lynQd< z3Kb_eu^Dm-UeTjT)FAe*;E#t7tg@VgC3)bgYU#?@4M%QX~Xfmu~o7)9lK4;t+xw#w8wGNUfw++;bX!@K>j+wM7r zFAFRR8QESeT}=otK<1ncn%I}Jykq7r^zj~%fS0!uy+vCfFyZhydDQYM6v?1GTF5JT zFgyEfpFnK(^&%RcOHG{?xqVC{p4aKx1=OKDG!e{?76>|s%@@_c+vi#roo{nErr;Oj zB|`P#BKZZ1CvCh_owztw3XR8PlXkQ=qy@h4?sK@Q_JH@0)%K_FFDCQvKgm9x8UqPu z^WHRnauG+zy4{m+*nh{DQ<-_Ag0%G!{23(r!FR7~-|6T&w@Ecz6!lJTa=YZmej?uf zOnFUv?X~$$`+B&qk4c8@y!s;KRmwbh5oA{eW-hhJi3(!OXvC2P{OTl3?@S$Ky%u(* zhyfk)p}+EoGsrqtCF(?dRwMtxorij8C0mT+n@Hnso&t?!BAc~PtcG z@bU^V=a|@bJ@AD)M$fAQ7J~f^>-Wf=eF*EB`dltO*!2MQ0UIbj5+CfW?xK_?)o+r! zQ=M(`A#{KLZQob>`$b-I3gBPczEX)&J+*78bbIn9)V`b*r5=F_EQwdlvFzgN&Z6=p zc{#(&2z`xWX#!*Db(5=w9lOp8n$&o~&yVY}H9qmbw=H^kw5OSMZ&h{ooM20c8)}=a zVp}#u5^WU0JYSw4we+GtyYbb2FgH`sg1KN);zZ{MLh3GQgRxEf3{tFM!FvVGUaQvY zFEn_BcwJ(+Gi7w=2zQ@b6j6-FO$Xx5rvz=-ai`YG^!TOoY0=oUN9C^uSs#hhTE;%| zH!%$hl;e1KH^1+ysG7qA<%qpuHHLdVE%&q46qRjPwr6*`@N%ErF?`nN!~({&#efx9 zXRlOMt?V>>4!>%l{E8nN2l1%7VHIvMbcIf4$C-z!vj$q;171TZlashpXJu=o8)B3n z7{?0OvT|t-JbBFOs;=iDcRV{;jIV^#JKjraw+us-m?qu!GK#phSxYuwi4SwS!~H47 zbMadxIZfp~LU-TU$~a1{(|NK5ve&B@=^AK~qc<_?_ICmXaqeWRz7aCU}P%0E@1 zb=dEtnZ4m5yK)Ef(Os6$wLwRoFrP9870*8_T2wz~bJKP-<$i>rI&`9c)4fO^Ga0w_h8dwD27XIK0hXQy?Cz2Xh zr%->FA_aw@;V>-nuiGd`92qd6crxIY-6g#MLoMmzLveGK^uiO!c0@d7{e?GtBW@IM z%NP{kK2ZoT6omjGuvjn*35;kY7=rqJSL8q@dAL%*4kVI;Gydy3zkc(5Z5|XnnIdIF zCV5ftR_>0#KCqKo8vxgVK%gNQl)Wtug@D4=FLEPR_4^_bC@>5T1;OEnueZ(!z;QwU z0EfBY$WC7!D%JP7051gCu2ME`xZ~b14|h)&cQS$CO;{iQMy%^v{4k*S&?qWC1fu}! z4uitLDAb?rAPUaK2KP1oum6&=BiT}bbrGpQuE26Al5i=C3l-!L?ZL>OUF#y&+gZe~ z*;xbv@lO+BASBQrpxB@ISp@Q*Cjy2S3|QA6=b`?29u$M2lA@m&=>P45f!6^={lxrA zsbGMB5a0jL-!1b0S?6DK$jF~LWGL{&Uv$W=|L2g+GLyI7OSZHBG*a(5Fe6QrynPd{ zrmCTKt7V(=ai8KBt4neq#qi8q?1X-;Ciq_Ot-K>ot0^>GW)e(h0*{Av9ycD-GzF7I zVtd}U*>ov$QJTkhjDl}o(|El&GQguJ>&*?5olAcnI?y(XQVsHhxu~hf4wpM`eo0}A=QgV^5o@`3;k=7evHbE1Lus7im;QU9<&jIq zZ%xh2rRSIn9`+YG^c}cj{7TBiq{3~vxY1Dh2)lj15-8+BaFR>>)7`t?Z(#{J>TNAN ze~`b=h7M`FjidzNxJ(x^1- zWk9URF{6DkAl0C_8%mMQw_`g`z1V*yL490tC5ZlWbhb%Vik;hN!Ae<$Y6zj=u~67N zXz6~XoO#&u`w_b1*(04-IZkcKX|+Z%rGu`tb}dxE_ks_1*!P5j1T7?&6cY34Z6Xbq z--zVBb$P#sOS#LFMYCOZq$hW)N@>2->(?2k##-n3TA=Akd*A38^QjaE?k@Be4P5 zsp{>ep#6pw=sRWR)e^hilZUK~Qs+;D(MEMm@-;V_81g&f6vIzkxhuOypD~k)A$}A(|Mjs9{ z(K3y;iEGz}4a?u*VXO_>Il*z2=BA=19X}oOy(0w8XZwbUOx`&+ENCrh_XU-h-r1|L;ZsNEK!}&0cZYE|?`=_ud=Zzj2;CNU zZ0DxK=OfMU%x#-FbYuS(40oz7oUyLXe(*(-9{x7}$euplnm)&Lhp-~Ja;r#~ed$_l(%mL4M-&}{l7y#%Udz1QKhCEuJrEmb}% zp=L{;YrXZf!*EBl?CNeM4XcA6(B~nM_Yxsp1)^=tYIQD2rzBJ&n%5Z92F}^{BLg{aupK5! z?~fgNytL=i(I%rUE}WKc?T>&orh3b*XbX1VbJw3>Oqt4vEGc16-#HYDI7&i~+|@rW zGkqR3EB2I&mY9=~Anw(C`Qgw-5d0y0>8=v~@fr3HmYs~vxui6;dA<_y3!(6)F#|VD zwo!lKg5r{Xvx};J8hNjR`L&^&u;rTPopU!;J{auZbhG4k)AOw(e4a_0&3!-eL@!k2(D)740u|p zmem~#7}a`R`uNrKv;FbR?Yrqmn>+^74~&WiL-{u2xL#alB#c^z5-NB)-&q+)`SWCf z2uG{0eYDrV$_0k7ih40JkJ?#1(N1`znwe{Y9v&T@HE`2c7vwO}amN@jp`VY6wO#a8 zhGvA`S;1!WOY1L*o!?{UybXCzEDP#E9}~}4s2nO@r&HmWqopquwf)8L%lVmtAPHI} z=XeHQUU?4gWW|?WOPw{AIgD>S9gUe!^@L@GUy|7x>r%X0Ane<8zxng$;uqJ#>6=!@ zj^AdJiPYzy=_+NrJ@uTmChRygPXo4npNMQ;yV=XI>O(m&KjR+KYNU{u>^Ax7cTwcP z8?Sl$1p|7DPwE*EvkA_o$QPXF)Sm~z6Y{G4b!zj9!jrDrC|eB}lyPY1bz-gOUwoAH zb97gzOFil2*;|_wTv_>SG5UN^A+J5@V#Oj%&G!Te=E1rv#2i=H%yCurLzw!9>pR#$ z^m9~XOmg}_$k-rE(E{vFf!XnQrtF{Xz%j}Mb8qZ_VG zhTbPKxN&IMHAgbIp>;oGhQn^g8k}d}X|SwddP6WoeW`V3Vmg5-T}kZ9eLcngkpS)@ zGbI;V*_}<{> z4wAK*(?}s4KPoS@`u44mPF=M!(>wM$@da2-yZC1KWuntb9z`~$L09~~(Zus&Tm*h4 zOLh((2~hUOQOi!b!+RzOFr#C)pL<*OU5UG5+dcGn;rum=lRC$<57Z96EwczUGJMf^ zEA8;ZR#27wF$2q+HuAT04W};7*fATXYir$rwDZiDfS5bvYjtWf5+tdicBNf0@SUEU}vKIs-KU{-Kyl(cT*~NTl}!8pFg|@KS~746xQ{72 z7m-4*J~(pTKa-u8tTyo_V_>yR%DN8Mt2Bv9K3JIT?uvA`_P++1>)mTwPE(ZLU7A#U zR{fxbKiy{aB!i!LS>*rrvdAC3EaKO^EFjm{dszhfN3V+5fKz}`FA<>#KoY{ia6rnz zF(@!qutKp2Fbwvawr|~is2$G1i-4#49}gl4(AA#n1T}KKpho_pphm90=Ry9bzC}TS z;4#pjOkA(T*G)vAVPH5G{*#I8mH4`e)H^m56#0{h>!tX*i7+?>a5z6R4Zk48|E|9O z>;2UK>GfYz->9FdZ#3+e)pvo(5TL%<{oh;Fl^unnwB|GnX2$Ik>mLfg81LwFnbf?N*3MsKx zuQt!ZO+L%j>$$ob-@h~{%x8jmTbORhI(~1@htRY1C_7{0ZKH)MOeKg12WO(kCA2O| zWNGE`x6347*u_>^5hJ<1H7;xG-oTE1wL3FgDS9|<;a#rJE29*4hIpkC33JVdwmxq* z3cei1&LFtGZHnp8mWaFqVXG&j>$D}Vtm5`>ubK8{dnh(2muGNGQ{SWfwfIrSz7xmt zzwA2QA+Gh1k%ioQAic}q+)nHbYJTXZuL=%VuJR@UbN242pg6|+3&{<4Gsr-``Mtla zL)s;~gZv__I;;bG%o;1C)DM3dYHhmmSm9|$b9SoLP_@67E!WdiRh0=1lfq-0`((q7 zz~k3w17t@vPN+zn@S8mT@Djv4=9yA8vrQ? z-H*C@thqLFxKyuWve4v;s=34AdOx$!E)r;%?_E7^rlv?Ev`YBls=uGtn`JZG9a2R_ zy(jn((}%`BkDuW0`I3H@^trYbf71DQ+?I>%sSI=ZFcjZ>H{yf&p$`{3lq8QczH#O5 z=sdm8c0q;Z>R5_st-6}l3wte{n}(WGa3(8p6$j5<6noTQ`f$#P!=&)*ky=BLv_7}Q zhvMEwwI|fLGS%dlK4u&3UJgli$FbQJ$G6>3#08f|S(-GL_PM?FWVyOWb=FvUzw5y$ z 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

    Bqf0t^#OIJX45&Kjo$0K$^G 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 literal 0 HcmV?d00001 From 00875ddea2a91e4d212900d38fc880f1d7f81605 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Dec 2011 16:27:37 -0400 Subject: [PATCH 091/484] Return a sorted permisions list by namespace name --- apps/permissions/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 13e367e21c..90faaf7210 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -50,7 +50,8 @@ class PermissionManager(object): @classmethod def all(cls): - return cls._permissions.values() + # 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): From 4cd36026b9f87885f4dde037b78e054060820498 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Dec 2011 17:06:41 -0400 Subject: [PATCH 092/484] Add migrations to convert existing databases to the class based permission system --- apps/permissions/migrations/0001_initial.py | 105 ++++++++++++++++++ ..._unique_storedpermission_namespace_name.py | 81 ++++++++++++++ .../0003_clear_permission_holders.py | 61 ++++++++++ ...n__del_unique_permission_namespace_name.py | 69 ++++++++++++ apps/permissions/migrations/__init__.py | 0 apps/permissions/models.py | 4 - 6 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 apps/permissions/migrations/0001_initial.py create mode 100644 apps/permissions/migrations/0002_auto__add_storedpermission__add_unique_storedpermission_namespace_name.py create mode 100644 apps/permissions/migrations/0003_clear_permission_holders.py create mode 100644 apps/permissions/migrations/0004_auto__del_permission__del_unique_permission_namespace_name.py create mode 100644 apps/permissions/migrations/__init__.py 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 90faaf7210..d823a2288b 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -89,9 +89,6 @@ class Permission(object): stored_permission, created = StoredPermission.objects.get_or_create( namespace=self.namespace.name, name=self.name, - defaults={ - 'label': self.label - } ) stored_permission.label = self.label stored_permission.save() @@ -114,7 +111,6 @@ 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')) # TODO: Create migration objects = StoredPermissionManager() From 3338035232f3e9ee94e8fccd6c001dfc876b53fe Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Dec 2011 23:48:07 -0400 Subject: [PATCH 093/484] Add convenience manager method filter_objects_by_access --- apps/acls/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/acls/models.py b/apps/acls/models.py index 942fdc18c4..bfdc0cf95e 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -1,5 +1,6 @@ import sys import types +import logging from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -20,6 +21,8 @@ _cache = {} _class_permissions = {} +logger = logging.getLogger(__name__) + def class_permissions(cls, permission_list): stored_permissions = _class_permissions.setdefault(cls, []) @@ -238,6 +241,12 @@ class AccessEntryManager(models.Manager): content_type = ContentType.objects.get_for_model(obj) return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] + def filter_objects_by_access(self, permission, actor, object_list): + class_objects = self.get_allowed_class_objects(permission, actor, object_list[0]) + logger.debug('class_objects: %s' % class_objects) + logger.debug('object_list: %s' % object_list) + return list(set(object_list) & set(class_objects)) + class AccessEntry(models.Model): permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) From 4c17910e8c16006b14ccd3461c9a8bc778ac80ac Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Dec 2011 23:48:46 -0400 Subject: [PATCH 094/484] Conver object_list view to use AccessEntry.objects.filter_objects_by_access for simplicity --- apps/documents/views.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index ab41c4999f..c203e01eba 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -76,12 +76,7 @@ def document_list(request, object_list=None, title=None, extra_context=None): # If user doesn't have global permission, get a list of document # for which he/she does hace access use it to filter the # provided object_list - class_objects = AccessEntry.objects.get_allowed_class_objects(PERMISSION_DOCUMENT_VIEW, request.user, Document) - logger.debug('class_objects: %s' % class_objects) - - logger.debug('pre_object_list: %s' % pre_object_list) - - final_object_list = list(set(pre_object_list) & set(class_objects)) + final_object_list = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_VIEW, request.user, pre_object_list) else: final_object_list = pre_object_list From 2afeabf03e806df55b3fb700a3504a316a19d674 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Dec 2011 23:49:33 -0400 Subject: [PATCH 095/484] Update folders app to use relative import, move permission to a separate file, import acl usage --- apps/folders/__init__.py | 22 +++++++------------- apps/folders/models.py | 4 ++++ apps/folders/permissions.py | 14 +++++++++++++ apps/folders/views.py | 40 +++++++++++++++++++++++++------------ 4 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 apps/folders/permissions.py diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 53f7dfb113..e2d847aff4 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -1,23 +1,15 @@ from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links, register_top_menu, \ - register_multi_item_links, register_sidebar_template +from navigation.api import (register_links, register_top_menu, + register_multi_item_links, register_sidebar_template) from documents.models import Document from documents.literals import PERMISSION_DOCUMENT_VIEW -from permissions.models import PermissionNamespace, Permission -from acls.models import class_permissions -from folders.models import Folder - -folder_namespace = PermissionNamespace('folders', _(u'Folders')) - -PERMISSION_FOLDER_LIST = Permission.objects.register(folder_namespace, 'folder_list', _(u'View all folders')) -PERMISSION_FOLDER_CREATE = Permission.objects.register(folder_namespace, 'folder_create', _(u'Create new folders')) -PERMISSION_FOLDER_EDIT = Permission.objects.register(folder_namespace, 'folder_edit', _(u'Edit new folders')) -PERMISSION_FOLDER_DELETE = Permission.objects.register(folder_namespace, 'folder_delete', _(u'Delete new folders')) -PERMISSION_FOLDER_REMOVE_DOCUMENT = Permission.objects.register(folder_namespace, 'folder_remove_document', _(u'Remove documents from folders')) -PERMISSION_FOLDER_VIEW = Permission.objects.register(folder_namespace, 'folder_view', _(u'View existing folders')) -PERMISSION_FOLDER_ADD_DOCUMENT = Permission.objects.register(folder_namespace, 'folder_add_document', _(u'Add documents to existing folders')) +from .models import Folder +from .permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, + PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, + PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, + PERMISSION_FOLDER_ADD_DOCUMENT) folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user', 'permissions': [PERMISSION_FOLDER_LIST]} folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_CREATE]} diff --git a/apps/folders/models.py b/apps/folders/models.py index d41d25c6e4..f2a83ff32c 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -23,6 +23,10 @@ class Folder(models.Model): @models.permalink def get_absolute_url(self): return ('folder_view', [self.pk]) + + @property + def documents(self): + return [folder_document.document for folder_document in self.folderdocument_set.all()] class Meta: unique_together = ('title', 'user') diff --git a/apps/folders/permissions.py b/apps/folders/permissions.py new file mode 100644 index 0000000000..665439c1b5 --- /dev/null +++ b/apps/folders/permissions.py @@ -0,0 +1,14 @@ +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission +from acls.models import class_permissions + +folder_namespace = PermissionNamespace('folders', _(u'Folders')) + +PERMISSION_FOLDER_LIST = Permission.objects.register(folder_namespace, 'folder_list', _(u'View all folders')) +PERMISSION_FOLDER_CREATE = Permission.objects.register(folder_namespace, 'folder_create', _(u'Create new folders')) +PERMISSION_FOLDER_EDIT = Permission.objects.register(folder_namespace, 'folder_edit', _(u'Edit new folders')) +PERMISSION_FOLDER_DELETE = Permission.objects.register(folder_namespace, 'folder_delete', _(u'Delete new folders')) +PERMISSION_FOLDER_REMOVE_DOCUMENT = Permission.objects.register(folder_namespace, 'folder_remove_document', _(u'Remove documents from folders')) +PERMISSION_FOLDER_VIEW = Permission.objects.register(folder_namespace, 'folder_view', _(u'View existing folders')) +PERMISSION_FOLDER_ADD_DOCUMENT = Permission.objects.register(folder_namespace, 'folder_add_document', _(u'Add documents to existing folders')) diff --git a/apps/folders/views.py b/apps/folders/views.py index 09edaf3874..ac596086aa 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -9,15 +9,16 @@ from django.core.exceptions import PermissionDenied from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document +from documents.views import document_list from permissions.models import Permission from common.utils import encapsulate from acls.models import AccessEntry, PermissionDenied from acls.views import acl_list_for, acl_new_holder_for -from folders.models import Folder, FolderDocument -from folders.forms import FolderForm, AddDocumentForm -from folders import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, - PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, +from .models import Folder, FolderDocument +from .forms import FolderForm, AddDocumentForm +from .permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, + PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) @@ -143,19 +144,30 @@ def folder_delete(request, folder_id): def folder_view(request, folder_id): folder = get_object_or_404(Folder, pk=folder_id) + document_list = folder.documents + try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_VIEW]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_FOLDER_VIEW, request.user, folder) - return render_to_response('generic_list.html', { - 'object_list': [fd.document for fd in folder.folderdocument_set.all()], + context = { + 'object_list': document_list, 'hide_links': True, 'title': _(u'documents in folder: %s') % folder, 'multi_select_as_buttons': True, 'object': folder, - 'object_name': _(u'folder'), - }, context_instance=RequestContext(request)) + 'object_name': _(u'folder'), + + } + + #document_list + + return render_to_response( + 'generic_list.html', + context, + context_instance=RequestContext(request) + ) ''' def folder_add_document_sidebar(request, document_id): @@ -243,9 +255,15 @@ def document_folder_list(request, document_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_FODLER_VIEW]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_REMOVE_DOCUMENT]) + except PermissionDenied: + folder_documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, folder_documents) + return folder_list( request, queryset=Folder.objects.filter(folderdocument__document=document), @@ -272,11 +290,7 @@ def folder_document_remove(request, folder_id, document_id=None, document_id_lis try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_REMOVE_DOCUMENT]) except PermissionDenied: - for document in folder_documents: - try: - AccessEntry.objects.check_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, document) - except PermissionDenied: - folder_documents.remove(document) + folder_documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, folder_documents) 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', '/'))) From fed62fb3c347065c6f6ddde328694b738f79a7fc Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Dec 2011 23:54:29 -0400 Subject: [PATCH 096/484] Rever to absolute import until circular import error is found --- apps/folders/__init__.py | 4 ++-- apps/folders/views.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index e2d847aff4..e1876c5d51 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -5,8 +5,8 @@ from navigation.api import (register_links, register_top_menu, from documents.models import Document from documents.literals import PERMISSION_DOCUMENT_VIEW -from .models import Folder -from .permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, +from folders.models import Folder +from folders.permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) diff --git a/apps/folders/views.py b/apps/folders/views.py index ac596086aa..7821391b2f 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -15,9 +15,9 @@ from common.utils import encapsulate from acls.models import AccessEntry, PermissionDenied from acls.views import acl_list_for, acl_new_holder_for -from .models import Folder, FolderDocument -from .forms import FolderForm, AddDocumentForm -from .permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, +from folders.models import Folder, FolderDocument +from folders.forms import FolderForm, AddDocumentForm +from folders.permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) From 0fa3a07a732c3365528727519d7b755822651484 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 20 Dec 2011 02:31:01 -0400 Subject: [PATCH 097/484] Improve acl tag logic --- apps/acls/templatetags/acl_tags.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/acls/templatetags/acl_tags.py b/apps/acls/templatetags/acl_tags.py index 3467a7aa49..f180cfe8f9 100644 --- a/apps/acls/templatetags/acl_tags.py +++ b/apps/acls/templatetags/acl_tags.py @@ -25,21 +25,25 @@ class CheckAccessNode(Node): context[u'access'] = True return u'' - requester = Variable(self.requester).resolve(context) - - if not permission_list or not obj: + if not permission_list: # There is no permissions list to check against which means # this link is available for all context[u'access'] = True return u'' - try: - AccessEntry.objects.check_accesses(permission_list, requester, obj) - except PermissionDenied: - context[u'access'] = False - return u'' + requester = Variable(self.requester).resolve(context) + + if obj: + try: + AccessEntry.objects.check_accesses(permission_list, requester, obj) + except PermissionDenied: + context[u'access'] = False + return u'' + else: + context[u'access'] = True + return u'' else: - context[u'access'] = True + context[u'access'] = False return u'' From f82a5091ed1b88af2fc6354cd90689de6911474e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 20 Dec 2011 02:31:18 -0400 Subject: [PATCH 098/484] Update navigation tag to enable ACLs to work with list's items --- apps/navigation/templatetags/navigation_tags.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 815af1ea0d..86b625ab0c 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -249,7 +249,9 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): + # Pass the list object to the navigation template as the navigation object return { + 'navigation_object': context['object'] if 'object' in context else None, 'request': context['request'], 'horizontal': True, 'object_navigation_links': _get_object_navigation_links(context) From c4508f486bf7cf37b170485b90e0212f25aca1a6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 20 Dec 2011 02:32:43 -0400 Subject: [PATCH 099/484] Update folder_view view to use document_list view, fix all absolute related import problems --- apps/folders/__init__.py | 15 ++++---- apps/folders/permissions.py | 4 +-- apps/folders/views.py | 69 +++++++------------------------------ 3 files changed, 23 insertions(+), 65 deletions(-) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index e1876c5d51..881ce8a3ce 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -4,14 +4,16 @@ from navigation.api import (register_links, register_top_menu, register_multi_item_links, register_sidebar_template) from documents.models import Document from documents.literals import PERMISSION_DOCUMENT_VIEW +from acls.models import class_permissions +from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL -from folders.models import Folder -from folders.permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, +from .models import Folder +from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) -folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user', 'permissions': [PERMISSION_FOLDER_LIST]} +folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user', 'permissions': [PERMISSION_FOLDER_VIEW]} folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_CREATE]} folder_edit = {'text': _('edit'), 'view': 'folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit', 'permissions': [PERMISSION_FOLDER_EDIT]} folder_delete = {'text': _('delete'), 'view': 'folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_DELETE]} @@ -20,8 +22,8 @@ folder_view = {'text': _(u'folder documents'), 'view': 'folder_view', 'args': 'o folder_add_document = {'text': _('add to a folder'), 'view': 'folder_add_document', 'args': 'object.pk', 'famfam': 'add', 'permissions': [PERMISSION_FOLDER_ADD_DOCUMENT]} document_folder_list = {'text': _(u'folders'), 'view': 'document_folder_list', 'args': 'object.pk', 'famfam': 'folder_user', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'children_view_regex': [r'folder']} -folder_acl_list = {'text': _(u'ACLs'), 'view': 'folder_acl_list', 'args': 'object.pk', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} -folder_new_holder = {'text': _(u'New holder'), 'view': 'folder_new_holder', 'args': 'object.pk', 'famfam': 'user'}#, 'permissions': [ACLS_VIEW_ACL]} +folder_acl_list = {'text': _(u'ACLs'), 'view': 'folder_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +folder_new_holder = {'text': _(u'New holder'), 'view': 'folder_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} register_multi_item_links(['folder_view'], [folder_document_multiple_remove]) @@ -40,10 +42,11 @@ register_sidebar_template(['folder_list'], 'folders_help.html') register_links(['document_folder_list', 'folder_add_document'], [folder_add_document], menu_name="sidebar") class_permissions(Folder, [ - PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_VIEW, + ACLS_EDIT_ACL, + ACLS_VIEW_ACL ]) class_permissions(Document, [ diff --git a/apps/folders/permissions.py b/apps/folders/permissions.py index 665439c1b5..6077438f42 100644 --- a/apps/folders/permissions.py +++ b/apps/folders/permissions.py @@ -1,11 +1,11 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from permissions.models import PermissionNamespace, Permission -from acls.models import class_permissions folder_namespace = PermissionNamespace('folders', _(u'Folders')) -PERMISSION_FOLDER_LIST = Permission.objects.register(folder_namespace, 'folder_list', _(u'View all folders')) PERMISSION_FOLDER_CREATE = Permission.objects.register(folder_namespace, 'folder_create', _(u'Create new folders')) PERMISSION_FOLDER_EDIT = Permission.objects.register(folder_namespace, 'folder_edit', _(u'Edit new folders')) PERMISSION_FOLDER_DELETE = Permission.objects.register(folder_namespace, 'folder_delete', _(u'Delete new folders')) diff --git a/apps/folders/views.py b/apps/folders/views.py index 7821391b2f..2d0b1ee6aa 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect from django.shortcuts import render_to_response, get_object_or_404 @@ -10,14 +12,14 @@ from django.core.exceptions import PermissionDenied from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list -from permissions.models import Permission +from permissions import Permission from common.utils import encapsulate from acls.models import AccessEntry, PermissionDenied from acls.views import acl_list_for, acl_new_holder_for -from folders.models import Folder, FolderDocument -from folders.forms import FolderForm, AddDocumentForm -from folders.permissions import (PERMISSION_FOLDER_LIST, PERMISSION_FOLDER_CREATE, +from .models import Folder, FolderDocument +from .forms import FolderForm, AddDocumentForm +from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) @@ -40,9 +42,7 @@ def folder_list(request, queryset=None, extra_context=None): try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_VIEW]) except PermissionDenied: - pass - #class_objects = AccessEntry.objects.get_allowed_class_objects(PERMISSION_FOLDER_VIEW, request.user, Folder) - #queryset = list(set(queryset) & set(class_objects)) + queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_VIEW, request.user, queryset) context['object_list'] = queryset @@ -144,64 +144,25 @@ def folder_delete(request, folder_id): def folder_view(request, folder_id): folder = get_object_or_404(Folder, pk=folder_id) - document_list = folder.documents - try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_VIEW]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_FOLDER_VIEW, request.user, folder) context = { - 'object_list': document_list, 'hide_links': True, - 'title': _(u'documents in folder: %s') % folder, 'multi_select_as_buttons': True, 'object': folder, 'object_name': _(u'folder'), - } - #document_list - - return render_to_response( - 'generic_list.html', - context, - context_instance=RequestContext(request) + return document_list( + request, + object_list=folder.documents, + title=_(u'documents in folder: %s') % folder, + extra_context=context ) -''' -def folder_add_document_sidebar(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - document = get_object_or_404(Document, pk=document_id) - - previous = request.META.get('HTTP_REFERER', '/') - - if request.method == 'POST': - form = AddDocumentForm(request.POST, user=request.user) - if form.is_valid(): - if form.cleaned_data['existing_folder']: - folder = form.cleaned_data['existing_folder'] - elif form.cleaned_data['title']: - folder, created = Folder.objects.get_or_create(user=request.user, title=form.cleaned_data['title']) - if created: - messages.success(request, _(u'Folder created successfully')) - else: - messages.error(request, _(u'A folder named: %s, already exists.') % form.cleaned_data['title']) - return HttpResponseRedirect(previous) - else: - messages.error(request, _(u'Must specify a new folder or an existing one.')) - return HttpResponseRedirect(previous) - - folder_document, created = FolderDocument.objects.get_or_create(folder=folder, document=document) - if created: - messages.success(request, _(u'Document: %(document)s added to folder: %(folder)s successfully.') % { - 'document': document, 'folder': folder}) - else: - messages.warning(request, _(u'Document: %(document)s is already in folder: %(folder)s.') % { - 'document': document, 'folder': folder}) - - return HttpResponseRedirect(previous) -''' def folder_add_document(request, document_id): document = get_object_or_404(Document, pk=document_id) @@ -255,15 +216,9 @@ def document_folder_list(request, document_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - Permission.objects.check_permissions(request.user, [PERMISSION_FODLER_VIEW]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) - try: - Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_REMOVE_DOCUMENT]) - except PermissionDenied: - folder_documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, folder_documents) - return folder_list( request, queryset=Folder.objects.filter(folderdocument__document=document), From 54cb1d29e3279ae61ca944fdeb99014b2d29fed4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 24 Dec 2011 01:08:57 -0400 Subject: [PATCH 100/484] Remove the requirement for global permission for the document view and document recent view User may not have the global permission, but still have permission to view certain documents via ACL --- apps/documents/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 653ad2bbcf..e52bb24bb3 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -55,8 +55,8 @@ register_history_type(HISTORY_DOCUMENT_CREATED) register_history_type(HISTORY_DOCUMENT_EDITED) register_history_type(HISTORY_DOCUMENT_DELETED) -document_list = {'text': _(u'all documents'), 'view': 'document_list', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_list_recent = {'text': _(u'recent documents'), 'view': 'document_list_recent', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_list = {'text': _(u'all documents'), 'view': 'document_list', 'famfam': 'page'} +document_list_recent = {'text': _(u'recent documents'), 'view': 'document_list_recent', 'famfam': 'page'} document_create_multiple = {'text': _(u'upload new documents'), 'view': 'document_create_multiple', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_CREATE], 'children_view_regex': [r'upload_interactive']} document_create_siblings = {'text': _(u'clone metadata'), 'view': 'document_create_siblings', 'args': 'object.id', 'famfam': 'page_copy', 'permissions': [PERMISSION_DOCUMENT_CREATE]} document_view_simple = {'text': _(u'details'), 'view': 'document_view_simple', 'args': 'object.id', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} From c187e77acc7e4b0b7bb2945e327c44c60d4e45c1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 24 Dec 2011 01:10:10 -0400 Subject: [PATCH 101/484] Fix document_clear_transformations and document_delete multi document ACL calculation --- apps/documents/views.py | 62 ++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index c203e01eba..d297c5cc79 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -196,23 +196,15 @@ def document_delete(request, document_id=None, document_id_list=None): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DELETE]) except PermissionDenied: if document_id: - document = get_object_or_404(Document, pk=document_id) - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_DELETE, request.user, document) - documents = [document] + documents = [get_object_or_404(Document, pk=document_id)] post_action_redirect = reverse('document_list') elif document_id_list: - documents = [] - for document_id in document_id_list.split(','): - document = get_object_or_404(Document, pk=document_id) - # If use doesn't have access for one document, stop and - # fail the entire operation - # TODO: improve it to remove documents not allowed - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_DELETE, request.user, document) - documents.append(document) + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] else: messages.error(request, _(u'Must provide at least one document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) - + + documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DELETE, request.user, documents) else: if document_id: documents = [get_object_or_404(Document, pk=document_id)] @@ -549,12 +541,11 @@ def document_find_all_duplicates(request): def document_update_page_count(request): - # TODO: access_queryset - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) - - previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) + office_converter = OfficeConverter() qs = DocumentVersion.objects.exclude(filename__iendswith='dxf').filter(mimetype__in=office_converter.mimetypes()) + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) if request.method == 'POST': updated = 0 @@ -581,18 +572,30 @@ def document_update_page_count(request): def document_clear_transformations(request, document_id=None, document_id_list=None): - #TODO: access_list - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) - - if document_id: - documents = [get_object_or_404(Document.objects, pk=document_id)] - post_redirect = reverse('document_view_simple', args=[documents[0].pk]) - elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] - post_redirect = None + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) + except PermissionDenied: + if document_id: + documents = [get_object_or_404(Document.objects, pk=document_id)] + post_redirect = reverse('document_view_simple', args=[documents[0].pk]) + elif document_id_list: + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + post_redirect = None + else: + messages.error(request, _(u'Must provide at least one document.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) + + documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, documents) else: - messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) + if document_id: + documents = [get_object_or_404(Document.objects, pk=document_id)] + post_redirect = reverse('document_view_simple', args=[documents[0].pk]) + elif document_id_list: + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + post_redirect = None + else: + messages.error(request, _(u'Must provide at least one document.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', post_redirect or reverse('document_list')))) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_redirect or reverse('document_list')))) @@ -1000,9 +1003,7 @@ def document_type_list(request): def document_type_document_list(request, document_type_id): - # TODO: access list - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TYPE_VIEW]) document_type = get_object_or_404(DocumentType, pk=document_type_id) return document_list( @@ -1039,7 +1040,6 @@ def document_type_edit(request, document_type_id): 'title': _(u'edit document type: %s') % document_type, 'form': form, #'object': document_type, - #'object_name': _(u'document type'), 'object_name': _(u'document type'), 'navigation_object_name': 'document_type', 'document_type': document_type, From e7c7ec0636432882b0a362cbcd1d92d8499a1892 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 24 Dec 2011 01:16:32 -0400 Subject: [PATCH 102/484] Remove remarked code --- apps/documents/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index d297c5cc79..fb375b5ac9 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -535,8 +535,6 @@ def _find_duplicate_list(request, source_document_list=Document.objects.all(), i def document_find_all_duplicates(request): - #Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) - return _find_duplicate_list(request, include_source=True) From 3b884e8c8abcd1e051ef4f153a356581b7a696f1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 24 Dec 2011 01:16:53 -0400 Subject: [PATCH 103/484] Update get_allowed_class_objects to return a generator instead of a list, filter_objects_by_access to try return to return a queryset and failing that return a filtered list --- apps/acls/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index bfdc0cf95e..05b99753a9 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -211,7 +211,7 @@ class AccessEntryManager(models.Manager): holder_type = ContentType.objects.get_for_model(requester) content_type = ContentType.objects.get_for_model(cls) - return [obj.content_object for obj in self.model.objects.filter(holder_type=holder_type, holder_id=requester.pk, content_type=content_type, permission=permission.get_stored_permission)] + return (obj.content_object for obj in self.model.objects.filter(holder_type=holder_type, holder_id=requester.pk, content_type=content_type, permission=permission.get_stored_permission)) def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) @@ -242,10 +242,11 @@ class AccessEntryManager(models.Manager): return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] def filter_objects_by_access(self, permission, actor, object_list): - class_objects = self.get_allowed_class_objects(permission, actor, object_list[0]) - logger.debug('class_objects: %s' % class_objects) logger.debug('object_list: %s' % object_list) - return list(set(object_list) & set(class_objects)) + try: + return object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) + except AttributeError: + return list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0]))) class AccessEntry(models.Model): From 80fab8b70d5a2db16a908a7c390d3c55aa76a1b5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:13:17 -0400 Subject: [PATCH 104/484] Add and enable the new PERMISSION_DOCUMENT_NEW_VERSION permission --- apps/sources/__init__.py | 20 ++++++++++++++------ apps/sources/views.py | 16 +++++++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 5d69ae8c1f..6fb37090f1 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -7,17 +7,21 @@ 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 acls.models import class_permissions from sources.staging import StagingFile from sources.models import WebForm, StagingFolder, SourceTransformation, \ WatchFolder from sources.widgets import staging_file_thumbnail -sources_namespace = PermissionNamespace('sources_setup', _(u'Sources setup')) -PERMISSION_SOURCES_SETUP_VIEW = Permission.objects.register(sources_namespace, 'sources_setup_view', _(u'View existing document sources')) -PERMISSION_SOURCES_SETUP_EDIT = Permission.objects.register(sources_namespace, 'sources_setup_edit', _(u'Edit document sources')) -PERMISSION_SOURCES_SETUP_DELETE = Permission.objects.register(sources_namespace, 'sources_setup_delete', _(u'Delete document sources')) -PERMISSION_SOURCES_SETUP_CREATE = Permission.objects.register(sources_namespace, 'sources_setup_create', _(u'Create new document sources')) +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')) + +sources_namespace = PermissionNamespace('sources', _(u'Sources')) +PERMISSION_DOCUMENT_NEW_VERSION = Permission.objects.register(sources_namespace, 'sources_document_new_version', _(u'Create new document version')) 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} @@ -38,7 +42,7 @@ setup_source_transformation_delete = {'text': _(u'delete'), 'view': 'setup_sourc source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add', 'children_url_regex': [r'sources/setup']} -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]) @@ -75,3 +79,7 @@ register_model_list_columns(StagingFile, [ register_setup(setup_sources) + +class_permissions(Document, [ + PERMISSION_DOCUMENT_NEW_VERSION +]) diff --git a/apps/sources/views.py b/apps/sources/views.py index 55c2f6829c..1dcce811c4 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -14,6 +14,7 @@ from metadata.api import decode_metadata_from_url, metadata_repr_as_list from permissions.models import Permission from common.utils import encapsulate import sendfile +from acls.models import AccessEntry, PermissionDenied from sources.models import WebForm, StagingFolder, SourceTransformation, \ WatchFolder @@ -26,9 +27,9 @@ 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 sources import (PERMISSION_SOURCES_SETUP_VIEW, + PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE, + PERMISSION_SOURCES_SETUP_CREATE, PERMISSION_DOCUMENT_NEW_VERSION) def return_function(obj): @@ -71,14 +72,18 @@ def get_active_tab_links(document=None): } def upload_interactive(request, source_type=None, source_id=None, document_pk=None): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) - 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() @@ -386,6 +391,7 @@ 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): Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_VIEW]) From de49d4a588988abed7a46ad9047c661aba2425df Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:14:19 -0400 Subject: [PATCH 105/484] Pass a copy of the entire context to the navigation subtemplate when calling it from sublist template --- .../templates/generic_subnavigation.html | 2 +- apps/navigation/templatetags/navigation_tags.py | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/navigation/templates/generic_subnavigation.html b/apps/navigation/templates/generic_subnavigation.html index 46fecb22ab..eac581d5e0 100644 --- a/apps/navigation/templates/generic_subnavigation.html +++ b/apps/navigation/templates/generic_subnavigation.html @@ -4,7 +4,7 @@ {% with link.permissions as permissions %} {% check_permissions request.user permissions %} - {% check_access permissions request.user navigation_object %} + {% check_access permissions request.user object %} {% if permission or access %} {% if as_li %} diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 86b625ab0c..81dd819c13 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -249,15 +249,14 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): - # Pass the list object to the navigation template as the navigation object - return { - 'navigation_object': context['object'] if 'object' in context else None, - '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) From a9c5caa9943ac77b4a3261e7ba1df6a6705ccf3c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:15:41 -0400 Subject: [PATCH 106/484] Add the __str__ method and stored_permission proxy property to the Permission class --- apps/permissions/models.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index d823a2288b..6e1a7cafe5 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -67,7 +67,7 @@ class PermissionManager(object): def __init__(self, model): self.model = model - + class Permission(object): DoesNotExist = PermissionDoesNotExists @@ -81,9 +81,16 @@ class Permission(object): 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( @@ -101,8 +108,7 @@ class Permission(object): return stored_permission.requester_has_this(requester) def save(self, *args, **kwargs): - return self.get_stored_permission( - ) + return self.get_stored_permission() Permission.objects = PermissionManager(Permission) Permission._default_manager = Permission.objects From b39a5bc90366489422e23bd324d2ca3169cb8940 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:16:54 -0400 Subject: [PATCH 107/484] Fix folder app ACL navigation --- apps/folders/__init__.py | 4 ++-- apps/folders/views.py | 39 ++++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 881ce8a3ce..0f8cb64a3c 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -29,9 +29,9 @@ register_multi_item_links(['folder_view'], [folder_document_multiple_remove]) register_links(Folder, [folder_view, folder_edit, folder_delete, folder_acl_list]) -register_links(['folder_acl_list'], [folder_new_holder], menu_name='sidebar') +register_links(['folder_acl_list', 'folder_new_holder'], [folder_new_holder], menu_name='sidebar') -register_links(['folder_edit', 'folder_delete', 'folder_list', 'folder_create', 'folder_view', 'folder_document_multiple_remove', 'folder_acl_list', 'folder_new_holder'], [folder_list, folder_create], menu_name='secondary_menu') +register_links([Folder, 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='secondary_menu') register_top_menu(name='folders', link={'text': _('folders'), 'famfam': 'folder_user', 'view': 'folder_list'}, children_views=['folder_list', 'folder_create', 'folder_edit', 'folder_delete', 'folder_view', 'folder_document_multiple_remove']) diff --git a/apps/folders/views.py b/apps/folders/views.py index 2d0b1ee6aa..6b3cdde802 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -1,4 +1,5 @@ from __future__ import absolute_import +import logging from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect @@ -24,6 +25,8 @@ from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) +logger = logging.getLogger(__name__) + def folder_list(request, queryset=None, extra_context=None): context = { @@ -245,7 +248,7 @@ def folder_document_remove(request, folder_id, document_id=None, document_id_lis try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_REMOVE_DOCUMENT]) except PermissionDenied: - folder_documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, folder_documents) + folder_documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, folder_documents, exception_on_empty=True) 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', '/'))) @@ -285,25 +288,27 @@ def folder_document_multiple_remove(request, folder_id): def folder_acl_list(request, folder_pk): - folder = get_object_or_404(Folder, pk=folder_pk) - return acl_list_for( - request, - folder, - extra_context={ - 'object': folder, - } - ) + folder = get_object_or_404(Folder, pk=folder_pk) + logger.debug('folder: %s' % folder) + + return acl_list_for( + request, + folder, + extra_context={ + 'object': folder, + } + ) def folder_new_holder(request, folder_pk): - folder = get_object_or_404(Folder, pk=folder_pk) - return acl_new_holder_for( - request, - folder, - extra_context={ - 'folder': folder, + folder = get_object_or_404(Folder, pk=folder_pk) + return acl_new_holder_for( + request, + folder, + extra_context={ + 'folder': folder, 'submit_label': _(u'Select'), 'submit_icon_famfam': 'tick', 'object': folder, - } - ) + } + ) From 8ab692ddc866698a35e3882f9a4eef3a00506676 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:18:09 -0400 Subject: [PATCH 108/484] Use self.content_type.model instead of name, rename holder to actor, add get_class_permission to the AccessEntry manager, Encapsulation class decapsulation for AccessEntry manager methods, add exception_on_empty to raise PermissionDenied when the result of a filtered list is empty --- apps/acls/models.py | 135 +++++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 47 deletions(-) diff --git a/apps/acls/models.py b/apps/acls/models.py index 05b99753a9..554403e0bf 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -103,10 +103,10 @@ class EncapsulatedObject(object): if isinstance(source_object, ModelBase): # Class - self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.name) + self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.model) else: # Object - self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.name, source_object.pk) + self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.model, source_object.pk) setattr(self, self.__class__.source_object_name, source_object) @@ -150,25 +150,37 @@ class ClassAccessHolder(EncapsulatedObject): class AccessEntryManager(models.Manager): - def grant(self, permission, requester, obj): + def source_object(self, obj): + if isinstance(obj, EncapsulatedObject): + return obj.source_object + else: + return obj + + def grant(self, permission, actor, obj): ''' Grant a permission (what), (to) a requester, (on) a specific object ''' + obj = self.source_object(obj) + actor = self.source_object(actor) + access_entry, created = self.model.objects.get_or_create( permission=permission, - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk ) return created - def revoke(self, permission, holder, obj): + def revoke(self, permission, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) + try: access_entry = self.model.objects.get( permission=permission, - holder_type=ContentType.objects.get_for_model(holder), - holder_id=holder.pk, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk ) @@ -177,16 +189,19 @@ class AccessEntryManager(models.Manager): except self.model.DoesNotExist: return False - def has_accesses(self, permission, requester, obj): - if isinstance(requester, User): - if requester.is_superuser or requester.is_staff: + def has_access(self, permission, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) + + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: return True - + try: access_entry = self.model.objects.get( permission=permission.get_stored_permission(), - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk ) @@ -194,24 +209,29 @@ class AccessEntryManager(models.Manager): except self.model.DoesNotExist: return False - def check_access(self, permission, requester, obj): - if self.has_accesses(permission, requester, obj): + def check_access(self, permission, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) + + if self.has_access(permission, actor, obj): return True else: raise PermissionDenied(ugettext(u'Insufficient access.')) - def check_accesses(self, permission_list, requester, obj): + def check_accesses(self, permission_list, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) for permission in permission_list: - if self.has_accesses(permission, requester, obj): + if self.has_access(permission, actor, obj): return True raise PermissionDenied(ugettext(u'Insufficient access.')) - def get_allowed_class_objects(self, permission, requester, cls): - holder_type = ContentType.objects.get_for_model(requester) + def get_allowed_class_objects(self, permission, actor, cls): + actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) - return (obj.content_object for obj in self.model.objects.filter(holder_type=holder_type, holder_id=requester.pk, content_type=content_type, permission=permission.get_stored_permission)) + return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) @@ -232,21 +252,42 @@ class AccessEntryManager(models.Manager): return holder_list - def get_holder_permissions_for(self, obj, holder): - if isinstance(holder, User): - if holder.is_superuser or holder.is_staff: + def get_holder_permissions_for(self, obj, actor): + logger.debug('obj: %s' % obj) + logger.debug('actor: %s' % actor) + + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: return Permission.objects.all() - - holder_type = ContentType.objects.get_for_model(holder) - content_type = ContentType.objects.get_for_model(obj) - return [access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=holder_type, holder_id=holder.pk)] - def filter_objects_by_access(self, permission, actor, object_list): + actor_type = ContentType.objects.get_for_model(actor) + content_type = ContentType.objects.get_for_model(obj) + return (access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=actor_type, holder_id=actor.pk)) + + def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False): + logger.debug('exception_on_empty: %s' % exception_on_empty) logger.debug('object_list: %s' % object_list) try: - return object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) + # Try to process as a QuerySet + qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) + logger.debug('qs: %s' % qs) + + if qs.count() == 0 and exception_on_empty == True: + raise PermissionDenied + + return qs except AttributeError: - return list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0]))) + # Fallback to a list filtered list + obj_list = list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0]))) + logger.debug('obj_list: %s' % obj_list) + if len(obj_list) == 0 and exception_on_empty == True: + raise PermissionDenied + + return obj_list + + def get_class_permissions_for(self, obj): + content_type = ContentType.objects.get_for_model(obj) + return _class_permissions.get(content_type.model_class(), []) class AccessEntry(models.Model): @@ -298,40 +339,40 @@ class DefaultAccessEntryManager(models.Manager): return holder_list - def has_accesses(self, permission, requester, cls): - if isinstance(requester, User): - if requester.is_superuser or requester.is_staff: + def has_access(self, permission, actor, cls): + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: return True try: access_entry = self.model.objects.get( permission=permission.get_stored_permission(), - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, content_type=ContentType.objects.get_for_model(cls), ) return True except self.model.DoesNotExist: return False - def grant(self, permission, requester, cls): + def grant(self, permission, actor, cls): ''' Grant a permission (what), (to) a requester, (on) a specific class ''' access_entry, created = self.model.objects.get_or_create( permission=permission, - holder_type=ContentType.objects.get_for_model(requester), - holder_id=requester.pk, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, content_type=ContentType.objects.get_for_model(cls), ) return created - def revoke(self, permission, holder, cls): + def revoke(self, permission, actor, cls): try: access_entry = self.model.objects.get( permission=permission, - holder_type=ContentType.objects.get_for_model(holder), - holder_id=holder.pk, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, content_type=ContentType.objects.get_for_model(cls), ) access_entry.delete() @@ -339,14 +380,14 @@ class DefaultAccessEntryManager(models.Manager): except self.model.DoesNotExist: return False - def get_holder_permissions_for(self, cls, holder): - if isinstance(holder, User): - if holder.is_superuser or holder.is_staff: + def get_holder_permissions_for(self, cls, actor): + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: return Permission.objects.all() - holder_type = ContentType.objects.get_for_model(holder) + actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) - return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=holder_type, holder_id=holder.pk)] + return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=actor_type, holder_id=actor.pk)] class DefaultAccessEntry(models.Model): From 53bf3d940dda0efd6b600b8e97ab47438689c20c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:20:16 -0400 Subject: [PATCH 109/484] Added logging to the acls tag --- apps/acls/templatetags/acl_tags.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/acls/templatetags/acl_tags.py b/apps/acls/templatetags/acl_tags.py index f180cfe8f9..f76b29e424 100644 --- a/apps/acls/templatetags/acl_tags.py +++ b/apps/acls/templatetags/acl_tags.py @@ -1,10 +1,14 @@ +import logging + from django.core.exceptions import PermissionDenied from django.template import (TemplateSyntaxError, Library, Node, Variable, VariableDoesNotExist) + from acls.models import AccessEntry register = Library() +logger = logging.getLogger(__name__) class CheckAccessNode(Node): @@ -15,14 +19,19 @@ class CheckAccessNode(Node): def render(self, context): permission_list = Variable(self.permission_list).resolve(context) + logger.debug('permission_list: %s' % u','.join([unicode(p) for p in permission_list])) + try: # Check access_object, useful for document_page views obj = Variable('access_object').resolve(context) + logger.debug('access_object: %s' % obj) except VariableDoesNotExist: try: obj = Variable(self.obj).resolve(context) + logger.debug('obj: %s' % obj) except VariableDoesNotExist: context[u'access'] = True + logger.debug('no obj, access True') return u'' if not permission_list: @@ -32,18 +41,22 @@ class CheckAccessNode(Node): return u'' requester = Variable(self.requester).resolve(context) + logger.debug('requester: %s' % requester) if obj: try: AccessEntry.objects.check_accesses(permission_list, requester, obj) except PermissionDenied: context[u'access'] = False + logger.debug('access: False') return u'' else: context[u'access'] = True + logger.debug('access: True') return u'' else: context[u'access'] = False + logger.debug('No object, access: False') return u'' From 5c7431394863e70ff1436931061bd5beb8bef729 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:21:01 -0400 Subject: [PATCH 110/484] Removed remarked code --- apps/documents/__init__.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index e52bb24bb3..9f8fc1a59a 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -159,15 +159,6 @@ register_diagnostic('documents', _(u'Documents'), document_missing_list) register_maintenance_links([document_find_all_duplicates, document_update_page_count, document_clear_image_cache], namespace='documents', title=_(u'documents')) -#def document_exists(document): -# try: -# if document.exists(): -# return u'' -# else: -# return u'' -# except Exception, exc: -# return exc - register_model_list_columns(Document, [ {'name':_(u'thumbnail'), 'attribute': encapsulate(lambda x: document_thumbnail(x)) From eb9fb7141dda2ce6ecd4ddf2d78c8893d44ddc53 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:21:22 -0400 Subject: [PATCH 111/484] Simplify multi document views access checking logic --- apps/documents/views.py | 62 +++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index fb375b5ac9..1c2acaef97 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -192,28 +192,19 @@ def document_view(request, document_id, advanced=False): def document_delete(request, document_id=None, document_id_list=None): + if document_id: + documents = [get_object_or_404(Document, pk=document_id)] + post_action_redirect = reverse('document_list') + elif document_id_list: + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one document.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DELETE]) except PermissionDenied: - if document_id: - documents = [get_object_or_404(Document, pk=document_id)] - post_action_redirect = reverse('document_list') - elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] - else: - messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) - - documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DELETE, request.user, documents) - else: - if document_id: - documents = [get_object_or_404(Document, pk=document_id)] - post_action_redirect = reverse('document_list') - elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] - else: - messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DELETE, request.user, documents, exception_on_empty=True) post_action_redirect = None @@ -570,30 +561,20 @@ def document_update_page_count(request): def document_clear_transformations(request, document_id=None, document_id_list=None): + if document_id: + documents = [get_object_or_404(Document.objects, pk=document_id)] + post_redirect = reverse('document_view_simple', args=[documents[0].pk]) + elif document_id_list: + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + post_redirect = None + else: + messages.error(request, _(u'Must provide at least one document.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) except PermissionDenied: - if document_id: - documents = [get_object_or_404(Document.objects, pk=document_id)] - post_redirect = reverse('document_view_simple', args=[documents[0].pk]) - elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] - post_redirect = None - else: - messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) - - documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, documents) - else: - if document_id: - documents = [get_object_or_404(Document.objects, pk=document_id)] - post_redirect = reverse('document_view_simple', args=[documents[0].pk]) - elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] - post_redirect = None - else: - messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) + documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, documents, exception_on_empty=True) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', post_redirect or reverse('document_list')))) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_redirect or reverse('document_list')))) @@ -1275,6 +1256,7 @@ def document_version_list(request, document_pk): 'title': _(u'versions for document: %s') % document, 'hide_object': True, 'object': document, + 'access_object': document, 'extra_columns': [ { 'name': _(u'version'), From 7e9fbf4f4778caf8a95f52e31bd5ff941dc71fa0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:22:05 -0400 Subject: [PATCH 112/484] Add ACL support to the linking app, convert import to absolute --- apps/linking/__init__.py | 24 +++++++- apps/linking/admin.py | 4 +- apps/linking/forms.py | 4 +- apps/linking/managers.py | 4 +- apps/linking/models.py | 6 +- apps/linking/tests.py | 23 -------- apps/linking/urls.py | 3 + apps/linking/views.py | 124 +++++++++++++++++++++++++++++++-------- 8 files changed, 135 insertions(+), 57 deletions(-) delete mode 100644 apps/linking/tests.py diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index f64337045e..63895ab171 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_sidebar_template @@ -5,8 +7,10 @@ from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup from documents.literals import PERMISSION_DOCUMENT_VIEW from documents.models import Document +from acls.models import class_permissions +from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL -from linking.models import SmartLink, SmartLinkCondition +from .models import SmartLink, SmartLinkCondition linking_namespace = PermissionNamespace('linking', _(u'Smart links')) @@ -29,12 +33,26 @@ smart_link_condition_create = {'text': _(u'create condition'), 'view': 'smart_li smart_link_condition_edit = {'text': _(u'edit'), 'view': 'smart_link_condition_edit', 'args': 'condition.pk', 'famfam': 'cog_edit', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} smart_link_condition_delete = {'text': _(u'delete'), 'view': 'smart_link_condition_delete', 'args': 'condition.pk', 'famfam': 'cog_delete', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} +smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'smart_link_acl_list', 'args': 'smart_link.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +smart_link_new_holder = {'text': _(u'New holder'), 'view': 'smart_link_new_holder', 'args': 'smart_link.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} + +register_links(['smart_link_acl_list', 'smart_link_new_holder'], [smart_link_new_holder], menu_name='sidebar') + register_links(Document, [smart_link_instances_for_document], menu_name='form_header') -register_links(SmartLink, [smart_link_edit, smart_link_delete, smart_link_condition_list]) +register_links(SmartLink, [smart_link_edit, smart_link_delete, smart_link_condition_list, smart_link_acl_list]) +register_links([SmartLink, 'smart_link_list', 'smart_link_create'], [smart_link_list, smart_link_create], menu_name='sidebar') + register_links(SmartLinkCondition, [smart_link_condition_edit, smart_link_condition_delete]) -register_links(['smart_link_list', 'smart_link_create', 'smart_link_edit', 'smart_link_delete', 'smart_link_condition_list', 'smart_link_condition_create', 'smart_link_condition_edit', 'smart_link_condition_delete'], [smart_link_list, smart_link_create], menu_name='sidebar') register_links(['smart_link_condition_list', 'smart_link_condition_create', 'smart_link_condition_edit', 'smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar') register_setup(smart_link_setup) register_sidebar_template(['smart_link_list'], 'smart_links_help.html') + +class_permissions(SmartLink, [ + PERMISSION_SMART_LINK_VIEW, + PERMISSION_SMART_LINK_DELETE, + PERMISSION_SMART_LINK_EDIT, + ACLS_EDIT_ACL, + ACLS_VIEW_ACL +]) diff --git a/apps/linking/admin.py b/apps/linking/admin.py index 045244bc5a..84f13692f5 100644 --- a/apps/linking/admin.py +++ b/apps/linking/admin.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from django.contrib import admin -from linking.models import SmartLink, SmartLinkCondition +from .models import SmartLink, SmartLinkCondition class SmartLinkConditionInline(admin.StackedInline): diff --git a/apps/linking/forms.py b/apps/linking/forms.py index 1e90e16c8a..5cdb6be1f9 100644 --- a/apps/linking/forms.py +++ b/apps/linking/forms.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django import forms from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext @@ -9,7 +11,7 @@ from django.conf import settings from documents.widgets import document_html_widget from tags.widgets import get_tags_inline_widget -from linking.models import SmartLink, SmartLinkCondition +from .models import SmartLink, SmartLinkCondition class SmartLinkForm(forms.ModelForm): diff --git a/apps/linking/managers.py b/apps/linking/managers.py index 050ddffea2..bb6dcba1c5 100644 --- a/apps/linking/managers.py +++ b/apps/linking/managers.py @@ -1,10 +1,12 @@ +from __future__ import absolute_import + from django.db import models from django.db.models import Q from metadata.classes import MetadataObject from documents.models import Document -from linking.literals import INCLUSION_AND, INCLUSION_OR +from .literals import INCLUSION_AND, INCLUSION_OR class SmartLinkManager(models.Manager): diff --git a/apps/linking/models.py b/apps/linking/models.py index ccc04f5537..18b145b936 100644 --- a/apps/linking/models.py +++ b/apps/linking/models.py @@ -1,8 +1,10 @@ +from __future__ import absolute_import + from django.db import models from django.utils.translation import ugettext_lazy as _ -from linking.managers import SmartLinkManager -from linking.literals import OPERATOR_CHOICES, INCLUSION_AND, \ +from .managers import SmartLinkManager +from .literals import OPERATOR_CHOICES, INCLUSION_AND, \ INCLUSION_CHOICES diff --git a/apps/linking/tests.py b/apps/linking/tests.py deleted file mode 100644 index 2247054b35..0000000000 --- a/apps/linking/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/linking/urls.py b/apps/linking/urls.py index 080a180b2b..e13bc00441 100644 --- a/apps/linking/urls.py +++ b/apps/linking/urls.py @@ -14,4 +14,7 @@ urlpatterns = patterns('linking.views', url(r'^setup/(?P\d+)/condition/create/$', 'smart_link_condition_create', (), 'smart_link_condition_create'), url(r'^setup/smart_link/condition/(?P\d+)/edit/$', 'smart_link_condition_edit', (), 'smart_link_condition_edit'), url(r'^setup/smart_link/condition/(?P\d+)/delete/$', 'smart_link_condition_delete', (), 'smart_link_condition_delete'), + + url(r'^(?P\d+)/acl/list/$', 'smart_link_acl_list', (), 'smart_link_acl_list'), + url(r'^(?P\d+)/acl/holder/new/$', 'smart_link_new_holder', (), 'smart_link_new_holder'), ) diff --git a/apps/linking/views.py b/apps/linking/views.py index 559f4dcea7..2e5d72a626 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -1,3 +1,6 @@ +from __future__ import absolute_import +import logging + from django.utils.translation import ugettext_lazy as _ from django.contrib import messages from django.http import HttpResponseRedirect @@ -7,24 +10,27 @@ from django.template import RequestContext from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template - from documents.models import Document from documents.views import document_list - +from documents.literals import PERMISSION_DOCUMENT_VIEW from permissions.models import Permission +from acls.views import acl_new_holder_for, acl_list_for, acl_detail_for +from acls.models import AccessEntry, PermissionDenied -from linking.models import SmartLink, SmartLinkCondition -from linking.conf.settings import SHOW_EMPTY_SMART_LINKS -from linking.forms import (SmartLinkInstanceForm, SmartLinkForm, +from .models import SmartLink, SmartLinkCondition +from .conf.settings import SHOW_EMPTY_SMART_LINKS +from .forms import (SmartLinkInstanceForm, SmartLinkForm, SmartLinkConditionForm) -from linking import smart_link_instance_view_link -from linking import (PERMISSION_SMART_LINK_VIEW, +from . import smart_link_instance_view_link +from . import (PERMISSION_SMART_LINK_VIEW, PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_DELETE, PERMISSION_SMART_LINK_EDIT) +logger = logging.getLogger(__name__) + def smart_link_action(request): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + #Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) action = request.GET.get('action', None) @@ -36,10 +42,14 @@ def smart_link_action(request): def smart_link_instance_view(request, document_id, smart_link_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) - document = get_object_or_404(Document, pk=document_id) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_SMART_LINK_VIEW, request.user, smart_link) + object_list, errors = SmartLink.objects.get_smart_link_instances_for(document, smart_link) return document_list( @@ -55,8 +65,6 @@ def smart_link_instance_view(request, document_id, smart_link_pk): def smart_link_instances_for_document(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) - subtemplates_list = [] document = get_object_or_404(Document, pk=document_id) smart_link_instances, errors = SmartLink.objects.get_smart_link_instances_for(document) @@ -69,6 +77,17 @@ def smart_link_instances_for_document(request, document_id): #dictionary smart_link_instances = dict([(group, data) for group, data in smart_link_instances.items() if data['documents']]) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + except PermissionDenied: + smart_link_instances_keys_filtered = AccessEntry.objects.filter_objects_by_access(PERMISSION_SMART_LINK_VIEW, request.user, smart_link_instances.keys()) + # Remove smart link instances not found in the new filtered key list + for key, value in smart_link_instances.items(): + if key not in smart_link_instances_keys_filtered: + smart_link_instances.pop(key) + + value['documents'] = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_VIEW, request.user, value['documents']) + if smart_link_instances: subtemplates_list = [{ 'name': 'generic_form_subtemplate.html', @@ -99,11 +118,17 @@ def smart_link_instances_for_document(request, document_id): def smart_link_list(request): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE]) + qs = SmartLink.objects.all() + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) + except PermissionDenied: + qs = AccessEntry.objects.filter_objects_by_access(PERMISSION_SMART_LINK_VIEW, request.user, qs) + return render_to_response('generic_list.html', { 'title': _(u'smart links'), - 'object_list': SmartLink.objects.all(), + 'object_list': qs, 'extra_columns': [ {'name': _(u'dynamic title'), 'attribute': 'dynamic_title'}, {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, @@ -133,10 +158,13 @@ def smart_link_create(request): def smart_link_edit(request, smart_link_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT]) - smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_SMART_LINK_EDIT, request.user, smart_link) + if request.method == 'POST': form = SmartLinkForm(request.POST, instance=smart_link) if form.is_valid(): @@ -155,10 +183,13 @@ def smart_link_edit(request, smart_link_pk): def smart_link_delete(request, smart_link_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_DELETE]) - smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_DELETE]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_SMART_LINK_DELETE, request.user, smart_link) + 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', '/'))) @@ -185,10 +216,13 @@ def smart_link_delete(request, smart_link_pk): def smart_link_condition_list(request, smart_link_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) - smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link) + return render_to_response('generic_list.html', { 'title': _(u'conditions for smart link: %s') % smart_link, 'object_list': smart_link.smartlinkcondition_set.all(), @@ -203,10 +237,13 @@ def smart_link_condition_list(request, smart_link_pk): def smart_link_condition_create(request, smart_link_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) - smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link) + if request.method == 'POST': form = SmartLinkConditionForm(request.POST) if form.is_valid(): @@ -227,10 +264,13 @@ def smart_link_condition_create(request, smart_link_pk): def smart_link_condition_edit(request, smart_link_condition_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) - smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link) + 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', '/'))) @@ -261,10 +301,13 @@ def smart_link_condition_edit(request, smart_link_condition_pk): def smart_link_condition_delete(request, smart_link_condition_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) - smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link) + 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', '/'))) @@ -292,3 +335,32 @@ def smart_link_condition_delete(request, smart_link_condition_pk): 'previous': previous, 'form_icon': u'cog_delete.png', }, context_instance=RequestContext(request)) + + +def smart_link_acl_list(request, smart_link_pk): + smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + logger.debug('smart_link: %s' % smart_link) + + return acl_list_for( + request, + smart_link, + extra_context={ + 'object': smart_link, + 'smart_link': smart_link, + } + ) + + +def smart_link_new_holder(request, smart_link_pk): + smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) + return acl_new_holder_for( + request, + smart_link, + extra_context={ + 'smart_link': smart_link, + 'submit_label': _(u'Select'), + 'submit_icon_famfam': 'tick', + 'object': smart_link, + }, + navigation_object=u'smart_link', + ) From 0f12364e0c302aaef12be1ffec8c721e537540e9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 03:23:44 -0400 Subject: [PATCH 113/484] Add ACLS_EDIT_ACL and ACLS_VIEW_ACL pero object access check --- apps/acls/views.py | 134 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 33 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index ac8c72ea91..3cac1fbabe 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -13,6 +13,8 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User, Group from django.core.exceptions import ObjectDoesNotExist from django.utils.simplejson import loads +from django.core.exceptions import PermissionDenied +from django.utils.http import urlencode from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate @@ -33,10 +35,14 @@ def _permission_titles(permission_list): def acl_list_for(request, obj, extra_context=None): - Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) + try: + Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) + except PermissionDenied: + AccessEntry.objects.check_access(ACLS_VIEW_ACL, request.user, obj) + + logger.debug('obj: %s' % obj) ct = ContentType.objects.get_for_model(obj) - context = { 'object_list': AccessEntry.objects.get_holders_for(obj), 'title': _(u'access control lists for: %s' % obj), @@ -64,28 +70,39 @@ def acl_list(request, app_label, model_name, object_id): def acl_detail(request, access_object_gid, holder_object_gid): - Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) - try: holder = AccessHolder.get(gid=holder_object_gid) access_object = AccessObject.get(gid=access_object_gid) except ObjectDoesNotExist: raise Http404 - - permission_list = list(access_object.get_class_permissions()) + + navigation_object = request.GET.get('navigation_object') + logger.debug('navigation_object: %s' % navigation_object) + return acl_detail_for(request, holder.source_object, access_object.source_object, navigation_object) + + +def acl_detail_for(request, actor, obj, navigation_object=None): + try: + Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL, ACLS_EDIT_ACL]) + except PermissionDenied: + AccessEntry.objects.check_accesses([ACLS_VIEW_ACL, ACLS_EDIT_ACL], actor, obj) + + #permission_list = list(obj.get_class_permissions()) + permission_list = AccessEntry.objects.get_class_permissions_for(obj) + #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { 'name': u'generic_list_subtemplate.html', 'context': { - 'title': _(u'permissions available to: %s for %s' % (holder, access_object)), + 'title': _(u'permissions available to: %s for %s' % (actor, obj)), 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': 'namespace'}, {'name': _(u'label'), 'attribute': 'label'}, { 'name':_(u'has permission'), - 'attribute': encapsulate(lambda x: two_state_template(AccessEntry.objects.has_accesses(x, holder.source_object, access_object.source_object))) + 'attribute': encapsulate(lambda permission: two_state_template(AccessEntry.objects.has_access(permission, actor, obj))) }, ], #'hide_link': True, @@ -94,20 +111,32 @@ def acl_detail(request, access_object_gid, holder_object_gid): }, ] - return render_to_response('generic_detail.html', { - 'object': access_object.obj, + context = { + 'object': obj, 'subtemplates_list': subtemplates_list, 'multi_select_as_buttons': True, 'multi_select_item_properties': { 'permission_pk': lambda x: x.pk, - 'holder_gid': lambda x: holder.gid, - 'object_gid': lambda x: access_object.gid, - }, - }, context_instance=RequestContext(request)) + 'holder_gid': lambda x: AccessHolder(actor).gid, + 'object_gid': lambda x: AccessObject(obj).gid, + } + } + + if navigation_object: + context.update( + { + navigation_object: obj + } + ) + + return render_to_response( + 'generic_detail.html', + context, + context_instance=RequestContext(request) + ) def acl_grant(request): - Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) post_action_redirect = None @@ -118,23 +147,38 @@ def acl_grant(request): title_suffix = [] navigation_object = None navigation_object_count = 0 - + for item_properties in items_property_list: try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: raise Http404 + try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) except ObjectDoesNotExist: raise Http404 - - items.setdefault(requester, {}) - items[requester].setdefault(access_object, []) - items[requester][access_object].append(permission) - navigation_object = access_object - navigation_object_count += 1 + + try: + Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + except PermissionDenied: + try: + AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, access_object) + except PermissionDenied: + raise + else: + items.setdefault(requester, {}) + items[requester].setdefault(access_object, []) + items[requester][access_object].append(permission) + navigation_object = access_object + navigation_object_count += 1 + else: + items.setdefault(requester, {}) + items[requester].setdefault(access_object, []) + items[requester][access_object].append(permission) + navigation_object = access_object + navigation_object_count += 1 for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): @@ -187,7 +231,6 @@ def acl_grant(request): def acl_revoke(request): - Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) post_action_redirect = None @@ -204,17 +247,32 @@ def acl_revoke(request): permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: raise Http404 + try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) except ObjectDoesNotExist: raise Http404 - - items.setdefault(requester, {}) - items[requester].setdefault(access_object, []) - items[requester][access_object].append(permission) - navigation_object = access_object - navigation_object_count += 1 + + try: + Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + except PermissionDenied: + try: + AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, access_object) + except PermissionDenied: + raise + else: + items.setdefault(requester, {}) + items[requester].setdefault(access_object, []) + items[requester][access_object].append(permission) + navigation_object = access_object + navigation_object_count += 1 + else: + items.setdefault(requester, {}) + items[requester].setdefault(access_object, []) + items[requester][access_object].append(permission) + navigation_object = access_object + navigation_object_count += 1 for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): @@ -266,8 +324,11 @@ def acl_revoke(request): context_instance=RequestContext(request)) -def acl_new_holder_for(request, obj, extra_context=None): - Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) +def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None): + try: + Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) + except PermissionDenied: + AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, obj) if request.method == 'POST': form = HolderSelectionForm(request.POST) @@ -276,7 +337,14 @@ def acl_new_holder_for(request, obj, extra_context=None): access_object = AccessObject.encapsulate(obj) access_holder = AccessHolder.get(form.cleaned_data['holder_gid']) - return HttpResponseRedirect(reverse('acl_detail', args=[access_object.gid, access_holder.gid])) + query_string = {u'navigation_object': navigation_object} + + return HttpResponseRedirect( + u'%s?%s' % ( + reverse('acl_detail', args=[access_object.gid, access_holder.gid]), + urlencode(query_string) + ) + ) except ObjectDoesNotExist: raise Http404 else: @@ -352,7 +420,7 @@ def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): {'name': _(u'label'), 'attribute': 'label'}, { 'name':_(u'has permission'), - 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_accesses(x, holder.source_object, access_object_class.source_object))) + 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_access(x, holder.source_object, access_object_class.source_object))) }, ], #'hide_link': True, From d9621dfb1fa255699ddbcb43783333823c532dd5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 16:07:45 -0400 Subject: [PATCH 114/484] Add new document signature app --- apps/document_signatures/__init__.py | 37 ++++++++ apps/document_signatures/forms.py | 12 +++ apps/document_signatures/models.py | 58 ++++++++++++ apps/document_signatures/tests.py | 16 ++++ apps/document_signatures/urls.py | 7 ++ apps/document_signatures/views.py | 127 +++++++++++++++++++++++++++ 6 files changed, 257 insertions(+) create mode 100644 apps/document_signatures/__init__.py create mode 100644 apps/document_signatures/forms.py create mode 100644 apps/document_signatures/models.py create mode 100644 apps/document_signatures/tests.py create mode 100644 apps/document_signatures/urls.py create mode 100644 apps/document_signatures/views.py diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py new file mode 100644 index 0000000000..11edeb1d07 --- /dev/null +++ b/apps/document_signatures/__init__.py @@ -0,0 +1,37 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from documents.models import Document +from navigation.api import register_links, register_top_menu, \ + register_model_list_columns, register_multi_item_links, \ + register_sidebar_template +from main.api import register_diagnostic, register_maintenance_links +from permissions.api import register_permission, set_namespace_title +#from project_setup.api import register_setup + +#from django_gpg.api import Key + +PERMISSION_DOCUMENT_VERIFY = {'namespace': 'document_signatures', 'name': 'document_verify', 'label': _(u'Verify document signatures')} +PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'document_signatures', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} +PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'document_signatures', 'name': 'key_receive', 'label': _(u'Download detached signatures')} + +# Permission setup +set_namespace_title('document_signatures', _(u'Document signatures')) +register_permission(PERMISSION_DOCUMENT_VERIFY) +register_permission(PERMISSION_SIGNATURE_UPLOAD) +register_permission(PERMISSION_SIGNATURE_DOWNLOAD) + +def has_embedded_signature(context): + return context['object'].signature_state + +def doesnt_have_detached_signature(context): + return context['object'].has_detached_signature() == False + +document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} +document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} +document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} + +register_links(Document, [document_verify], menu_name='form_header') + +register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') diff --git a/apps/document_signatures/forms.py b/apps/document_signatures/forms.py new file mode 100644 index 0000000000..7e3f568b1b --- /dev/null +++ b/apps/document_signatures/forms.py @@ -0,0 +1,12 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ +#from django.utils.translation import ugettext +#from django.core.urlresolvers import reverse +#from django.utils.safestring import mark_safe +#from django.conf import settings + + +class DetachedSignatureForm(forms.Form): + file = forms.FileField( + label=_(u'Signature file'), + ) diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py new file mode 100644 index 0000000000..9086d3d7ce --- /dev/null +++ b/apps/document_signatures/models.py @@ -0,0 +1,58 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from documents.models import DocumentVersion, get_filename_from_uuid +from documents.conf.settings import STORAGE_BACKEND + + +class DocumentVersionSignature(models.Model): + ''' + Model that describes a document version signature properties + ''' + document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'), editable=False) + signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False) + signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) + + def update_signed_state(self, save=True): + if self.exists(): + try: + self.signature_state = gpg.verify_file(self.open()).status + # TODO: give use choice for auto public key fetch? + # OR maybe new config option + except GPGVerificationError: + self.signature_state = None + + if save: + self.save() + + def add_detached_signature(self, detached_signature): + if not self.signature_state: + self.signature_file = detached_signature + self.save() + else: + raise Exception('document already has an embedded signature') + + def has_detached_signature(self): + if self.signature_file: + return self.signature_file.storage.exists(self.signature_file.path) + else: + return False + + def detached_signature(self): + return self.signature_file.storage.open(self.signature_file.path) + + def verify_signature(self): + try: + if self.has_detached_signature(): + logger.debug('has detached signature') + signature = gpg.verify_w_retry(self.open(), self.detached_signature()) + else: + signature = gpg.verify_w_retry(self.open(raw=True)) + except GPGVerificationError: + signature = None + + return signature + + class Meta: + verbose_name = _(u'document version signature') + verbose_name_plural = _(u'document version signatures') diff --git a/apps/document_signatures/tests.py b/apps/document_signatures/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/apps/document_signatures/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/document_signatures/urls.py b/apps/document_signatures/urls.py new file mode 100644 index 0000000000..37d857aa40 --- /dev/null +++ b/apps/document_signatures/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('document_signatures.views', + url(r'^verify/(?P\d+)/$', 'document_verify', (), 'document_verify'), + url(r'^upload/signature/(?P\d+)/$', 'document_signature_upload', (), 'document_signature_upload'), + url(r'^download/signature/(?P\d+)/$', 'document_signature_download', (), 'document_signature_download'), +) diff --git a/apps/document_signatures/views.py b/apps/document_signatures/views.py new file mode 100644 index 0000000000..02b33d8847 --- /dev/null +++ b/apps/document_signatures/views.py @@ -0,0 +1,127 @@ +from __future__ import absolute_import + +from datetime import datetime +import logging + +from django.utils.translation import ugettext_lazy as _ +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.safestring import mark_safe +from django.conf import settings +from django.template.defaultfilters import force_escape + +from documents.models import Document, RecentDocument +from permissions.api import check_permissions +from common.utils import pretty_size, parse_range, urlquote, \ + return_diff, encapsulate +from filetransfers.api import serve_file + +from django_gpg.api import Key, SIGNATURE_STATES +from django_gpg.runtime import gpg +from django_gpg.exceptions import (GPGVerificationError, KeyFetchingError, + KeyImportError) + +from . import (PERMISSION_DOCUMENT_VERIFY, PERMISSION_SIGNATURE_UPLOAD, + PERMISSION_SIGNATURE_DOWNLOAD) +from .forms import DetachedSignatureForm +from .models import DocumentVersionSignature + +logger = logging.getLogger(__name__) + + +def document_verify(request, document_pk): + check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) + document = get_object_or_404(Document, pk=document_pk) + + RecentDocument.objects.add_document_for_user(request.user, document) + + signature = document.verify_signature() + + signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None)) + + widget = (u'' % (settings.STATIC_URL, signature_state['icon'])) + paragraphs = [ + _(u'Signature status: %(widget)s %(text)s') % { + 'widget': mark_safe(widget), + 'text': signature_state['text'] + }, + ] + + if document.signature_state: + signature_type = _(u'embedded') + else: + signature_type = _(u'detached') + + if signature: + paragraphs.extend( + [ + _(u'Signature ID: %s') % signature.signature_id, + _(u'Signature type: %s') % signature_type, + _(u'Key ID: %s') % signature.key_id, + _(u'Timestamp: %s') % datetime.fromtimestamp(int(signature.sig_timestamp)), + _(u'Signee: %s') % force_escape(getattr(signature, 'username', u'')), + ] + ) + + return render_to_response('generic_template.html', { + 'title': _(u'signature properties for: %s') % document, + 'object': document, + 'document': document, + 'paragraphs': paragraphs, + }, context_instance=RequestContext(request)) + + +def document_signature_upload(request, document_pk): + check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) + document = get_object_or_404(Document, pk=document_pk) + + RecentDocument.objects.add_document_for_user(request.user, document) + + post_action_redirect = None + 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', '/'))) + + if request.method == 'POST': + form = DetachedSignatureForm(request.POST, request.FILES) + if form.is_valid(): + try: + document.add_detached_signature(request.FILES['file']) + messages.success(request, _(u'Detached signature uploaded successfully.')) + return HttpResponseRedirect(next) + except Exception, msg: + messages.error(request, msg) + return HttpResponseRedirect(previous) + else: + form = DetachedSignatureForm() + + return render_to_response('generic_form.html', { + 'title': _(u'Upload detached signature for: %s') % document, + 'form_icon': 'key_delete.png', + 'next': next, + 'form': form, + 'previous': previous, + 'object': document, + }, context_instance=RequestContext(request)) + + +def document_signature_download(request, document_pk): + check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) + document = get_object_or_404(Document, pk=document_pk) + + try: + if document.has_detached_signature(): + signature = document.detached_signature() + return serve_file( + request, + signature, + save_as=u'"%s.sig"' % document.filename, + content_type=u'application/octet-stream' + ) + except Exception, e: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) + + return HttpResponseRedirect(request.META['HTTP_REFERER']) From c2419e63df37c91e2e0cacf02d3f157072cd1931 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 16:08:03 -0400 Subject: [PATCH 115/484] Move document signature handling to the new document signature app --- apps/django_gpg/__init__.py | 31 +++++------ apps/django_gpg/forms.py | 6 --- apps/django_gpg/urls.py | 3 -- apps/django_gpg/views.py | 105 ++---------------------------------- apps/documents/models.py | 38 +++++++++++-- 5 files changed, 52 insertions(+), 131 deletions(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index e45ae78165..a69efbab8e 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -11,29 +11,30 @@ from hkp import Key as KeyServerKey from django_gpg.api import Key -PERMISSION_DOCUMENT_VERIFY = {'namespace': 'django_gpg', 'name': 'document_verify', 'label': _(u'Verify document signatures')} PERMISSION_KEY_VIEW = {'namespace': 'django_gpg', 'name': 'key_view', 'label': _(u'View keys')} PERMISSION_KEY_DELETE = {'namespace': 'django_gpg', 'name': 'key_delete', 'label': _(u'Delete keys')} PERMISSION_KEYSERVER_QUERY = {'namespace': 'django_gpg', 'name': 'keyserver_query', 'label': _(u'Query keyservers')} PERMISSION_KEY_RECEIVE = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Import key from keyservers')} -PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'django_gpg', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} -PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Download detached signatures')} +#PERMISSION_DOCUMENT_VERIFY = {'namespace': 'django_gpg', 'name': 'document_verify', 'label': _(u'Verify document signatures')} +#PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'django_gpg', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} +#PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Download detached signatures')} # Permission setup set_namespace_title('django_gpg', _(u'Signatures')) -register_permission(PERMISSION_DOCUMENT_VERIFY) register_permission(PERMISSION_KEY_VIEW) register_permission(PERMISSION_KEY_DELETE) register_permission(PERMISSION_KEYSERVER_QUERY) register_permission(PERMISSION_KEY_RECEIVE) -register_permission(PERMISSION_SIGNATURE_UPLOAD) -register_permission(PERMISSION_SIGNATURE_DOWNLOAD) -def has_embedded_signature(context): - return context['object'].signature_state +#register_permission(PERMISSION_DOCUMENT_VERIFY) +#register_permission(PERMISSION_SIGNATURE_UPLOAD) +#register_permission(PERMISSION_SIGNATURE_DOWNLOAD) + +#def has_embedded_signature(context): +# return context['object'].signature_state -def doesnt_have_detached_signature(context): - return context['object'].has_detached_signature() == False +#def doesnt_have_detached_signature(context): +# return context['object'].has_detached_signature() == False # Setup views private_keys = {'text': _(u'private keys'), 'view': 'key_private_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} @@ -41,16 +42,16 @@ public_keys = {'text': _(u'public keys'), 'view': 'key_public_list', 'args': 'ob key_delete = {'text': _(u'delete'), 'view': 'key_delete', 'args': ['object.fingerprint', 'object.type'], 'famfam': 'key_delete', 'permissions': [PERMISSION_KEY_DELETE]} key_query = {'text': _(u'query keyservers'), 'view': 'key_query', 'famfam': 'zoom', 'permissions': [PERMISSION_KEYSERVER_QUERY]} key_receive = {'text': _(u'import'), 'view': 'key_receive', 'args': 'object.keyid', 'famfam': 'key_add', 'keep_query': True, 'permissions': [PERMISSION_KEY_RECEIVE]} -document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} -document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} key_setup = {'text': _(u'key management'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} # Document views -document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} +#document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} +#document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} +#document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} -register_links(Document, [document_verify], menu_name='form_header') +#register_links(Document, [document_verify], menu_name='form_header') +#register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') -register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') #register_links(['key_delete', 'key_private_list', 'key_public_list', 'key_query'], [private_keys, public_keys, key_query], menu_name='sidebar') register_links(['key_delete', 'key_public_list', 'key_query'], [public_keys, key_query], menu_name='sidebar') diff --git a/apps/django_gpg/forms.py b/apps/django_gpg/forms.py index b961daf037..619035fd5d 100644 --- a/apps/django_gpg/forms.py +++ b/apps/django_gpg/forms.py @@ -11,9 +11,3 @@ class KeySearchForm(forms.Form): label=_(u'Term'), help_text=_(u'Name, e-mail, key ID or key fingerprint to look for.') ) - - -class DetachedSignatureForm(forms.Form): - file = forms.FileField( - label=_(u'Signature file'), - ) diff --git a/apps/django_gpg/urls.py b/apps/django_gpg/urls.py index 4a22882d06..04ef8af89c 100644 --- a/apps/django_gpg/urls.py +++ b/apps/django_gpg/urls.py @@ -4,9 +4,6 @@ urlpatterns = patterns('django_gpg.views', url(r'^delete/(?P.+)/(?P\w+)/$', 'key_delete', (), 'key_delete'), url(r'^list/private/$', 'key_list', {'secret': True}, 'key_private_list'), url(r'^list/public/$', 'key_list', {'secret': False}, 'key_public_list'), - url(r'^verify/(?P\d+)/$', 'document_verify', (), 'document_verify'), - url(r'^upload/signature/(?P\d+)/$', 'document_signature_upload', (), 'document_signature_upload'), - url(r'^download/signature/(?P\d+)/$', 'document_signature_download', (), 'document_signature_download'), url(r'^query/$', 'key_query', (), 'key_query'), url(r'^receive/(?P.+)/$', 'key_receive', (), 'key_receive'), ) diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index 6fe629dbe8..7129246887 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -11,21 +11,17 @@ from django.utils.safestring import mark_safe from django.conf import settings from django.template.defaultfilters import force_escape -from documents.models import Document, RecentDocument from permissions.api import check_permissions from common.utils import pretty_size, parse_range, urlquote, \ return_diff, encapsulate -from filetransfers.api import serve_file from django_gpg.api import Key, SIGNATURE_STATES from django_gpg.runtime import gpg from django_gpg.exceptions import (GPGVerificationError, KeyFetchingError, KeyImportError) -from django_gpg import (PERMISSION_DOCUMENT_VERIFY, PERMISSION_KEY_VIEW, - PERMISSION_KEY_DELETE, PERMISSION_KEYSERVER_QUERY, - PERMISSION_KEY_RECEIVE, PERMISSION_SIGNATURE_UPLOAD, - PERMISSION_SIGNATURE_DOWNLOAD) -from django_gpg.forms import KeySearchForm, DetachedSignatureForm +from django_gpg import (PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, + PERMISSION_KEYSERVER_QUERY, PERMISSION_KEY_RECEIVE) +from django_gpg.forms import KeySearchForm logger = logging.getLogger(__name__) @@ -189,98 +185,3 @@ def key_query(request): return render_to_response('generic_form.html', { 'subtemplates_list': subtemplates_list, }, context_instance=RequestContext(request)) - - -def document_verify(request, document_pk): - check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) - document = get_object_or_404(Document, pk=document_pk) - - RecentDocument.objects.add_document_for_user(request.user, document) - - signature = document.verify_signature() - - signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None)) - - widget = (u'' % (settings.STATIC_URL, signature_state['icon'])) - paragraphs = [ - _(u'Signature status: %(widget)s %(text)s') % { - 'widget': mark_safe(widget), - 'text': signature_state['text'] - }, - ] - - if document.signature_state: - signature_type = _(u'embedded') - else: - signature_type = _(u'detached') - - if signature: - paragraphs.extend( - [ - _(u'Signature ID: %s') % signature.signature_id, - _(u'Signature type: %s') % signature_type, - _(u'Key ID: %s') % signature.key_id, - _(u'Timestamp: %s') % datetime.fromtimestamp(int(signature.sig_timestamp)), - _(u'Signee: %s') % force_escape(getattr(signature, 'username', u'')), - ] - ) - - return render_to_response('generic_template.html', { - 'title': _(u'signature properties for: %s') % document, - 'object': document, - 'document': document, - 'paragraphs': paragraphs, - }, context_instance=RequestContext(request)) - - -def document_signature_upload(request, document_pk): - check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) - document = get_object_or_404(Document, pk=document_pk) - - RecentDocument.objects.add_document_for_user(request.user, document) - - post_action_redirect = None - 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', '/'))) - - if request.method == 'POST': - form = DetachedSignatureForm(request.POST, request.FILES) - if form.is_valid(): - try: - document.add_detached_signature(request.FILES['file']) - messages.success(request, _(u'Detached signature uploaded successfully.')) - return HttpResponseRedirect(next) - except Exception, msg: - messages.error(request, msg) - return HttpResponseRedirect(previous) - else: - form = DetachedSignatureForm() - - return render_to_response('generic_form.html', { - 'title': _(u'Upload detached signature for: %s') % document, - 'form_icon': 'key_delete.png', - 'next': next, - 'form': form, - 'previous': previous, - 'object': document, - }, context_instance=RequestContext(request)) - - -def document_signature_download(request, document_pk): - check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) - document = get_object_or_404(Document, pk=document_pk) - - try: - if document.has_detached_signature(): - signature = document.detached_signature() - return serve_file( - request, - signature, - save_as=u'"%s.sig"' % document.filename, - content_type=u'application/octet-stream' - ) - except Exception, e: - messages.error(request, e) - return HttpResponseRedirect(request.META['HTTP_REFERER']) - - return HttpResponseRedirect(request.META['HTTP_REFERER']) diff --git a/apps/documents/models.py b/apps/documents/models.py index d05737632a..b5366934e2 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -288,7 +288,9 @@ class Document(models.Model): return version.save() filename = property(_get_filename, _set_filename) - + + #TODO: remove after migration + """ def add_detached_signature(self, *args, **kwargs): return self.latest_version.add_detached_signature(*args, **kwargs) @@ -300,12 +302,14 @@ class Document(models.Model): def verify_signature(self): return self.latest_version.verify_signature() - + """ class DocumentVersion(models.Model): ''' Model that describes a document version and its properties ''' + _pre_open_hooks = {} + @staticmethod def get_version_update_choices(document_version): return ( @@ -314,6 +318,10 @@ class DocumentVersion(models.Model): (VERSION_UPDATE_MICRO, _(u'Micro %(major)i.%(minor)i.%(micro)i, (fixes)') % document_version.get_new_version_dict(VERSION_UPDATE_MICRO)) ) + @classmethod + def register_pre_open_hook(cls, order, func): + cls._pre_open_hooks[order] = func + document = models.ForeignKey(Document, verbose_name=_(u'document'), editable=False) major = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1, editable=False) minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0, editable=False) @@ -329,6 +337,8 @@ class DocumentVersion(models.Model): encoding = models.CharField(max_length=64, default='', editable=False) filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) + + #TODO: to be removed after migration signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False) signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) @@ -393,7 +403,9 @@ class DocumentVersion(models.Model): if new_document: #Only do this for new documents - self.update_signed_state(save=False) + #Only do this for new documents + # TODO: remove after migration + #self.update_signed_state(save=False) self.update_checksum(save=False) self.update_mimetype(save=False) self.save() @@ -467,6 +479,8 @@ class DocumentVersion(models.Model): for version in self.document.versions.filter(timestamp__gt=self.timestamp): version.delete() + #TODO: remove after migration + """ def update_signed_state(self, save=True): if self.exists(): try: @@ -478,7 +492,8 @@ class DocumentVersion(models.Model): if save: self.save() - + """ + def update_mimetype(self, save=True): ''' Read a document verions's file and determine the mimetype by calling the @@ -510,6 +525,16 @@ class DocumentVersion(models.Model): Return a file descriptor to a document version's file irrespective of the storage backend ''' + if raw: + return self.file.storage.open(self.file.path) + else: + result = self.file.storage.open(self.file.path) + for key in sorted(DocumentVersion._pre_open_hooks): + result = DocumentVersion._pre_open_hooks[key](result) + + return result + #TODO: remove after migration + """ if self.signature_state and not raw: try: result = gpg.decrypt_file(self.file.storage.open(self.file.path)) @@ -520,6 +545,7 @@ class DocumentVersion(models.Model): return self.file.storage.open(self.file.path) else: return self.file.storage.open(self.file.path) + """ def save_to_file(self, filepath, buffer_size=1024 * 1024): ''' @@ -545,7 +571,8 @@ class DocumentVersion(models.Model): return self.file.storage.size(self.file.path) else: return None - + #TODO: remove after migration + """ def add_detached_signature(self, detached_signature): if not self.signature_state: self.signature_file = detached_signature @@ -573,6 +600,7 @@ class DocumentVersion(models.Model): signature = None return signature + """ class DocumentTypeFilename(models.Model): From c0fbec0f8e1fa68da74cf22d89e10a0c6ec3cb3b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 25 Dec 2011 16:08:28 -0400 Subject: [PATCH 116/484] Add and enable new document singatures app --- settings.py | 1 + urls.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/settings.py b/settings.py index 2620793172..8372d0dd19 100644 --- a/settings.py +++ b/settings.py @@ -168,6 +168,7 @@ INSTALLED_APPS = ( 'djangorestframework', 'rest_api', 'south', + 'document_signatures', ) TEMPLATE_CONTEXT_PROCESSORS = ( diff --git a/urls.py b/urls.py index a4ccd38cef..f2c8ea5b71 100644 --- a/urls.py +++ b/urls.py @@ -28,7 +28,8 @@ urlpatterns = patterns('', (r'^project_setup/', include('project_setup.urls')), (r'^project_tools/', include('project_tools.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')), ) From 37050073302b0505b5fd60acf52ff3711936f9ba Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 31 Dec 2011 00:22:20 -0400 Subject: [PATCH 117/484] Move comments and tags manager statements to their respective apps --- apps/document_comments/__init__.py | 10 ++++++++++ apps/documents/models.py | 11 ----------- apps/tags/__init__.py | 3 +++ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/document_comments/__init__.py b/apps/document_comments/__init__.py index 01619af003..7bc049db4d 100644 --- a/apps/document_comments/__init__.py +++ b/apps/document_comments/__init__.py @@ -1,6 +1,7 @@ from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.contrib.comments.models import Comment +from django.contrib.contenttypes import generic from navigation.api import register_links, \ register_model_list_columns @@ -47,3 +48,12 @@ register_links(['comments_for_object', 'comment_add', 'comment_delete', 'comment register_links(Comment, [comment_delete]) register_links(Document, [comments_for_object], menu_name='form_header') + +Document.add_to_class( + 'comments', + generic.GenericRelation( + Comment, + content_type_field='content_type', + object_id_field='object_pk' + ) +) diff --git a/apps/documents/models.py b/apps/documents/models.py index b5366934e2..d2edaf0e91 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -15,11 +15,8 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.contrib.auth.models import User -from django.contrib.contenttypes import generic -from django.contrib.comments.models import Comment from django.core.exceptions import ValidationError -from taggit.managers import TaggableManager from dynamic_search.api import register from converter.api import get_page_count from converter.api import get_available_transformations_choices @@ -86,14 +83,6 @@ class Document(models.Model): description = models.TextField(blank=True, null=True, verbose_name=_(u'description')) date_added = models.DateTimeField(verbose_name=_(u'added'), db_index=True, editable=False) - tags = TaggableManager() - - comments = generic.GenericRelation( - Comment, - content_type_field='content_type', - object_id_field='object_pk' - ) - @staticmethod def clear_image_cache(): for the_file in os.listdir(CACHE_PATH): diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 4b349e012e..c6170e4e28 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -7,6 +7,7 @@ from common.utils import encapsulate from documents.models import Document from taggit.models import Tag +from taggit.managers import TaggableManager from tags.widgets import tag_color_block @@ -61,3 +62,5 @@ 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_multi_item_links(['document_tags'], [tag_document_remove_multiple]) + +Document.add_to_class('tags', TaggableManager()) From 51464c910baff4c0e7eb4c27b73ad81e5f154464 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 31 Dec 2011 03:26:25 -0400 Subject: [PATCH 118/484] Move more signature functionality to the document signature app --- apps/document_signatures/__init__.py | 46 +++++---- apps/document_signatures/models.py | 129 +++++++++++++++++------- apps/document_signatures/permissions.py | 15 +++ apps/document_signatures/views.py | 14 +-- apps/documents/models.py | 2 - 5 files changed, 141 insertions(+), 65 deletions(-) create mode 100644 apps/document_signatures/permissions.py diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index 11edeb1d07..1422b3e4e6 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -1,37 +1,49 @@ from __future__ import absolute_import +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + from django.utils.translation import ugettext_lazy as _ -from documents.models import Document +from documents.models import Document, DocumentVersion from navigation.api import register_links, register_top_menu, \ register_model_list_columns, register_multi_item_links, \ register_sidebar_template -from main.api import register_diagnostic, register_maintenance_links -from permissions.api import register_permission, set_namespace_title -#from project_setup.api import register_setup +from django_gpg.runtime import gpg +from django_gpg.exceptions import GPGDecryptionError +#from main.api import register_diagnostic, register_maintenance_links -#from django_gpg.api import Key +from .models import DocumentVersionSignature +from .permissions import ( + PERMISSION_DOCUMENT_VERIFY, + PERMISSION_SIGNATURE_UPLOAD, + PERMISSION_SIGNATURE_DOWNLOAD + ) -PERMISSION_DOCUMENT_VERIFY = {'namespace': 'document_signatures', 'name': 'document_verify', 'label': _(u'Verify document signatures')} -PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'document_signatures', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} -PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'document_signatures', 'name': 'key_receive', 'label': _(u'Download detached signatures')} - -# Permission setup -set_namespace_title('document_signatures', _(u'Document signatures')) -register_permission(PERMISSION_DOCUMENT_VERIFY) -register_permission(PERMISSION_SIGNATURE_UPLOAD) -register_permission(PERMISSION_SIGNATURE_DOWNLOAD) def has_embedded_signature(context): - return context['object'].signature_state + return DocumentVersionSignature.objects.has_embedded_signature(context['object']) def doesnt_have_detached_signature(context): - return context['object'].has_detached_signature() == False + return DocumentVersionSignature.objects.has_detached_signature(context['object']) == False + +def document_pre_open_hook(descriptor): + try: + result = gpg.decrypt_file(descriptor) + # gpg return a string, turn it into a file like object + return StringIO(result.data) + except GPGDecryptionError: + # At least return the original raw content + return descriptor document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} register_links(Document, [document_verify], menu_name='form_header') - register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') + + +DocumentVersion.register_pre_open_hook(1, document_pre_open_hook) diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 9086d3d7ce..645dc04270 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -1,9 +1,98 @@ +import logging + from django.db import models from django.utils.translation import ugettext_lazy as _ from documents.models import DocumentVersion, get_filename_from_uuid from documents.conf.settings import STORAGE_BACKEND +from django_gpg.runtime import gpg +from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError +logger = logging.getLogger(__name__) + + +class DocumentVersionSignatureManager(models.Manager): + #def update_signed_state(self, document): + # document_signature, created = self.model.get_or_create( + # document_version=document.latest_version, + # ) + # if document.exists(): + # descriptor = document.open() + # try: + # document_signature.signature_state = gpg.verify_file(descriptor).status + # # TODO: give use choice for auto public key fetch? + # # OR maybe new config option + # except GPGVerificationError: + # document_signature.signature_state = None + # finally: + # document_signature.save() + + def add_detached_signature(self, document, detached_signature): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + if not self.signature_state(document): + document_signature.signature_file = detached_signature + document_signature.save() + else: + raise Exception('document already has an embedded signature') + + def has_detached_signature(self, document): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + if document_signature.signature_file: + return True + else: + return False + + def has_embedded_signature(self, document): + logger.debug('document: %s' % document) + + if self.signature_state(document): + return True + else: + return False + + def signature_state(self, document): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + logger.debug('created: %s' % created) + if created and document.exists(): + descriptor = document.open(raw=True) + try: + document_signature.signature_state = gpg.verify_file(descriptor).status + # TODO: give use choice for auto public key fetch? + # OR maybe new config option + except GPGVerificationError: + document_signature.signature_state = None + finally: + document_signature.save() + + #document_signature.signature_state = self.verify_signature(document).status + #document_signature.save() + + return document_signature.signature_state + + def detached_signature(self, document): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + return document_signature.signature_file.storage.open(document_signature.signature_file.path) + + def verify_signature(self, document): + if self.has_detached_signature(document): + logger.debug('has detached signature') + args = (document.open(), self.detached_signature(document)) + else: + args = (document.open(raw=True),) + + try: + return gpg.verify_w_retry(*args) + except GPGVerificationError: + return None + class DocumentVersionSignature(models.Model): ''' @@ -13,46 +102,8 @@ class DocumentVersionSignature(models.Model): signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False) signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) - def update_signed_state(self, save=True): - if self.exists(): - try: - self.signature_state = gpg.verify_file(self.open()).status - # TODO: give use choice for auto public key fetch? - # OR maybe new config option - except GPGVerificationError: - self.signature_state = None - - if save: - self.save() + objects = DocumentVersionSignatureManager() - def add_detached_signature(self, detached_signature): - if not self.signature_state: - self.signature_file = detached_signature - self.save() - else: - raise Exception('document already has an embedded signature') - - def has_detached_signature(self): - if self.signature_file: - return self.signature_file.storage.exists(self.signature_file.path) - else: - return False - - def detached_signature(self): - return self.signature_file.storage.open(self.signature_file.path) - - def verify_signature(self): - try: - if self.has_detached_signature(): - logger.debug('has detached signature') - signature = gpg.verify_w_retry(self.open(), self.detached_signature()) - else: - signature = gpg.verify_w_retry(self.open(raw=True)) - except GPGVerificationError: - signature = None - - return signature - class Meta: verbose_name = _(u'document version signature') verbose_name_plural = _(u'document version signatures') diff --git a/apps/document_signatures/permissions.py b/apps/document_signatures/permissions.py new file mode 100644 index 0000000000..9bbfdfece8 --- /dev/null +++ b/apps/document_signatures/permissions.py @@ -0,0 +1,15 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.api import register_permission, set_namespace_title + +PERMISSION_DOCUMENT_VERIFY = {'namespace': 'document_signatures', 'name': 'document_verify', 'label': _(u'Verify document signatures')} +PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'document_signatures', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} +PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'document_signatures', 'name': 'key_receive', 'label': _(u'Download detached signatures')} + +# Permission setup +set_namespace_title('document_signatures', _(u'Document signatures')) +register_permission(PERMISSION_DOCUMENT_VERIFY) +register_permission(PERMISSION_SIGNATURE_UPLOAD) +register_permission(PERMISSION_SIGNATURE_DOWNLOAD) diff --git a/apps/document_signatures/views.py b/apps/document_signatures/views.py index 02b33d8847..dd83df19be 100644 --- a/apps/document_signatures/views.py +++ b/apps/document_signatures/views.py @@ -38,8 +38,8 @@ def document_verify(request, document_pk): RecentDocument.objects.add_document_for_user(request.user, document) - signature = document.verify_signature() - + signature = DocumentVersionSignature.objects.verify_signature(document) + signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None)) widget = (u'' % (settings.STATIC_URL, signature_state['icon'])) @@ -50,7 +50,7 @@ def document_verify(request, document_pk): }, ] - if document.signature_state: + if DocumentVersionSignature.objects.has_embedded_signature(document): signature_type = _(u'embedded') else: signature_type = _(u'detached') @@ -88,7 +88,7 @@ def document_signature_upload(request, document_pk): form = DetachedSignatureForm(request.POST, request.FILES) if form.is_valid(): try: - document.add_detached_signature(request.FILES['file']) + DocumentVersionSignature.objects.add_detached_signature(document, request.FILES['file']) messages.success(request, _(u'Detached signature uploaded successfully.')) return HttpResponseRedirect(next) except Exception, msg: @@ -110,10 +110,10 @@ def document_signature_upload(request, document_pk): def document_signature_download(request, document_pk): check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) document = get_object_or_404(Document, pk=document_pk) - + try: - if document.has_detached_signature(): - signature = document.detached_signature() + if DocumentVersionSignature.objects.has_detached_signature(document): + signature = DocumentVersionSignature.objects.detached_signature(document) return serve_file( request, signature, diff --git a/apps/documents/models.py b/apps/documents/models.py index d2edaf0e91..2255d487fe 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -26,8 +26,6 @@ from mimetype.api import (get_mimetype, get_icon_file_path, get_error_icon_file_path) from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_PAGE_NUMBER) -from django_gpg.runtime import gpg -from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError from documents.conf.settings import CHECKSUM_FUNCTION from documents.conf.settings import UUID_FUNCTION From 9e71b0bbc540b68dc196872c47e5aff6e7de4108 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 31 Dec 2011 03:27:29 -0400 Subject: [PATCH 119/484] Don't mask upload errors when the DEBUG flas is True --- apps/sources/views.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/sources/views.py b/apps/sources/views.py index 17e8c380a6..48330415fd 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -6,6 +6,7 @@ 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 documents.literals import PERMISSION_DOCUMENT_CREATE from documents.models import DocumentType, Document @@ -156,6 +157,8 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No messages.success(request, _(u'Document uploaded successfully.')) return HttpResponseRedirect(request.get_full_path()) except Exception, e: + if settings.DEBUG: + raise messages.error(request, _(u'Unhandled exception: %s') % e) else: form = WebFormForm( @@ -226,6 +229,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, From 3de53dccfa196deaa6b1483fdff711c69df47737 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:10:52 -0400 Subject: [PATCH 120/484] Added document_post_save signal to detect is a document has a signature, improve the pre_open_hook, and added logging --- apps/document_signatures/__init__.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index 1422b3e4e6..f8a60505ac 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -1,4 +1,5 @@ from __future__ import absolute_import +import logging try: from cStringIO import StringIO @@ -6,6 +7,7 @@ except ImportError: from StringIO import StringIO from django.utils.translation import ugettext_lazy as _ +from django.db.models.signals import post_save from documents.models import Document, DocumentVersion from navigation.api import register_links, register_top_menu, \ @@ -13,7 +15,6 @@ from navigation.api import register_links, register_top_menu, \ register_sidebar_template from django_gpg.runtime import gpg from django_gpg.exceptions import GPGDecryptionError -#from main.api import register_diagnostic, register_maintenance_links from .models import DocumentVersionSignature from .permissions import ( @@ -22,6 +23,8 @@ from .permissions import ( PERMISSION_SIGNATURE_DOWNLOAD ) +logger = logging.getLogger(__name__) + def has_embedded_signature(context): return DocumentVersionSignature.objects.has_embedded_signature(context['object']) @@ -31,12 +34,18 @@ def doesnt_have_detached_signature(context): def document_pre_open_hook(descriptor): try: - result = gpg.decrypt_file(descriptor) + result = gpg.decrypt_file(descriptor, close_descriptor=False) # gpg return a string, turn it into a file like object - return StringIO(result.data) except GPGDecryptionError: # At least return the original raw content + descriptor.seek(0) return descriptor + else: + return StringIO(result.data) + +def document_post_save(sender, instance, **kwargs): + if kwargs.get('created', False): + DocumentVersionSignature.objects.signature_state(instance.document) document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} @@ -45,5 +54,6 @@ document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': register_links(Document, [document_verify], menu_name='form_header') register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') - DocumentVersion.register_pre_open_hook(1, document_pre_open_hook) + +post_save.connect(document_post_save, sender=DocumentVersion) From 6cafb394e94583cb1acc3a567692282a51e4c557 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:11:40 -0400 Subject: [PATCH 121/484] Move manager code to a new managers.py file --- apps/document_signatures/managers.py | 91 ++++++++++++++++++++++++++++ apps/document_signatures/models.py | 88 +-------------------------- 2 files changed, 94 insertions(+), 85 deletions(-) create mode 100644 apps/document_signatures/managers.py diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py new file mode 100644 index 0000000000..04980e3094 --- /dev/null +++ b/apps/document_signatures/managers.py @@ -0,0 +1,91 @@ +import logging + +from django.db import models + +from django_gpg.runtime import gpg +from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError + +logger = logging.getLogger(__name__) + + +class DocumentVersionSignatureManager(models.Manager): + #def update_signed_state(self, document): + # document_signature, created = self.model.get_or_create( + # document_version=document.latest_version, + # ) + # if document.exists(): + # descriptor = document.open() + # try: + # document_signature.signature_state = gpg.verify_file(descriptor).status + # # TODO: give use choice for auto public key fetch? + # # OR maybe new config option + # except GPGVerificationError: + # document_signature.signature_state = None + # finally: + # document_signature.save() + + def add_detached_signature(self, document, detached_signature): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + if not self.signature_state(document): + document_signature.signature_file = detached_signature + document_signature.save() + else: + raise Exception('document already has an embedded signature') + + def has_detached_signature(self, document): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + if document_signature.signature_file: + return True + else: + return False + + def has_embedded_signature(self, document): + logger.debug('document: %s' % document) + + if self.signature_state(document): + return True + else: + return False + + def signature_state(self, document): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + logger.debug('created: %s' % created) + if created and document.exists(): + descriptor = document.open(raw=True) + try: + document_signature.signature_state = gpg.verify_file(descriptor).status + # TODO: give use choice for auto public key fetch? + # OR maybe new config option + except GPGVerificationError: + document_signature.signature_state = None + finally: + document_signature.save() + + #document_signature.signature_state = self.verify_signature(document).status + #document_signature.save() + + return document_signature.signature_state + + def detached_signature(self, document): + document_signature, created = self.model.objects.get_or_create( + document_version=document.latest_version, + ) + return document_signature.signature_file.storage.open(document_signature.signature_file.path) + + def verify_signature(self, document): + if self.has_detached_signature(document): + logger.debug('has detached signature') + args = (document.open(raw=True), self.detached_signature(document)) + else: + args = (document.open(raw=True),) + + try: + return gpg.verify_w_retry(*args) + except GPGVerificationError: + return None diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 645dc04270..3f2b40c057 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import logging from django.db import models @@ -5,95 +6,12 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import DocumentVersion, get_filename_from_uuid from documents.conf.settings import STORAGE_BACKEND -from django_gpg.runtime import gpg -from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError + +from .managers import DocumentVersionSignatureManager logger = logging.getLogger(__name__) -class DocumentVersionSignatureManager(models.Manager): - #def update_signed_state(self, document): - # document_signature, created = self.model.get_or_create( - # document_version=document.latest_version, - # ) - # if document.exists(): - # descriptor = document.open() - # try: - # document_signature.signature_state = gpg.verify_file(descriptor).status - # # TODO: give use choice for auto public key fetch? - # # OR maybe new config option - # except GPGVerificationError: - # document_signature.signature_state = None - # finally: - # document_signature.save() - - def add_detached_signature(self, document, detached_signature): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) - if not self.signature_state(document): - document_signature.signature_file = detached_signature - document_signature.save() - else: - raise Exception('document already has an embedded signature') - - def has_detached_signature(self, document): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) - if document_signature.signature_file: - return True - else: - return False - - def has_embedded_signature(self, document): - logger.debug('document: %s' % document) - - if self.signature_state(document): - return True - else: - return False - - def signature_state(self, document): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) - logger.debug('created: %s' % created) - if created and document.exists(): - descriptor = document.open(raw=True) - try: - document_signature.signature_state = gpg.verify_file(descriptor).status - # TODO: give use choice for auto public key fetch? - # OR maybe new config option - except GPGVerificationError: - document_signature.signature_state = None - finally: - document_signature.save() - - #document_signature.signature_state = self.verify_signature(document).status - #document_signature.save() - - return document_signature.signature_state - - def detached_signature(self, document): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) - return document_signature.signature_file.storage.open(document_signature.signature_file.path) - - def verify_signature(self, document): - if self.has_detached_signature(document): - logger.debug('has detached signature') - args = (document.open(), self.detached_signature(document)) - else: - args = (document.open(raw=True),) - - try: - return gpg.verify_w_retry(*args) - except GPGVerificationError: - return None - - class DocumentVersionSignature(models.Model): ''' Model that describes a document version signature properties From 796475dfd9f7600074e8b76b0b576e6bb4de08e9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:12:13 -0400 Subject: [PATCH 122/484] Update file access to be smarter and accept either file like objects of file names, use less code to do so too --- apps/django_gpg/api.py | 78 ++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 8d9f2e2b4b..af95cc924f 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -1,5 +1,5 @@ import types -from StringIO import StringIO + from pickle import dumps import logging import tempfile @@ -151,6 +151,17 @@ class Key(object): class GPG(object): + @staticmethod + def get_descriptor(file_input): + try: + # Is it a file like object? + file_input.seek(0) + except AttributeError: + # If not, try open it. + return open(file_input, 'rb') + else: + return file_input + def __init__(self, binary_path=None, home=None, keyring=None, keyservers=None): kwargs = {} if binary_path: @@ -167,52 +178,46 @@ class GPG(object): self.gpg = gnupg.GPG(**kwargs) def verify_w_retry(self, file_input, detached_signature=None): - if isinstance(file_input, types.StringTypes): - input_descriptor = open(file_input, 'rb') - elif isinstance(file_input, types.FileType) or isinstance(file_input, File): - input_descriptor = file_input - elif issubclass(file_input.__class__, StringIO): - input_descriptor = file_input - else: - raise ValueError('Invalid file_input argument type') + logger.debug('file_input type: %s' % type(file_input)) + + input_descriptor = GPG.get_descriptor(file_input) try: - verify = self.verify_file(input_descriptor, detached_signature) + verify = self.verify_file(input_descriptor, detached_signature, close_descriptor=False) if verify.status == 'no public key': # Try to fetch the public key from the keyservers try: self.receive_key(verify.key_id) - return self.verify_w_retry(file_input, detached_signature) + return self.verify_w_retry(input_descriptor, detached_signature) except KeyFetchingError: return verify else: + input_descriptor.close() return verify except IOError: return False - def verify_file(self, file_input, detached_signature=None): - """ + def verify_file(self, file_input, detached_signature=None, close_descriptor=True): + ''' Verify the signature of a file. - """ - if isinstance(file_input, types.StringTypes): - descriptor = open(file_input, 'rb') - elif isinstance(file_input, types.FileType) or isinstance(file_input, File) or isinstance(file_input, StringIO): - descriptor = file_input - else: - raise ValueError('Invalid file_input argument type') + ''' + input_descriptor = GPG.get_descriptor(file_input) + if detached_signature: # Save the original data and invert the argument order # Signature first, file second file_descriptor, filename = tempfile.mkstemp(prefix='django_gpg') - file_data = file_input.read() + file_data = input_descriptor.read() file_input.close() os.write(file_descriptor, file_data) os.close(file_descriptor) verify = self.gpg.verify_file(detached_signature, data_filename=filename) else: - verify = self.gpg.verify_file(descriptor) - descriptor.close() + verify = self.gpg.verify_file(input_descriptor) + + if close_descriptor: + input_descriptor.close() if verify: return verify @@ -232,12 +237,13 @@ class GPG(object): raise GPGVerificationError(verify.status) def sign_file(self, file_input, key=None, destination=None, key_id=None, passphrase=None, clearsign=False): - """ + ''' Signs a filename, storing the signature and the original file in the destination filename provided (the destination file is overrided if it already exists), if no destination file name is provided the signature is returned. - """ + ''' + kwargs = {} kwargs['clearsign'] = clearsign @@ -250,14 +256,7 @@ class GPG(object): if passphrase: kwargs['passphrase'] = passphrase - if isinstance(file_input, types.StringTypes): - input_descriptor = open(file_input, 'rb') - elif isinstance(file_input, types.FileType) or isinstance(file_input, File): - input_descriptor = file_input - elif issubclass(file_input.__class__, StringIO): - input_descriptor = file_input - else: - raise ValueError('Invalid file_input argument type') + input_descriptor = GPG.get_descriptor(file_input) if destination: output_descriptor = open(destination, 'wb') @@ -277,16 +276,13 @@ class GPG(object): if not destination: return signed_data - def decrypt_file(self, file_input): - if isinstance(file_input, types.StringTypes): - input_descriptor = open(file_input, 'rb') - elif isinstance(file_input, types.FileType) or isinstance(file_input, File) or isinstance(file_input, StringIO): - input_descriptor = file_input - else: - raise ValueError('Invalid file_input argument type') + def decrypt_file(self, file_input, close_descriptor=True): + input_descriptor = GPG.get_descriptor(file_input) result = self.gpg.decrypt_file(input_descriptor) - input_descriptor.close() + if close_descriptor: + input_descriptor.close() + if not result.status: raise GPGDecryptionError('Unable to decrypt file') From 992f470039de18efc125ac9661dbf7a99ecf2a81 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:14:58 -0400 Subject: [PATCH 123/484] Add translation file for the new document_signatures app --- .../locale/en/LC_MESSAGES/django.po | 122 +++++++++++++++++ .../locale/es/LC_MESSAGES/django.po | 123 +++++++++++++++++ .../locale/it/LC_MESSAGES/django.po | 123 +++++++++++++++++ .../locale/pt/LC_MESSAGES/django.po | 123 +++++++++++++++++ .../locale/ru/LC_MESSAGES/django.po | 124 ++++++++++++++++++ 5 files changed, 615 insertions(+) create mode 100644 apps/document_signatures/locale/en/LC_MESSAGES/django.po create mode 100644 apps/document_signatures/locale/es/LC_MESSAGES/django.po create mode 100644 apps/document_signatures/locale/it/LC_MESSAGES/django.po create mode 100644 apps/document_signatures/locale/pt/LC_MESSAGES/django.po create mode 100644 apps/document_signatures/locale/ru/LC_MESSAGES/django.po diff --git a/apps/document_signatures/locale/en/LC_MESSAGES/django.po b/apps/document_signatures/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000000..f2c2ac4175 --- /dev/null +++ b/apps/document_signatures/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,122 @@ +# 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: 2012-01-01 20:14-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: __init__.py:50 +msgid "upload signature" +msgstr "" + +#: __init__.py:51 +msgid "download signature" +msgstr "" + +#: __init__.py:52 +msgid "signatures" +msgstr "" + +#: forms.py:11 +msgid "Signature file" +msgstr "" + +#: models.py:19 +msgid "document version" +msgstr "" + +#: models.py:20 +msgid "signature state" +msgstr "" + +#: models.py:21 +msgid "signature file" +msgstr "" + +#: models.py:26 +msgid "document version signature" +msgstr "" + +#: models.py:27 +msgid "document version signatures" +msgstr "" + +#: permissions.py:7 +msgid "Verify document signatures" +msgstr "" + +#: permissions.py:8 +msgid "Upload detached signatures" +msgstr "" + +#: permissions.py:9 +msgid "Download detached signatures" +msgstr "" + +#: permissions.py:12 +msgid "Document signatures" +msgstr "" + +#: views.py:47 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "" + +#: views.py:54 +msgid "embedded" +msgstr "" + +#: views.py:56 +msgid "detached" +msgstr "" + +#: views.py:61 +#, python-format +msgid "Signature ID: %s" +msgstr "" + +#: views.py:62 +#, python-format +msgid "Signature type: %s" +msgstr "" + +#: views.py:63 +#, python-format +msgid "Key ID: %s" +msgstr "" + +#: views.py:64 +#, python-format +msgid "Timestamp: %s" +msgstr "" + +#: views.py:65 +#, python-format +msgid "Signee: %s" +msgstr "" + +#: views.py:70 +#, python-format +msgid "signature properties for: %s" +msgstr "" + +#: views.py:92 +msgid "Detached signature uploaded successfully." +msgstr "" + +#: views.py:101 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "" diff --git a/apps/document_signatures/locale/es/LC_MESSAGES/django.po b/apps/document_signatures/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000..6aaa824359 --- /dev/null +++ b/apps/document_signatures/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,123 @@ +# 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: 2012-01-01 20:14-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:50 +msgid "upload signature" +msgstr "" + +#: __init__.py:51 +msgid "download signature" +msgstr "" + +#: __init__.py:52 +msgid "signatures" +msgstr "" + +#: forms.py:11 +msgid "Signature file" +msgstr "" + +#: models.py:19 +msgid "document version" +msgstr "" + +#: models.py:20 +msgid "signature state" +msgstr "" + +#: models.py:21 +msgid "signature file" +msgstr "" + +#: models.py:26 +msgid "document version signature" +msgstr "" + +#: models.py:27 +msgid "document version signatures" +msgstr "" + +#: permissions.py:7 +msgid "Verify document signatures" +msgstr "" + +#: permissions.py:8 +msgid "Upload detached signatures" +msgstr "" + +#: permissions.py:9 +msgid "Download detached signatures" +msgstr "" + +#: permissions.py:12 +msgid "Document signatures" +msgstr "" + +#: views.py:47 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "" + +#: views.py:54 +msgid "embedded" +msgstr "" + +#: views.py:56 +msgid "detached" +msgstr "" + +#: views.py:61 +#, python-format +msgid "Signature ID: %s" +msgstr "" + +#: views.py:62 +#, python-format +msgid "Signature type: %s" +msgstr "" + +#: views.py:63 +#, python-format +msgid "Key ID: %s" +msgstr "" + +#: views.py:64 +#, python-format +msgid "Timestamp: %s" +msgstr "" + +#: views.py:65 +#, python-format +msgid "Signee: %s" +msgstr "" + +#: views.py:70 +#, python-format +msgid "signature properties for: %s" +msgstr "" + +#: views.py:92 +msgid "Detached signature uploaded successfully." +msgstr "" + +#: views.py:101 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "" diff --git a/apps/document_signatures/locale/it/LC_MESSAGES/django.po b/apps/document_signatures/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..6aaa824359 --- /dev/null +++ b/apps/document_signatures/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,123 @@ +# 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: 2012-01-01 20:14-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:50 +msgid "upload signature" +msgstr "" + +#: __init__.py:51 +msgid "download signature" +msgstr "" + +#: __init__.py:52 +msgid "signatures" +msgstr "" + +#: forms.py:11 +msgid "Signature file" +msgstr "" + +#: models.py:19 +msgid "document version" +msgstr "" + +#: models.py:20 +msgid "signature state" +msgstr "" + +#: models.py:21 +msgid "signature file" +msgstr "" + +#: models.py:26 +msgid "document version signature" +msgstr "" + +#: models.py:27 +msgid "document version signatures" +msgstr "" + +#: permissions.py:7 +msgid "Verify document signatures" +msgstr "" + +#: permissions.py:8 +msgid "Upload detached signatures" +msgstr "" + +#: permissions.py:9 +msgid "Download detached signatures" +msgstr "" + +#: permissions.py:12 +msgid "Document signatures" +msgstr "" + +#: views.py:47 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "" + +#: views.py:54 +msgid "embedded" +msgstr "" + +#: views.py:56 +msgid "detached" +msgstr "" + +#: views.py:61 +#, python-format +msgid "Signature ID: %s" +msgstr "" + +#: views.py:62 +#, python-format +msgid "Signature type: %s" +msgstr "" + +#: views.py:63 +#, python-format +msgid "Key ID: %s" +msgstr "" + +#: views.py:64 +#, python-format +msgid "Timestamp: %s" +msgstr "" + +#: views.py:65 +#, python-format +msgid "Signee: %s" +msgstr "" + +#: views.py:70 +#, python-format +msgid "signature properties for: %s" +msgstr "" + +#: views.py:92 +msgid "Detached signature uploaded successfully." +msgstr "" + +#: views.py:101 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "" diff --git a/apps/document_signatures/locale/pt/LC_MESSAGES/django.po b/apps/document_signatures/locale/pt/LC_MESSAGES/django.po new file mode 100644 index 0000000000..6aaa824359 --- /dev/null +++ b/apps/document_signatures/locale/pt/LC_MESSAGES/django.po @@ -0,0 +1,123 @@ +# 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: 2012-01-01 20:14-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:50 +msgid "upload signature" +msgstr "" + +#: __init__.py:51 +msgid "download signature" +msgstr "" + +#: __init__.py:52 +msgid "signatures" +msgstr "" + +#: forms.py:11 +msgid "Signature file" +msgstr "" + +#: models.py:19 +msgid "document version" +msgstr "" + +#: models.py:20 +msgid "signature state" +msgstr "" + +#: models.py:21 +msgid "signature file" +msgstr "" + +#: models.py:26 +msgid "document version signature" +msgstr "" + +#: models.py:27 +msgid "document version signatures" +msgstr "" + +#: permissions.py:7 +msgid "Verify document signatures" +msgstr "" + +#: permissions.py:8 +msgid "Upload detached signatures" +msgstr "" + +#: permissions.py:9 +msgid "Download detached signatures" +msgstr "" + +#: permissions.py:12 +msgid "Document signatures" +msgstr "" + +#: views.py:47 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "" + +#: views.py:54 +msgid "embedded" +msgstr "" + +#: views.py:56 +msgid "detached" +msgstr "" + +#: views.py:61 +#, python-format +msgid "Signature ID: %s" +msgstr "" + +#: views.py:62 +#, python-format +msgid "Signature type: %s" +msgstr "" + +#: views.py:63 +#, python-format +msgid "Key ID: %s" +msgstr "" + +#: views.py:64 +#, python-format +msgid "Timestamp: %s" +msgstr "" + +#: views.py:65 +#, python-format +msgid "Signee: %s" +msgstr "" + +#: views.py:70 +#, python-format +msgid "signature properties for: %s" +msgstr "" + +#: views.py:92 +msgid "Detached signature uploaded successfully." +msgstr "" + +#: views.py:101 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "" diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000000..c0c6309907 --- /dev/null +++ b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,124 @@ +# 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: 2012-01-01 20:14-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:50 +msgid "upload signature" +msgstr "" + +#: __init__.py:51 +msgid "download signature" +msgstr "" + +#: __init__.py:52 +msgid "signatures" +msgstr "" + +#: forms.py:11 +msgid "Signature file" +msgstr "" + +#: models.py:19 +msgid "document version" +msgstr "" + +#: models.py:20 +msgid "signature state" +msgstr "" + +#: models.py:21 +msgid "signature file" +msgstr "" + +#: models.py:26 +msgid "document version signature" +msgstr "" + +#: models.py:27 +msgid "document version signatures" +msgstr "" + +#: permissions.py:7 +msgid "Verify document signatures" +msgstr "" + +#: permissions.py:8 +msgid "Upload detached signatures" +msgstr "" + +#: permissions.py:9 +msgid "Download detached signatures" +msgstr "" + +#: permissions.py:12 +msgid "Document signatures" +msgstr "" + +#: views.py:47 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "" + +#: views.py:54 +msgid "embedded" +msgstr "" + +#: views.py:56 +msgid "detached" +msgstr "" + +#: views.py:61 +#, python-format +msgid "Signature ID: %s" +msgstr "" + +#: views.py:62 +#, python-format +msgid "Signature type: %s" +msgstr "" + +#: views.py:63 +#, python-format +msgid "Key ID: %s" +msgstr "" + +#: views.py:64 +#, python-format +msgid "Timestamp: %s" +msgstr "" + +#: views.py:65 +#, python-format +msgid "Signee: %s" +msgstr "" + +#: views.py:70 +#, python-format +msgid "signature properties for: %s" +msgstr "" + +#: views.py:92 +msgid "Detached signature uploaded successfully." +msgstr "" + +#: views.py:101 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "" From 8c49bf1aa1ed831821ed586b4895dbc26e3e8399 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:16:35 -0400 Subject: [PATCH 124/484] Add the document signatures app to the translation helper scripts --- misc/compilemessages_all.sh | 6 ++++++ misc/makemessages_all.sh | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index a6abd085c7..b37e263fac 100755 --- a/misc/compilemessages_all.sh +++ b/misc/compilemessages_all.sh @@ -134,3 +134,9 @@ $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es $COMPILEMESSAGES -l it + +cd $BASE/apps/document_signatures +$COMPILEMESSAGES -l pt +$COMPILEMESSAGES -l ru +$COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh index 3cc25f2a01..beba6e7d53 100755 --- a/misc/makemessages_all.sh +++ b/misc/makemessages_all.sh @@ -156,3 +156,10 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it + +cd $BASE/apps/document_signatures +$MAKEMESSAGES -l en +$MAKEMESSAGES -l pt +$MAKEMESSAGES -l ru +$MAKEMESSAGES -l es +$MAKEMESSAGES -l it From 722f70029bd1c385b0236807cf8940101af0282e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:16:55 -0400 Subject: [PATCH 125/484] Add document signatures app to the transifex resource file --- .tx/config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.tx/config b/.tx/config index 0ee87646bb..751a29b59d 100644 --- a/.tx/config +++ b/.tx/config @@ -176,3 +176,11 @@ trans.es = apps/django_gpg/locale/es/LC_MESSAGES/django.po trans.pt = apps/django_gpg/locale/pt/LC_MESSAGES/django.po trans.ru = apps/django_gpg/locale/ru/LC_MESSAGES/django.po trans.it = apps/django_gpg/locale/it/LC_MESSAGES/django.po + +[mayan-edms.apps-document_signatures] +source_file = apps/document_signatures/locale/en/LC_MESSAGES/django.po +source_lang = en +trans.es = apps/document_signatures/locale/es/LC_MESSAGES/django.po +trans.pt = apps/document_signatures/locale/pt/LC_MESSAGES/django.po +trans.ru = apps/document_signatures/locale/ru/LC_MESSAGES/django.po +trans.it = apps/document_signatures/locale/it/LC_MESSAGES/django.po From 6864f1426904dd9c890343cacdae597ab2d19df1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:26:16 -0400 Subject: [PATCH 126/484] PEP8 Cleanups --- apps/document_signatures/__init__.py | 20 +++++++++++--------- apps/document_signatures/managers.py | 26 +++++++++++++------------- apps/document_signatures/models.py | 4 ++-- apps/document_signatures/views.py | 28 +++++++++++----------------- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index f8a60505ac..0a34ed064d 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -4,34 +4,35 @@ import logging try: from cStringIO import StringIO except ImportError: - from StringIO import StringIO + from StringIO import StringIO from django.utils.translation import ugettext_lazy as _ from django.db.models.signals import post_save from documents.models import Document, DocumentVersion -from navigation.api import register_links, register_top_menu, \ - register_model_list_columns, register_multi_item_links, \ - register_sidebar_template +from navigation.api import register_links + from django_gpg.runtime import gpg -from django_gpg.exceptions import GPGDecryptionError +from django_gpg.exceptions import GPGDecryptionError from .models import DocumentVersionSignature from .permissions import ( - PERMISSION_DOCUMENT_VERIFY, + PERMISSION_DOCUMENT_VERIFY, PERMISSION_SIGNATURE_UPLOAD, PERMISSION_SIGNATURE_DOWNLOAD - ) +) logger = logging.getLogger(__name__) def has_embedded_signature(context): return DocumentVersionSignature.objects.has_embedded_signature(context['object']) - + + def doesnt_have_detached_signature(context): return DocumentVersionSignature.objects.has_detached_signature(context['object']) == False + def document_pre_open_hook(descriptor): try: result = gpg.decrypt_file(descriptor, close_descriptor=False) @@ -43,9 +44,10 @@ def document_pre_open_hook(descriptor): else: return StringIO(result.data) + def document_post_save(sender, instance, **kwargs): if kwargs.get('created', False): - DocumentVersionSignature.objects.signature_state(instance.document) + DocumentVersionSignature.objects.signature_state(instance.document) document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index 04980e3094..f4ed8c28f9 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -3,7 +3,7 @@ import logging from django.db import models from django_gpg.runtime import gpg -from django_gpg.exceptions import GPGVerificationError, GPGDecryptionError +from django_gpg.exceptions import GPGVerificationError logger = logging.getLogger(__name__) @@ -33,24 +33,24 @@ class DocumentVersionSignatureManager(models.Manager): document_signature.save() else: raise Exception('document already has an embedded signature') - + def has_detached_signature(self, document): document_signature, created = self.model.objects.get_or_create( document_version=document.latest_version, - ) + ) if document_signature.signature_file: return True else: return False - + def has_embedded_signature(self, document): logger.debug('document: %s' % document) - + if self.signature_state(document): return True else: return False - + def signature_state(self, document): document_signature, created = self.model.objects.get_or_create( document_version=document.latest_version, @@ -65,26 +65,26 @@ class DocumentVersionSignatureManager(models.Manager): except GPGVerificationError: document_signature.signature_state = None finally: - document_signature.save() - + document_signature.save() + #document_signature.signature_state = self.verify_signature(document).status #document_signature.save() - + return document_signature.signature_state - + def detached_signature(self, document): document_signature, created = self.model.objects.get_or_create( document_version=document.latest_version, - ) + ) return document_signature.signature_file.storage.open(document_signature.signature_file.path) - + def verify_signature(self, document): if self.has_detached_signature(document): logger.debug('has detached signature') args = (document.open(raw=True), self.detached_signature(document)) else: args = (document.open(raw=True),) - + try: return gpg.verify_w_retry(*args) except GPGVerificationError: diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 3f2b40c057..0f82666b84 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -19,9 +19,9 @@ class DocumentVersionSignature(models.Model): document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'), editable=False) signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False) signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) - + objects = DocumentVersionSignatureManager() class Meta: verbose_name = _(u'document version signature') - verbose_name_plural = _(u'document version signatures') + verbose_name_plural = _(u'document version signatures') diff --git a/apps/document_signatures/views.py b/apps/document_signatures/views.py index dd83df19be..6c3d51fddf 100644 --- a/apps/document_signatures/views.py +++ b/apps/document_signatures/views.py @@ -8,21 +8,15 @@ 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.safestring import mark_safe from django.conf import settings from django.template.defaultfilters import force_escape from documents.models import Document, RecentDocument from permissions.api import check_permissions -from common.utils import pretty_size, parse_range, urlquote, \ - return_diff, encapsulate from filetransfers.api import serve_file - -from django_gpg.api import Key, SIGNATURE_STATES -from django_gpg.runtime import gpg -from django_gpg.exceptions import (GPGVerificationError, KeyFetchingError, - KeyImportError) + +from django_gpg.api import SIGNATURE_STATES from . import (PERMISSION_DOCUMENT_VERIFY, PERMISSION_SIGNATURE_UPLOAD, PERMISSION_SIGNATURE_DOWNLOAD) @@ -30,18 +24,18 @@ from .forms import DetachedSignatureForm from .models import DocumentVersionSignature logger = logging.getLogger(__name__) - + def document_verify(request, document_pk): check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) - + signature = DocumentVersionSignature.objects.verify_signature(document) signature_state = SIGNATURE_STATES.get(getattr(signature, 'status', None)) - + widget = (u'' % (settings.STATIC_URL, signature_state['icon'])) paragraphs = [ _(u'Signature status: %(widget)s %(text)s') % { @@ -65,21 +59,21 @@ def document_verify(request, document_pk): _(u'Signee: %s') % force_escape(getattr(signature, 'username', u'')), ] ) - + return render_to_response('generic_template.html', { 'title': _(u'signature properties for: %s') % document, 'object': document, 'document': document, 'paragraphs': paragraphs, }, context_instance=RequestContext(request)) - - + + def document_signature_upload(request, document_pk): check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) - + post_action_redirect = None 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', '/'))) @@ -105,8 +99,8 @@ def document_signature_upload(request, document_pk): 'previous': previous, 'object': document, }, context_instance=RequestContext(request)) - - + + def document_signature_download(request, document_pk): check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) document = get_object_or_404(Document, pk=document_pk) From a70b12b488e35674b2c7faf38555f8d03030dcd1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:26:31 -0400 Subject: [PATCH 127/484] Removed remarked code --- apps/django_gpg/__init__.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index a69efbab8e..4d587074da 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -15,9 +15,6 @@ PERMISSION_KEY_VIEW = {'namespace': 'django_gpg', 'name': 'key_view', 'label': _ PERMISSION_KEY_DELETE = {'namespace': 'django_gpg', 'name': 'key_delete', 'label': _(u'Delete keys')} PERMISSION_KEYSERVER_QUERY = {'namespace': 'django_gpg', 'name': 'keyserver_query', 'label': _(u'Query keyservers')} PERMISSION_KEY_RECEIVE = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Import key from keyservers')} -#PERMISSION_DOCUMENT_VERIFY = {'namespace': 'django_gpg', 'name': 'document_verify', 'label': _(u'Verify document signatures')} -#PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'django_gpg', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} -#PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'django_gpg', 'name': 'key_receive', 'label': _(u'Download detached signatures')} # Permission setup set_namespace_title('django_gpg', _(u'Signatures')) @@ -26,16 +23,6 @@ register_permission(PERMISSION_KEY_DELETE) register_permission(PERMISSION_KEYSERVER_QUERY) register_permission(PERMISSION_KEY_RECEIVE) -#register_permission(PERMISSION_DOCUMENT_VERIFY) -#register_permission(PERMISSION_SIGNATURE_UPLOAD) -#register_permission(PERMISSION_SIGNATURE_DOWNLOAD) - -#def has_embedded_signature(context): -# return context['object'].signature_state - -#def doesnt_have_detached_signature(context): -# return context['object'].has_detached_signature() == False - # Setup views private_keys = {'text': _(u'private keys'), 'view': 'key_private_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} public_keys = {'text': _(u'public keys'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} @@ -44,15 +31,6 @@ key_query = {'text': _(u'query keyservers'), 'view': 'key_query', 'famfam': 'zoo key_receive = {'text': _(u'import'), 'view': 'key_receive', 'args': 'object.keyid', 'famfam': 'key_add', 'keep_query': True, 'permissions': [PERMISSION_KEY_RECEIVE]} key_setup = {'text': _(u'key management'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} -# Document views -#document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} -#document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} -#document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} - -#register_links(Document, [document_verify], menu_name='form_header') -#register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') - - #register_links(['key_delete', 'key_private_list', 'key_public_list', 'key_query'], [private_keys, public_keys, key_query], menu_name='sidebar') register_links(['key_delete', 'key_public_list', 'key_query'], [public_keys, key_query], menu_name='sidebar') From d54ec02b83c4a3e3ade211c65c3ffbbb5d6915c4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:39:41 -0400 Subject: [PATCH 128/484] Add schema and data migrations for the new document signatures app --- .../migrations/0001_initial.py | 140 +++++++++++++++++ .../0002_move_signatures_to_new_app.py | 145 ++++++++++++++++++ .../migrations/__init__.py | 0 3 files changed, 285 insertions(+) create mode 100644 apps/document_signatures/migrations/0001_initial.py create mode 100644 apps/document_signatures/migrations/0002_move_signatures_to_new_app.py create mode 100644 apps/document_signatures/migrations/__init__.py diff --git a/apps/document_signatures/migrations/0001_initial.py b/apps/document_signatures/migrations/0001_initial.py new file mode 100644 index 0000000000..17f930aa40 --- /dev/null +++ b/apps/document_signatures/migrations/0001_initial.py @@ -0,0 +1,140 @@ +# 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 'DocumentVersionSignature' + db.create_table('document_signatures_documentversionsignature', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('document_version', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.DocumentVersion'])), + ('signature_state', self.gf('django.db.models.fields.CharField')(max_length=16, null=True, blank=True)), + ('signature_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True, blank=True)), + )) + db.send_create_signal('document_signatures', ['DocumentVersionSignature']) + + + def backwards(self, orm): + + # Deleting model 'DocumentVersionSignature' + db.delete_table('document_signatures_documentversionsignature') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_signatures.documentversionsignature': { + 'Meta': {'object_name': 'DocumentVersionSignature'}, + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'signature_state': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'signature_state': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_signatures'] diff --git a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py new file mode 100644 index 0000000000..2fef743da0 --- /dev/null +++ b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py @@ -0,0 +1,145 @@ +# 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 document_version in orm.DocumentVersion.objects.all(): + if document_version.signature_state or document_version.signature_file: + document_signature = orm.DocumentVersionSignature( + document_version=document_version, + signature_state=document_version.signature_state, + signature_file=document_version.signature_file, + ) + document_signature.save() + + + def backwards(self, orm): + for document_signature in orm.DocumentVersionSignature.objects.all(): + try: + document_version = orm.DocumentVersion.objects.get(document_version=document_version) + except orm.DocumentVersion.DoesNotExists: + pass + else: + document_version.signature_state=document_signature.signature_state + document_version.signature_file=document_signature.signature_file + document_version.save() + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_signatures.documentversionsignature': { + 'Meta': {'object_name': 'DocumentVersionSignature'}, + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'signature_state': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'signature_state': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_signatures'] diff --git a/apps/document_signatures/migrations/__init__.py b/apps/document_signatures/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 1c0a52c93198840d2fa2d52903611bb783f0d52b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 1 Jan 2012 20:50:46 -0400 Subject: [PATCH 129/484] Update document signatures app to use the new class based permissions --- apps/document_signatures/permissions.py | 13 +++++-------- apps/document_signatures/views.py | 9 +++++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/document_signatures/permissions.py b/apps/document_signatures/permissions.py index 9bbfdfece8..8575d4c80c 100644 --- a/apps/document_signatures/permissions.py +++ b/apps/document_signatures/permissions.py @@ -3,13 +3,10 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from permissions.api import register_permission, set_namespace_title +from permissions.models import PermissionNamespace, Permission -PERMISSION_DOCUMENT_VERIFY = {'namespace': 'document_signatures', 'name': 'document_verify', 'label': _(u'Verify document signatures')} -PERMISSION_SIGNATURE_UPLOAD = {'namespace': 'document_signatures', 'name': 'signature_upload', 'label': _(u'Upload detached signatures')} -PERMISSION_SIGNATURE_DOWNLOAD = {'namespace': 'document_signatures', 'name': 'key_receive', 'label': _(u'Download detached signatures')} +document_signatures_namespace = PermissionNamespace('document_signatures', _(u'Document signatures')) -# Permission setup -set_namespace_title('document_signatures', _(u'Document signatures')) -register_permission(PERMISSION_DOCUMENT_VERIFY) -register_permission(PERMISSION_SIGNATURE_UPLOAD) -register_permission(PERMISSION_SIGNATURE_DOWNLOAD) +PERMISSION_DOCUMENT_VERIFY = Permission.objects.register(document_signatures_namespace, 'document_verify', _(u'Verify document signatures')) +PERMISSION_SIGNATURE_UPLOAD = Permission.objects.register(document_signatures_namespace, 'signature_upload', _(u'Upload detached signatures')) +PERMISSION_SIGNATURE_DOWNLOAD = Permission.objects.register(document_signatures_namespace, 'signature_download', _(u'Download detached signatures')) diff --git a/apps/document_signatures/views.py b/apps/document_signatures/views.py index 6c3d51fddf..b69f7aba38 100644 --- a/apps/document_signatures/views.py +++ b/apps/document_signatures/views.py @@ -13,7 +13,7 @@ from django.conf import settings from django.template.defaultfilters import force_escape from documents.models import Document, RecentDocument -from permissions.api import check_permissions +from permissions.models import Permission from filetransfers.api import serve_file from django_gpg.api import SIGNATURE_STATES @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) def document_verify(request, document_pk): - check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) @@ -69,7 +69,8 @@ def document_verify(request, document_pk): def document_signature_upload(request, document_pk): - check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) + Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) + document = get_object_or_404(Document, pk=document_pk) RecentDocument.objects.add_document_for_user(request.user, document) @@ -102,7 +103,7 @@ def document_signature_upload(request, document_pk): def document_signature_download(request, document_pk): - check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) + Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) document = get_object_or_404(Document, pk=document_pk) try: From 2781a211ec1a6f7bc340bf5cad0c9a0166101fe2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 01:47:14 -0400 Subject: [PATCH 130/484] Language translation updates --- .../locale/pt/LC_MESSAGES/django.mo | Bin 485 -> 2445 bytes .../locale/pt/LC_MESSAGES/django.po | 88 +++++++++--------- .../locale/es/LC_MESSAGES/django.mo | Bin 0 -> 1920 bytes .../locale/es/LC_MESSAGES/django.po | 54 +++++------ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 1568 bytes .../locale/it/LC_MESSAGES/django.po | 44 ++++----- .../locale/pt/LC_MESSAGES/django.mo | Bin 0 -> 2002 bytes .../locale/pt/LC_MESSAGES/django.po | 54 +++++------ .../locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 1679 bytes .../locale/ru/LC_MESSAGES/django.po | 41 ++++---- apps/linking/locale/pt/LC_MESSAGES/django.mo | Bin 3013 -> 4333 bytes apps/linking/locale/pt/LC_MESSAGES/django.po | 87 +++++++---------- apps/main/locale/es/LC_MESSAGES/django.mo | Bin 2727 -> 2759 bytes apps/main/locale/es/LC_MESSAGES/django.po | 26 +++--- apps/main/locale/it/LC_MESSAGES/django.mo | Bin 2531 -> 2538 bytes apps/main/locale/it/LC_MESSAGES/django.po | 24 +++-- apps/main/locale/pt/LC_MESSAGES/django.mo | Bin 2525 -> 2579 bytes apps/main/locale/pt/LC_MESSAGES/django.po | 39 ++++---- apps/main/locale/ru/LC_MESSAGES/django.mo | Bin 3157 -> 3227 bytes apps/main/locale/ru/LC_MESSAGES/django.po | 42 +++++---- 20 files changed, 245 insertions(+), 254 deletions(-) create mode 100644 apps/document_signatures/locale/es/LC_MESSAGES/django.mo create mode 100644 apps/document_signatures/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/document_signatures/locale/pt/LC_MESSAGES/django.mo create mode 100644 apps/document_signatures/locale/ru/LC_MESSAGES/django.mo diff --git a/apps/django_gpg/locale/pt/LC_MESSAGES/django.mo b/apps/django_gpg/locale/pt/LC_MESSAGES/django.mo index 9aea042e15ed1726fc95360f0144fddecdfc5543..cbde9b3dc3c2f39bd3e52295c558bb4949d69968 100644 GIT binary patch literal 2445 zcmZvcJ8T?97{@0N9yth)#6SWhOaex>?7fFcOt@f(^14E_V21n+?lfyWLO^C!WlFdi*A4MK#yQ?6ew=NCcp*#}AgXW$Fq7vLfACU_XU z4U)Yd!AHSgO8y2uiSb>K{QVmwxqIN_AUQ>G9R_LrI7oI*fe>Mn<$MGD9XWdgtYiKt zgvtLFNPe$?7yJ0RKr6MPB$7bHC+2!i4`jXyfC z3Gf8?E=cy)L5Q+V@F-|NI+ssD(svVl1^fXdeRsj9!M{M-cL2$wI1hoCVk02MbD|tq zLDKU&Nco#9*Ox%r7nJK7q&$5LQa-PNNYid3TXg=^ju*)FQJ2n<8pn4U-!u3q7K#&U za(|D2lrL(}7RddgE}i4Ca*jZ8Qm!Z-YUS0=`;^<~@R6_i`GVvx#r!fpYLqX^E!|%n zbAImtHbQ^1M)GZ)ahsK$p0XROLjyC={`X*nEr4?^@i`7kV&(hM^Y#mP7IVTB9tZR8|m26 zAV4mS(Wbg*!a785VRo#if>63~i>{Mf=nSPSTS>%PB=^lBTUD}`N5f!DIHeOF2q#$) z1q+m=y#bT)nhXN!Y^BQV5zNP!k7N?M4VD_!#r{HNnulBTjkHGZt?8>+y&n1$9`)=j?QT-vPFLghBH zwW_bLBw;2(=`BkUH+csUW+D8Qe5{PD*XvasnNjO9SWlkp!SKnJkx|^J?M=gznO3rhCLl`UF%*yg5@7z$1 z?5#`VwG&?lDhZqX+?sN`-ZpvaDxD}ZBJwV26XOCVX+E?wQ|Ecnof%8`sTtlFudr3^ z_rHbRnEObP+!6evOyZeXxhcw5Ee!e6g?sd@XRTHFn-<(;DlQ&&d&`e9Rm!pZM#JZ= zdD8z{bCD|uG)Eo56YpQg8z0P~RER43-zy(@P`>oR5N>jMlh}_7OrzXSi}HYXQViJK z!1YNkQV|N+!tqi8!28!#y4rXa()F+7X0lHIHWdNQa4z&DU}|7tkN&~p?%I9Ui}DZ} z8EDoaiD9lSd!KUG|Awd9+WvQ48SQgA4385^2Wdd95V_Yz ziT(}jM}5f8iQ#-vCAuOIR68<<46=cAUUWqu%VL5RF#rGn delta 121 zcmeAbe#&fdPl#nI0}wC*u?!Ha05LNV>i{tbSOD>Aprj>`2C0F8$rh|;lc%!U^BU?J z8tEFCDj1qunHW!g$STfJlwX`!l$l>NnVqeQ$0so_y)-dB)k>kDWO4&r^yC+8+5ipu B7lZ%+ diff --git a/apps/django_gpg/locale/pt/LC_MESSAGES/django.po b/apps/django_gpg/locale/pt/LC_MESSAGES/django.po index 7b89397c22..cfdd02ef9f 100644 --- a/apps/django_gpg/locale/pt/LC_MESSAGES/django.po +++ b/apps/django_gpg/locale/pt/LC_MESSAGES/django.po @@ -1,21 +1,21 @@ # 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" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "POT-Creation-Date: 2011-12-06 02:06-0400\n" -"PO-Revision-Date: 2011-12-05 17:43+0000\n" -"Last-Translator: rosarior \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\n" +"PO-Revision-Date: 2012-01-02 05:34+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 @@ -24,19 +24,19 @@ msgstr "" #: __init__.py:15 msgid "View keys" -msgstr "" +msgstr "Ver as chaves" #: __init__.py:16 msgid "Delete keys" -msgstr "" +msgstr "Excluir chaves" #: __init__.py:17 msgid "Query keyservers" -msgstr "" +msgstr "Consulta servidores de chaves" #: __init__.py:18 msgid "Import key from keyservers" -msgstr "" +msgstr "Importar chave de servidores de chaves" #: __init__.py:19 msgid "Upload detached signatures" @@ -48,19 +48,19 @@ msgstr "" #: __init__.py:23 msgid "Signatures" -msgstr "" +msgstr "Assinaturas" #: __init__.py:39 views.py:67 msgid "private keys" -msgstr "" +msgstr "chaves privadas" #: __init__.py:40 views.py:70 msgid "public keys" -msgstr "" +msgstr "chaves públicas" #: __init__.py:41 msgid "delete" -msgstr "" +msgstr "excluir" #: __init__.py:42 msgid "query keyservers" @@ -84,39 +84,39 @@ msgstr "" #: __init__.py:49 msgid "signatures" -msgstr "" +msgstr "assinaturas" #: api.py:22 msgid "Public" -msgstr "" +msgstr "Público" #: api.py:23 msgid "Secret" -msgstr "" +msgstr "Segredo" #: api.py:31 api.py:36 msgid "RSA" -msgstr "" +msgstr "RSA" #: api.py:32 msgid "DSA" -msgstr "" +msgstr "DSA" #: api.py:37 msgid "Elgamal" -msgstr "" +msgstr "Elgamal" #: api.py:51 msgid "Bad signature." -msgstr "" +msgstr "Assinatura ruim." #: api.py:55 msgid "Document not signed or invalid signature." -msgstr "" +msgstr "Documento não assinado ou inválido assinatura." #: api.py:59 msgid "Signature error." -msgstr "" +msgstr "Erro de assinatura." #: api.py:63 msgid "Document is signed but no public key is available for verification." @@ -132,7 +132,7 @@ msgstr "" #: api.py:144 msgid "unknown" -msgstr "" +msgstr "desconhecido" #: forms.py:11 msgid "Term" @@ -154,33 +154,33 @@ msgstr "" #: views.py:48 #, python-format msgid "Unable to import key id: %s" -msgstr "" +msgstr "Não é possível importar chave: %s" #: views.py:52 msgid "Import key" -msgstr "" +msgstr "Importar chave" #: views.py:53 #, python-format msgid "Are you sure you wish to import key id: %s?" -msgstr "" +msgstr "Você tem certeza que deseja importar chave: %s?" #: views.py:78 msgid "Key ID" -msgstr "" +msgstr "ID da chave" #: views.py:82 msgid "Owner" -msgstr "" +msgstr "Proprietário" #: views.py:102 #, python-format msgid "Key: %s, deleted successfully." -msgstr "" +msgstr "Chave: %s, apagado com sucesso." #: views.py:109 msgid "Delete key" -msgstr "" +msgstr "Excluir chave" #: views.py:111 #, python-format @@ -192,39 +192,39 @@ msgstr "" #: views.py:129 msgid "Query key server" -msgstr "" +msgstr "Consultar servidor de chaves" #: views.py:142 msgid "results" -msgstr "" +msgstr "resultados" #: views.py:147 msgid "ID" -msgstr "" +msgstr "ID" #: views.py:151 msgid "type" -msgstr "" +msgstr "tipo" #: views.py:155 msgid "creation date" -msgstr "" +msgstr "data de criação" #: views.py:159 msgid "disabled" -msgstr "" +msgstr "desativada" #: views.py:163 msgid "expiration date" -msgstr "" +msgstr "data de validade" #: views.py:167 msgid "expired" -msgstr "" +msgstr "expirado" #: views.py:171 msgid "length" -msgstr "" +msgstr "comprimento" #: views.py:175 msgid "revoked" @@ -237,11 +237,11 @@ msgstr "" #: views.py:205 #, python-format msgid "Signature status: %(widget)s %(text)s" -msgstr "" +msgstr "Status da assinatura: %(widget)s %(text)s" #: views.py:212 msgid "embedded" -msgstr "" +msgstr "embutido" #: views.py:214 msgid "detached" @@ -289,3 +289,5 @@ msgstr "" #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." msgstr "" + + diff --git a/apps/document_signatures/locale/es/LC_MESSAGES/django.mo b/apps/document_signatures/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a1ea5d8bfc37c6c5e11dab0de8e70f53bbf16e4d GIT binary patch literal 1920 zcmaKsO>f*p7{{kjDBVI^+EQpi)%1|QsB*fgDk$4h#blkb>TWjLY$Dp*#GZ8qytbK{ zO&Ts-kvMZe;!H277cQJZz$f6qr6(jV^dlhgf5u)r+eCe|_Rll(%=0?4Pfs2GmO;+p zc@NLuc;@i@cnB}Z;!BKO1%2=|_&G>=Ux5wqd+;Rq7(5RC4ATBTz*FEeko4HgjJ*LI z122N-!1Lhkk{jS_7=Hnhy)Vo8Z@_mk{sAO=zksCoCrJLDf)vj)@C4X6T=+W=lASql z5xKk%lHZ+I7&`-g2fhtH0m<&~CI13x-@o8x@IUZPaPC#cUI#w_sSa(B;`+24TkrzL zUxWCu$9SCupMd1|H}Dep4@hwyKf>5i@B&Ewu7Di;5Ttk>f>32+@EB-8q~UzO1=3y; zvPD9^pyC7}yBd{4hSZ%68dERGKIKkAeWyC2O-@ioCzLA*#YS;Z&8UA=3zByVpb*lE za7#wqs5ljNq9vc?NhTtinuMV=W;98X-Feo|!pT^sw$?P5+et~8NBhhec3yM=X^!~t>f zQKnz4Vc3S$YP8Fv12Uc_%Bsa}sg26geG_$^Ua(}aR+g}80F&cQ8KD8Jn&PfX^)T02 zF11zCRO!@FpE?gxA?71Wh?I}0$WykEV#&pwi4H5Q$>QyN6KbK z&=ryMg@(cTask%uP zpwp2XW9wA!fO|7kdA-Y-S|<01(+zq;hk~r)JdJZSnJz4HDx;jHiDbp|YgGpB#wa8= z&1^RDqEgIVm0y2K;Vh}^!d&QO1@@>sui>hhplVYcoc>ui(QJL0LW;2#kzh!1wsv%b cl#K8{SDGyX=T(;UUou, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,112 +12,112 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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" +"Language: \n" #: __init__.py:50 msgid "upload signature" -msgstr "" +msgstr "subir firma" #: __init__.py:51 msgid "download signature" -msgstr "" +msgstr "descargar firma" #: __init__.py:52 msgid "signatures" -msgstr "" +msgstr "firmas" #: forms.py:11 msgid "Signature file" -msgstr "" +msgstr "Archivo de firma" #: models.py:19 msgid "document version" -msgstr "" +msgstr "versión del documento" #: models.py:20 msgid "signature state" -msgstr "" +msgstr "estado de la firma" #: models.py:21 msgid "signature file" -msgstr "" +msgstr "archivo de firma" #: models.py:26 msgid "document version signature" -msgstr "" +msgstr "firma de la versión de documento" #: models.py:27 msgid "document version signatures" -msgstr "" +msgstr "firmas de las versiónes de documentos" #: permissions.py:7 msgid "Verify document signatures" -msgstr "" +msgstr "Verificar firmas de documentos" #: permissions.py:8 msgid "Upload detached signatures" -msgstr "" +msgstr "Subir firmas aparte" #: permissions.py:9 msgid "Download detached signatures" -msgstr "" +msgstr "Descargar firmas aparte" #: permissions.py:12 msgid "Document signatures" -msgstr "" +msgstr "Firmas de documentos" #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" -msgstr "" +msgstr "Estado de la firma: %(widget)s %(text)s" #: views.py:54 msgid "embedded" -msgstr "" +msgstr "integrada" #: views.py:56 msgid "detached" -msgstr "" +msgstr "aparte" #: views.py:61 #, python-format msgid "Signature ID: %s" -msgstr "" +msgstr "ID de la firma: %s" #: views.py:62 #, python-format msgid "Signature type: %s" -msgstr "" +msgstr "Tipo de firma: %s" #: views.py:63 #, python-format msgid "Key ID: %s" -msgstr "" +msgstr "ID de la llave: %s" #: views.py:64 #, python-format msgid "Timestamp: %s" -msgstr "" +msgstr "Marca de tiempo: %s" #: views.py:65 #, python-format msgid "Signee: %s" -msgstr "" +msgstr "Firmante: %s" #: views.py:70 #, python-format msgid "signature properties for: %s" -msgstr "" +msgstr "propiedades de la firma para: %s" #: views.py:92 msgid "Detached signature uploaded successfully." -msgstr "" +msgstr "Firma aparte subida exitosamente." #: views.py:101 #, python-format msgid "Upload detached signature for: %s" -msgstr "" +msgstr "Subir firma aparte para: %s" + diff --git a/apps/document_signatures/locale/it/LC_MESSAGES/django.mo b/apps/document_signatures/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..dac760626fb3d11073e7722d8cfa25833fc1ad93 GIT binary patch literal 1568 zcmaKr-)lok~=2G2I<+rdsc; zX2va%5Vt%*FAz7p1w!JA_5q*|kS73fSE=HL?~LPhq=t?>{_X6XIp;fP&h9Ure9AB` zVt$DE8|FutUmwFC#vkBy@K2ET{{>fY6_EU`gA}&|Za~We@KdaRI?31v;O`*C+XvqP z{{qSW6?hG7yv5jga1|tfF-Z1(kb~cVr0;w1WAI0i?0yBw?m2iCd;yZ*eURe*1LDWd zo|@@C4?Xi%PXc0OPlYDnw%Fd;S6gmh9&x|<7_C=GiXGsFRDoWVp179&<( zrn@TRPUofcQ>*y2DvZqN)ih0&bK_}I>@Bm{JSk~|XRjS`?4H`=ow&uXIyS5wz4l_P z3w3DUc?5Jg^w|@g<;q`oc=YO9JRGv}dzGpktJ&j7PZUm1s<5#W1RtS`kBxn^g=6=X z)#E*$nRGf)rC-#+v3a5_o2OnEiK)p$m7z$ie#Jv}i)Cd^rL5P=)iUZ$$7V%dL}T05 zJW{C_olHQI)23|k?Wlb(x|8tx$za&&Z#4$0GS-Wp%XKEcoaRo9Op7a>UBPU(BDcLUFp0S zSy{S5dMe@OPPfaqqF%ypC%vfC-H76NkPL_GFfH?`%#|1^Icf23v~_2PB;W3KHwwLM zY`)&;b$ZDnsg>nsqisr$VvA9@Te|WaRUvhGi>JHNI_1CE8EuN23p>&>R#qfsYBF8s zEq?Q%_H}d=fo*C#k=&&+n|jG*o@-;#(UPa8oVT)BX2Vokol4x6oha^9B`u8T>J@A6 zYWY~r8@Utn;4^g4CR!IARur?7k_|)i9)1P8BN}<6E5kD#;>qA@h!5n*K8_ZeN!=nD z^ieq3{(tGAjVZ6WKvGtBwPBgY_mZZ#PKFZI6_8A$q84pMJJi94Goq%ftXBTn&m0, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,27 +12,26 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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" +"Language: \n" #: __init__.py:50 msgid "upload signature" -msgstr "" +msgstr "aggiorna firma" #: __init__.py:51 msgid "download signature" -msgstr "" +msgstr "scarica firma" #: __init__.py:52 msgid "signatures" -msgstr "" +msgstr "firma" #: forms.py:11 msgid "Signature file" -msgstr "" +msgstr "File della firma" #: models.py:19 msgid "document version" @@ -44,7 +43,7 @@ msgstr "" #: models.py:21 msgid "signature file" -msgstr "" +msgstr "file della firma" #: models.py:26 msgid "document version signature" @@ -56,15 +55,15 @@ msgstr "" #: permissions.py:7 msgid "Verify document signatures" -msgstr "" +msgstr "Verifica la firma del documento" #: permissions.py:8 msgid "Upload detached signatures" -msgstr "" +msgstr "Carica firme separatamente" #: permissions.py:9 msgid "Download detached signatures" -msgstr "" +msgstr "Scarica firme separatamente" #: permissions.py:12 msgid "Document signatures" @@ -73,51 +72,52 @@ msgstr "" #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" -msgstr "" +msgstr "Status della firma: %(widget)s %(text)s" #: views.py:54 msgid "embedded" -msgstr "" +msgstr "incorporato" #: views.py:56 msgid "detached" -msgstr "" +msgstr "distaccato" #: views.py:61 #, python-format msgid "Signature ID: %s" -msgstr "" +msgstr "ID Firma: %s" #: views.py:62 #, python-format msgid "Signature type: %s" -msgstr "" +msgstr "Tipo di firma: %s" #: views.py:63 #, python-format msgid "Key ID: %s" -msgstr "" +msgstr "Chiave ID: %s" #: views.py:64 #, python-format msgid "Timestamp: %s" -msgstr "" +msgstr "Timestamp: %s" #: views.py:65 #, python-format msgid "Signee: %s" -msgstr "" +msgstr "Signee: %s" #: views.py:70 #, python-format msgid "signature properties for: %s" -msgstr "" +msgstr "Proprietà per la firma: %s" #: views.py:92 msgid "Detached signature uploaded successfully." -msgstr "" +msgstr "Firma scaduta aggiornata con successo." #: views.py:101 #, python-format msgid "Upload detached signature for: %s" -msgstr "" +msgstr "Aggiornata firma scaduta per: %s" + diff --git a/apps/document_signatures/locale/pt/LC_MESSAGES/django.mo b/apps/document_signatures/locale/pt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d2c545543e992fcd36bfeb5b1608d23686098858 GIT binary patch literal 2002 zcmai!&u<$=6vqczXmR<`ru=FFG5ko?s+!gD-+VgS7t-Z~=S> zk{&z6*bBfh@E!0JcpAJsn3P^EuL5ky3 z@C-NvIr!C7{t0{z^55Xg;6LEI;D6xz;9Ex~_O5~y$4!vV+XmkQ?}D`N9(WA=aVq}` zQc0)=q)%tiAm3?_k5F*~t~=XPks)+vi)4y{^7tAF7*u!4Bg*6k(&)zXQ&JA$y7P(R zrX10DeFDbnDwV-46>_Twkxa8h@hl!18PZf11j^ceHXQCQvAPMek&4nn(_(HXB4r-# zF=N>cwaXjz8eg=mn;YLV(bq#&TDK{ju-J5VM~4HIp0oH&)m?m)w9?&J<%ZSdv!_Q2 zyGOBG*mObc;}`FnIx03vDq41+Lvb}5SkW^zUfF2(#9E?cicO-9gKGRjb@_s*F5|&xZTX_8UaVH3 zC^~Aa$@o<7rtft`t1apt|F~UiHO_z1UiT|aX;aZlWMqdjrP5s6Y&QA2*Yf#_-|`yG zRj*#}_}%Ums78ZK4wUFAIjZrdw|;$-TwZB5SBHAZB!erJR-@$?K`k#;D{Cf7acxD< z-5I({AH+kcqsu(FB@?UCk2ZVP#HB)yeCex1_)%a&9Sv&y(zZ_X(~$(`S*u;QNN!au z6B!z=qOm3hW<;HX#xYAJMT@)0XP3s5T1V!#NCm|UWGF3b)Oje$#qs2NLoPJk1@@9V znI0RmTdc6IYarTNOhSF1cIxT)iOtSz7rlCLOO-6o!k3(~FyB`twYkV#cj-VTP, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,112 +12,112 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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" +"Language: \n" #: __init__.py:50 msgid "upload signature" -msgstr "" +msgstr "upload do assinatura" #: __init__.py:51 msgid "download signature" -msgstr "" +msgstr "download do assinatura" #: __init__.py:52 msgid "signatures" -msgstr "" +msgstr "assinaturas" #: forms.py:11 msgid "Signature file" -msgstr "" +msgstr "Arquivo de assinatura" #: models.py:19 msgid "document version" -msgstr "" +msgstr "versão do documento" #: models.py:20 msgid "signature state" -msgstr "" +msgstr "estado do assinatura" #: models.py:21 msgid "signature file" -msgstr "" +msgstr "arquivo do assinatura" #: models.py:26 msgid "document version signature" -msgstr "" +msgstr "assinatura do versão do documento" #: models.py:27 msgid "document version signatures" -msgstr "" +msgstr "assinaturas de versão de documentos" #: permissions.py:7 msgid "Verify document signatures" -msgstr "" +msgstr "Verificar as assinaturas de documentos" #: permissions.py:8 msgid "Upload detached signatures" -msgstr "" +msgstr "Upload de assinaturas destacadas" #: permissions.py:9 msgid "Download detached signatures" -msgstr "" +msgstr "Download assinaturas destacadas" #: permissions.py:12 msgid "Document signatures" -msgstr "" +msgstr "Assinaturas de documentos" #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" -msgstr "" +msgstr "Status da assinatura: %(widget)s %(text)s" #: views.py:54 msgid "embedded" -msgstr "" +msgstr "embutido" #: views.py:56 msgid "detached" -msgstr "" +msgstr "destacado" #: views.py:61 #, python-format msgid "Signature ID: %s" -msgstr "" +msgstr "ID assinatura: %s" #: views.py:62 #, python-format msgid "Signature type: %s" -msgstr "" +msgstr "Tipo de assinatura: %s" #: views.py:63 #, python-format msgid "Key ID: %s" -msgstr "" +msgstr "ID da chave: %s" #: views.py:64 #, python-format msgid "Timestamp: %s" -msgstr "" +msgstr "Timestamp: %s" #: views.py:65 #, python-format msgid "Signee: %s" -msgstr "" +msgstr "Signee: %s" #: views.py:70 #, python-format msgid "signature properties for: %s" -msgstr "" +msgstr "propriedades da assinatura para: %s" #: views.py:92 msgid "Detached signature uploaded successfully." -msgstr "" +msgstr "Assinatura separado enviado com sucesso." #: views.py:101 #, python-format msgid "Upload detached signature for: %s" -msgstr "" +msgstr "Upload de assinatura separada para: %s" + diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.mo b/apps/document_signatures/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d0393e9f05a4ac3b6ee719e2404b1d02a4e2f9f4 GIT binary patch literal 1679 zcmaiz%Wo4$9LI<9XfdTcq*ApiVmP1@!K4lf2)St*6ED=ojw8oGg%gW+Y__s@t(`G6 zJ&_;;5)}v}#I2}Rk3}+3f}DgTCvF^O51f#C>>t3PJt6V^*^VD1qGOLg^Z32Kzg_>m zcgq8Yu^018%)c=AV-9V?4@M2_1D}8q@D;cl{0IC5{0}??Zu_7a<0wdW-+?>9AHaj) zkKh;JFD*U*Kf=BSQtpM;{sl;NyaXxEYmoB20Y@n3X2yR(h%;+ks_snRCk$-sMW;VzN;ach*;1@PqeTD0WT;ZefZ$e!g0kp6*ChY%L&j z{Hq?x?p!iiz9b#=fpuC_3H*u-v?~=~%iF$Gtl7A(2;+hOlgw+8bOdTpuJ6V8czpD1 z{EWrVS=otXW-OAG6+h4-t%|NAPF0Iad5jD^s zjg0!9Mt4Q7@i6Hbe_biruJ;YkU$z4!^|zC`)8b^uj%q2$Kv-VhcU-R+<0mh|;{vlQMl%lOp7yWFgr6&$XbdN>{a%FS$e+brSeDePd;&yopl7U6OyylHBU zm%}{jacRA^=1)^I3udV&qNy|UJF?coneciz{mvbtZSW?WKTO@Mt~XVzJ28?io0Vog zr0bcP$M2%4k%Vg~9tW_fH!beBRn<`mWUj!ts}(5jPESU%nS<)P^ba-v>weqJ_qdbp zM<`>(%%ZMqXl^6xJH4L6{bG2%St<&uvEI5^I8BPE@f-Lvv)YI}jVSXdwr-Z`xsuZ? bju!AdXRty;y3(3@x2~QG*7fW+s+YY5-63;h literal 0 HcmV?d00001 diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po index c0c6309907..feb24e1186 100644 --- a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ # 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 "" @@ -12,28 +12,26 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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: \n" #: __init__.py:50 msgid "upload signature" -msgstr "" +msgstr "выложить подпись" #: __init__.py:51 msgid "download signature" -msgstr "" +msgstr "скачать подпись" #: __init__.py:52 msgid "signatures" -msgstr "" +msgstr "подписи" #: forms.py:11 msgid "Signature file" -msgstr "" +msgstr "Файл подписи" #: models.py:19 msgid "document version" @@ -57,11 +55,11 @@ msgstr "" #: permissions.py:7 msgid "Verify document signatures" -msgstr "" +msgstr "Проверить подпись документа" #: permissions.py:8 msgid "Upload detached signatures" -msgstr "" +msgstr "Выложить отделённые подписи" #: permissions.py:9 msgid "Download detached signatures" @@ -74,51 +72,52 @@ msgstr "" #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" -msgstr "" +msgstr "Статус подписи: %(widget)s %(text)s" #: views.py:54 msgid "embedded" -msgstr "" +msgstr "присоединён" #: views.py:56 msgid "detached" -msgstr "" +msgstr "отделён" #: views.py:61 #, python-format msgid "Signature ID: %s" -msgstr "" +msgstr "Подпись ID: %s" #: views.py:62 #, python-format msgid "Signature type: %s" -msgstr "" +msgstr "Тип подписи: %s" #: views.py:63 #, python-format msgid "Key ID: %s" -msgstr "" +msgstr "ID ключа: %s" #: views.py:64 #, python-format msgid "Timestamp: %s" -msgstr "" +msgstr "Отметка времени: %s" #: views.py:65 #, python-format msgid "Signee: %s" -msgstr "" +msgstr "Подписано: %s" #: views.py:70 #, python-format msgid "signature properties for: %s" -msgstr "" +msgstr "свойства подписи для %s" #: views.py:92 msgid "Detached signature uploaded successfully." -msgstr "" +msgstr "Отделённая подпись выложена." #: views.py:101 #, python-format msgid "Upload detached signature for: %s" -msgstr "" +msgstr "Выложить отделённую подпись для %s" + diff --git a/apps/linking/locale/pt/LC_MESSAGES/django.mo b/apps/linking/locale/pt/LC_MESSAGES/django.mo index b9625e54787339d3ed304b53db5515c6a3a195a0..86f916301e326e5dd5af66a241ebf710a493c7f9 100644 GIT binary patch literal 4333 zcmaKuO^h5z6@UvcU>0zQArK&eiiwFg_WbO!iL8ljaO@3Oc;m%h=YWK=wbQk;jk~)h zUDe~COAxY95FohZfH)w7k|>9OMBoA(5EBszaR_iB2Yf){0E)zg8$#lH-90nC$t05r_^!yP55E>TX+z@4nGLrfFFSB zok|@7cS4z8f&8g2@bfPCIJ_TThVO+p;4%0O_$&A_ya^qPKMMa1#e@UzR_Z_U$5UkU(f#p%D(*uikw%W$oUf#J-6%m|3c04eu66N7U8{c1xlPR@*{EEg5uW* zil0xzHv9pUy!btob$@~4=NnM=b05JMJMM*&H}^x?r$s3FaSY1(N1@35GL*a@K@GnT z#qM81vHN#W;_!DUarzK<8D}`T*gCb${Xjh-c8E_>lSjD^bBivymMWCBQxD6$6JNv* z(fuGd>dH9Z2j!C5!^N_OCGRB$avkB8dX`J}NiOkQ_Db?Vd=>lUlK9D`%ik)$B~}t2 ziS^`?ypvc-9ZL-4l3bN*g}ciwHPGQ+{uPAW?=QU%k_4VB-+O} ztRBVos&?Du`|UXQK@VBfR%dc+g4G#seQNTclQ_HL)mfWZrkhi%Q5+f*J$=}#H_dr< zE*sfA_)<;c262C)(+zEIg3H_Lai>i`#MtUl(hoLjt95Mg>QecvE=}za9lBpy7-?Vh z`__AL>3X}d$g2(UIqN5d7pbw=@gQ@#jmi*6Kq`mhVAD2>SzxaXb7aZ#t1%(kvf7SJ zQV@zrn}LZl0wiDdi#)d(e%Gez$n}eqnYPxVcJioG8%$(^5%p$d;>2tvRvWKJCXZ$8 z_2y*FrZ!nL`*fH~a6-(IB8zNZDxQ3%Hzz7KYuj@xwqrsS<%v)Uw80gJ+4)qs$IjDJ zbKKTf3ApdggtkwZ5b}7d2=-KE*3`=OiHYbZ!}XzkGBYV_+Ug0(BzrCPA&V#%3l)U@oRl012;Fo_PXIi4qrrGwI1**ufU^5(Oq6q};r zaz&i!+zyJw@N$}u^6A_cd#EL`Bo8W`(}!IOrJ@^Q-TmlQW(Sh?Dsw@(T+K?pG4#!` zK62PE?wY9TdH14(1W`V4q|}?y7|-*i+Q{|XNs6}4MXe`nE(O}tYv#Ji^y=BQOA8n6 z(B+}E<_B@qdbAk$)`sipoe+k-PG`WD7hCPVOFOyql%2~vseIdsy)Ud^Sii8*D$hH_ zw$9>oPcL_umRkHRFYBeH-txn(?n<}I!q!DQibefw-EynD)aowl?nAwm?$IvS!g=FE zYa=(APvmUt>5FcQN_Mc+uTSLFM7uVqJ#g6#lh_-d8>E~OV(TfSWP^eOu(e@L+SBWJ zSPZb&>LayhSFc`e2T>Dm+iUI2h7M;&S<0PZFD))ehkB}@(QraadrIj)xzThB%{Z9U zWIK+c;SAx})WbYZZOnq<_|_oKj5Mm4Ldo2SGc}0^X8gkV7o3?ObIZem|DewpTGI5BkD*`l(u*=(msjTYMwUiJ)9h`vCF ztNf^&oXqBGPdn&&u|YKHA#INmckRjQw>W(oFQoU0%JGX;??Yu3UpI*)zLxE8l`@ezQ1nTUB_!I zBJP;2IH5Emr-IE>>J1%fb3D(Ox@ob|iY=2U&i)_bi5#Gs2UM~1s!U8tAk!Gm6UstP zM*1cD&v_xMt7lh`+LZ*!u3Mz4nhcr=UANT#_ihipamH~cs!JRBCy!x6>m=%u*LD_Z z*{&$APorHgq_IXuWfCA)s5&3sv^RTY$^7}M^-j({LNtGwN14?5%$&EJ8tktfzfkRS MV>~Z3b=s)^0b(KU82|tP delta 979 zcmXxiKWGzC9Ki8kOk&Jmn^s#}t-aI|l{Re>ENGB+(Bcy4(nX4Yj^r9c(>qBnf>S_C z2Nl$w7I9Fpa~HEHA_!3zr-Fl%;ARJLb}0D$)%fGy`@DC(yx;G=*I%hm1Fi49fu};G zXvb({K9MP$*hfeF#Iv}Aqd4jp>BBh;;$_^A*Kh)t@Ev-%it_;xhVm5;;5R&qKQJ!R zl3fNNUPM_fjD4tu3}XZfco^p}ii>z0D|issP#4@l9(hf71mEB|Zet90yYC}ZtNBi# zpZqe;KsP&unjnvwUExyyiCkb9^n@ep}rolXmQfm-o<)E#J2y%PQQ5KWV5=o)(T8hVup zn*Lrx{|7WQv4&nT%eAD3f!8RGde0(@>(OQJcXYnJ8hh;XSza+Q lmUKH?ZnNeX<*MCzMPW|+b0Yn(rm`t^XVVd<>Amea^B0UFeiQ%z diff --git a/apps/linking/locale/pt/LC_MESSAGES/django.po b/apps/linking/locale/pt/LC_MESSAGES/django.po index 120688a322..bbfb8411f3 100644 --- a/apps/linking/locale/pt/LC_MESSAGES/django.po +++ b/apps/linking/locale/pt/LC_MESSAGES/django.po @@ -1,75 +1,75 @@ # 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" +"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-02 05:05+0000\n" -"Last-Translator: emersonsoares \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\n" +"PO-Revision-Date: 2012-01-02 05:40+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:11 msgid "View existing smart links" -msgstr "" +msgstr "Ver os ligações inteligentes" #: __init__.py:12 msgid "Create new smart links" -msgstr "" +msgstr "Criar novas ligações inteligentes" #: __init__.py:13 msgid "Delete smart links" -msgstr "" +msgstr "Excluir ligações inteligentes" #: __init__.py:14 msgid "Edit smart links" -msgstr "" +msgstr "Editar ligações inteligentes" #: __init__.py:16 msgid "Smart links" -msgstr "" +msgstr "Ligações inteligentes" #: __init__.py:22 msgid "smart links actions" -msgstr "" +msgstr "ações do ligações inteligentes" #: __init__.py:23 __init__.py:25 models.py:21 views.py:105 msgid "smart links" -msgstr "" +msgstr "ligações inteligentes" #: __init__.py:26 msgid "smart links list" -msgstr "" +msgstr "lista de ligações inteligentes" #: __init__.py:27 msgid "create new smart link" -msgstr "" +msgstr "criar um novo ligação inteligente" #: __init__.py:28 __init__.py:33 msgid "edit" -msgstr "" +msgstr "editar" #: __init__.py:29 __init__.py:34 msgid "delete" -msgstr "" +msgstr "excluir" #: __init__.py:31 msgid "conditions" -msgstr "" +msgstr "condições" #: __init__.py:32 msgid "create condition" -msgstr "" +msgstr "criar condições" #: forms.py:48 msgid "Pages" @@ -175,7 +175,7 @@ msgstr "habilitado" #: models.py:20 models.py:25 views.py:256 views.py:287 msgid "smart link" -msgstr "" +msgstr "ligação inteligente" #: models.py:26 msgid "The inclusion is ignored for the first item." @@ -211,40 +211,39 @@ msgstr "não" #: models.py:37 msgid "link condition" -msgstr "" +msgstr "condição de ligação" #: models.py:38 msgid "link conditions" -msgstr "" +msgstr "condições de ligação" #: views.py:32 msgid "No action selected." msgstr "Nenhuma ação selecionada." #: views.py:47 -#, fuzzy, python-format +#, python-format msgid "documents in smart link: %(group)s" -msgstr "documentos no grupo: %(group)s " +msgstr "" #: views.py:65 -#, fuzzy, python-format +#, python-format msgid "Smart link query error: %s" -msgstr "Erro na consulta de grupo do documento: %s" +msgstr "" #: views.py:76 #, python-format msgid "smart links (%s)" -msgstr "" +msgstr "ligações inteligente (%s)" #: views.py:90 -#, fuzzy msgid "There no defined smart links for the current document." -msgstr "Não há grupos definidos para o documento atual." +msgstr "" #: views.py:124 #, python-format msgid "Smart link: %s created successfully." -msgstr "" +msgstr "Ligação inteligente: %s criado com sucesso." #: views.py:131 msgid "Create new smart link" @@ -258,7 +257,7 @@ msgstr "" #: views.py:153 #, python-format msgid "Edit smart link: %s" -msgstr "" +msgstr "Editar Ligação inteligente: %s" #: views.py:168 #, python-format @@ -301,7 +300,7 @@ msgstr "" #: views.py:257 views.py:288 msgid "condition" -msgstr "" +msgstr "condição" #: views.py:274 #, python-format @@ -336,26 +335,4 @@ msgid "" "jump to and from linked documents very easily." msgstr "" -#~ msgid "group actions" -#~ msgstr "ações do grupo" -#~ msgid "groups" -#~ msgstr "grupos" - -#~ msgid "group document" -#~ msgstr "agrupar documento" - -#~ msgid "document group" -#~ msgstr "grupo de documentos" - -#~ msgid "document groups" -#~ msgstr "grupos de documentos" - -#~ msgid "group item" -#~ msgstr "item do grupo" - -#~ msgid "group items" -#~ msgstr "itens do grupo" - -#~ msgid "document groups (%s)" -#~ msgstr "grupos do documento (%s)" diff --git a/apps/main/locale/es/LC_MESSAGES/django.mo b/apps/main/locale/es/LC_MESSAGES/django.mo index 3c57a910a9e48b2d9537d81617cf048f6d855ec1..61b945b1de16be1f8cde1c0ff2a678dd7b369da3 100644 GIT binary patch delta 450 zcmXZXy-UMD7zXf*(oYnvHVRJH!4Hrov9wDmD5#r=SQiI}t3A?`Bqw**!J>2!+@+JC zv*MyyI=H$x`40##u7Zos;!~R&^2__a$@6kI=8O4|H98*#A?+9;2|~yL9zd3oCYl9P0_tf X<}$R#6srr$L%Pvqp(}c?$v5K90%~07^IvpVa$zc#Hf2C*hSz9kTIoZxS`&GaP|muw10q z{yxltqsUVbXUT`<#fz|HRR0{}ztJn|0~Zzfsx8aDHs~$X zHn_;$t&At4&GR%1oYn9+PGXT~JWMmkS>k10`K|I$|D4(RpN>LzTf|8#aKa;=v{E-q iMU>~<@x6I(w%Dz1GJQP~*edUghV;!k^NPOl#(n^(7DeR% diff --git a/apps/main/locale/es/LC_MESSAGES/django.po b/apps/main/locale/es/LC_MESSAGES/django.po index da34696a3f..aa29907f8d 100644 --- a/apps/main/locale/es/LC_MESSAGES/django.po +++ b/apps/main/locale/es/LC_MESSAGES/django.po @@ -3,21 +3,20 @@ # 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" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "POT-Creation-Date: 2011-12-06 03:26-0400\n" -"PO-Revision-Date: 2011-12-06 03:27\n" -"Last-Translator: Administrador \n" +"PO-Revision-Date: 2012-01-02 05:42+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" -"X-Translated-Using: django-rosetta 0.6.2\n" #: __init__.py:31 msgid "maintenance" @@ -61,11 +60,11 @@ msgstr "Diagnósticos" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar " -"widget or by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." msgstr "" -"Controla si la funcionalidad de búsqueda es proporcionada por una " -"barra lateral o por una entrada de menú." +"Controla si la funcionalidad de búsqueda es proporcionada por una barra " +"lateral o por una entrada de menú." #: templates/about.html:5 msgid "About this program" @@ -136,13 +135,12 @@ msgstr "Otras acciones disponibles" #: templates/home.html:8 msgid "Django based open source document management system" -msgstr "Gestor de documentos de código abierto, basado en Django." +msgstr "Sistema de manejo de documentos de código abierto basado en Django" #: templates/project_description.html:6 msgid "" -"Open source, Django based electronic document manager with custom " -"metadata, indexing, tagging, file serving integration and OCR " -"capabilities" +"Open source, Django based electronic document manager with custom metadata, " +"indexing, tagging, file serving integration and OCR capabilities" msgstr "" "Gestor documental de código abierto, basado en Django con metadatos " "personaliables, indexación, etiquedado de documentos, integración de " @@ -151,3 +149,5 @@ msgstr "" #: templates/project_description.html:15 msgid "Released under the GPL V3 License" msgstr "Publicado bajo la licencia GPL v3" + + diff --git a/apps/main/locale/it/LC_MESSAGES/django.mo b/apps/main/locale/it/LC_MESSAGES/django.mo index cef91c1286a59d4539e9bfd460fe5c5572acc7d8..1fbd414fb8680cc7438b01b73c090f66b3c17373 100644 GIT binary patch delta 370 zcmXZXu}T9$5P;!{F{gC|80mRxu zNg-J13s{In$~1O9h5wSk?tIHIGtBdiBC<@_z&bjpa2F5I#}01e z19Iezu!f&_fj_u}dQpUta)fqH8{hF5*U>49tl(BzhO)_HZZiQBfWBq z4ZK5J_lWcOj8%NaRs2A^z&F}O$7t&($bSW-&TYu3GWS%}+Ebyc_9Gp7Dp0C&cIw6H zP1egy*J~&JG;+1_De^s~T@^$@ct0sMcVg2?^S*Io(@XNqxQF>P(aNWZ)}`qVlB;wu IYC2!Ve^C=QegFUf delta 363 zcmXxfJxc>Y5P;!{F{g<^(O?XMvZV5ZmEBb%9@G)Sscdz7jX#y{vyD$!#|nPo1Xl9Wl{p>@`QOAY`T+;%8=HUm1nH3r zEaN5mx*HtEJ1pWoPT~Xl1)k9_IzV6lhWuARrnzP57lv-L&T8kBwV|tNvt~@8v8VUr z^W-#1+qxc|#i4S>T5X*+o64?-X7&0#H&bmS@ku92TdCTKTE|gaZFT-LE6txwe?EB4 FegpqoGjsp| diff --git a/apps/main/locale/it/LC_MESSAGES/django.po b/apps/main/locale/it/LC_MESSAGES/django.po index dc3c3c9cf5..d2e9b27283 100644 --- a/apps/main/locale/it/LC_MESSAGES/django.po +++ b/apps/main/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-09 15:03+0000\n" -"Last-Translator: Pierpaolo Baldan \n" +"POT-Creation-Date: 2011-12-06 03:26-0400\n" +"PO-Revision-Date: 2012-01-02 04:46+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" @@ -18,31 +18,31 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:15 +#: __init__.py:31 msgid "maintenance" msgstr "manutenzione" -#: __init__.py:16 +#: __init__.py:32 msgid "statistics" msgstr "statistiche" -#: __init__.py:17 +#: __init__.py:33 msgid "diagnostics" msgstr "disgnostica" -#: __init__.py:18 +#: __init__.py:34 msgid "sentry" msgstr "guardia" -#: __init__.py:19 +#: __init__.py:35 msgid "admin site" msgstr "sito d'amministrazione" -#: __init__.py:30 +#: __init__.py:38 msgid "home" msgstr "home" -#: __init__.py:32 +#: __init__.py:40 msgid "search" msgstr "cerca" @@ -133,6 +133,10 @@ msgstr "Azioni" msgid "Other available actions" msgstr "Altre azioni disponibili" +#: templates/home.html:8 +msgid "Django based open source document management system" +msgstr "" + #: templates/project_description.html:6 msgid "" "Open source, Django based electronic document manager with custom metadata, " diff --git a/apps/main/locale/pt/LC_MESSAGES/django.mo b/apps/main/locale/pt/LC_MESSAGES/django.mo index f0e4a1a726677c699069ce2665e39927ee0635eb..ad932ad425e1d57ef05704b46ffc5154ee77d252 100644 GIT binary patch delta 427 zcmXZXKTN_v6bA5zSP;ZW6p7JHwXdK+d#ps}m9@>;f=rz|e$RMMOTL%|M zCleDBMqM4;Ts2{Lc6ISPpt-zX`}*CxcD$ODUJ9w4XJ|09vVdzgla$tk)@ki z@D^e=J-{-2gevz6Gw=fz;3rfcG=^&bFT|oh6qVQVMEKuHZw;1dl%M12?M@trj%9g% z-08Qg7oulL5pn4YY4!Lu4=g{5`fik5X&c$P$!wi9k~^((fcu)s>N;yWP1|6&@+}_4 z=8@z<)a9{|j(#ZGu8akoOw@Pfv{9WMQT0SH;9Yl+{AlONaprWf#RIR;J=f90(Q}5S F{{h@CO$Gn} delta 402 zcmZY4ze~eF7{>9p*2Y>Qh_)3JN+CETvmQxe6(|;+nh+FATlE&Z*H b{gtwsbz(PF(i*51U+MO<3+s6NWqJ7@_i#YH diff --git a/apps/main/locale/pt/LC_MESSAGES/django.po b/apps/main/locale/pt/LC_MESSAGES/django.po index 02ed418063..6f871ca74f 100644 --- a/apps/main/locale/pt/LC_MESSAGES/django.po +++ b/apps/main/locale/pt/LC_MESSAGES/django.po @@ -1,49 +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: # , 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-03 21:55+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: 2011-12-06 03:26-0400\n" +"PO-Revision-Date: 2012-01-02 04:46+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:15 +#: __init__.py:31 msgid "maintenance" msgstr "manutenção" -#: __init__.py:16 +#: __init__.py:32 msgid "statistics" msgstr "estatísticas" -#: __init__.py:17 +#: __init__.py:33 msgid "diagnostics" msgstr "diagnósticos" -#: __init__.py:18 +#: __init__.py:34 msgid "sentry" msgstr "sentinela" -#: __init__.py:19 +#: __init__.py:35 msgid "admin site" msgstr "site de administação" -#: __init__.py:30 +#: __init__.py:38 msgid "home" msgstr "inicio" -#: __init__.py:32 +#: __init__.py:40 msgid "search" msgstr "pesquisa" @@ -61,8 +60,8 @@ msgstr "Diagnósticos" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or " -"by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." msgstr "" "Controla-se a funcionalidade de pesquisa é fornecido por um widget da barra " "lateral ou por uma entrada de menu." @@ -134,6 +133,10 @@ msgstr "Ações" msgid "Other available actions" msgstr "Outras ações disponíveis" +#: templates/home.html:8 +msgid "Django based open source document management system" +msgstr "" + #: templates/project_description.html:6 msgid "" "Open source, Django based electronic document manager with custom metadata, " @@ -146,3 +149,5 @@ msgstr "" #: templates/project_description.html:15 msgid "Released under the GPL V3 License" msgstr "Liberado sob a licença GPL V3" + + diff --git a/apps/main/locale/ru/LC_MESSAGES/django.mo b/apps/main/locale/ru/LC_MESSAGES/django.mo index 4dd6882e6c0537acdc8926b030d6648cdf5306e1..eceafef576f83e40363075c1b75ce035b3455ebd 100644 GIT binary patch delta 438 zcmXZWze~eF6bJCvO4`~M>!77ok$^)7ZF2oV3sFQI#G#W41sAzWNP}svTrPuMs*970 z1a#=XASiV6KkyH569+f{14qBHJ-GYay~n-xK1!4FYd$g7lSD0zC{09N96G#!%kT!a z;RD=<@6dpm%q-uATX-MCXXwEqEH4seA)C7kpAtkzkRkqsWc;s?qcPQRY2=93p$%8y zEiA!DxC38c9)7|l_yglczw>wjNfYl4Sb-fF51?QQj$vH)4q^_%9JGpEq-i$E7b<q@|yTo-LJt{}uH;ISUx`7KS7I5%=uTfivK)7k7`owbSS@b)N5V Q-wC;6Te=LVlhm8`2aHxwrvLx| delta 396 zcmZY3Jxjwt7{KwTl}3$06l!g8Fd(RdN$)~wX%s2wX2GIvP8muFXobEFE*<;`1r;1! z9mGzqZktdu|FZ`FkrhcuR?tGa{2BGS6mX0q4-i3hv=H zUZ9IlN&OpFh|^Odcesi7Hds~Epq!(Ihw+&C1!E&U>Hq)$ diff --git a/apps/main/locale/ru/LC_MESSAGES/django.po b/apps/main/locale/ru/LC_MESSAGES/django.po index 068fcbe6a4..517f7a9a6b 100644 --- a/apps/main/locale/ru/LC_MESSAGES/django.po +++ b/apps/main/locale/ru/LC_MESSAGES/django.po @@ -1,50 +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: # Sergey Glita , 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-19 21:04+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: 2011-12-06 03:26-0400\n" +"PO-Revision-Date: 2012-01-02 04:46+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/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:15 +#: __init__.py:31 msgid "maintenance" msgstr "техническое обслуживание" -#: __init__.py:16 +#: __init__.py:32 msgid "statistics" msgstr "статистика" -#: __init__.py:17 +#: __init__.py:33 msgid "diagnostics" msgstr "диагностика" -#: __init__.py:18 +#: __init__.py:34 msgid "sentry" msgstr "sentry" -#: __init__.py:19 +#: __init__.py:35 msgid "admin site" msgstr "админка" -#: __init__.py:30 +#: __init__.py:38 msgid "home" msgstr "Начало" -#: __init__.py:32 +#: __init__.py:40 msgid "search" msgstr "поиск" @@ -62,8 +60,8 @@ msgstr "Диагностика" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or " -"by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." msgstr "" "Определяет, будет ли функция поиска обеспечивается виджетом боковой панели " "или пунктом меню." @@ -135,6 +133,10 @@ msgstr "Действия" msgid "Other available actions" msgstr "Другие возможные действия" +#: templates/home.html:8 +msgid "Django based open source document management system" +msgstr "" + #: templates/project_description.html:6 msgid "" "Open source, Django based electronic document manager with custom metadata, " @@ -147,3 +149,5 @@ msgstr "" #: templates/project_description.html:15 msgid "Released under the GPL V3 License" msgstr "Выпущено под лицензией GPL V3" + + From 34311fb17e5dc7b0d9e70cede6eaecf6b3bd97f7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 03:48:26 -0400 Subject: [PATCH 131/484] Cleanups, permissions separation into explicit module, absolute import update --- apps/acls/admin.py | 8 ++-- apps/acls/forms.py | 4 +- apps/acls/models.py | 2 + apps/acls/permissions.py | 14 +++++++ apps/acls/widgets.py | 4 +- apps/common/__init__.py | 6 ++- apps/common/forms.py | 24 ++++++------ apps/common/utils.py | 4 +- apps/common/views.py | 37 +++++++++--------- apps/common/widgets.py | 16 ++++---- apps/common/wizard.py | 22 +++++++---- apps/converter/__init__.py | 6 ++- apps/converter/api.py | 18 ++++----- apps/converter/exceptions.py | 16 ++++---- apps/converter/office_converter.py | 6 ++- apps/converter/runtime.py | 6 ++- apps/django_gpg/__init__.py | 14 +++---- apps/django_gpg/api.py | 4 +- apps/django_gpg/views.py | 12 +++--- apps/document_comments/__init__.py | 13 +++---- apps/document_comments/permissions.py | 12 ++++++ apps/document_comments/utils.py | 4 +- apps/document_comments/views.py | 13 ++++--- apps/document_indexing/__init__.py | 13 +++---- apps/document_indexing/api.py | 18 ++++----- apps/document_indexing/filesystem.py | 7 ++-- apps/document_indexing/models.py | 4 +- apps/document_indexing/os_specifics.py | 4 +- apps/document_indexing/permissions.py | 10 +++++ apps/document_indexing/views.py | 13 ++++--- apps/document_signatures/permissions.py | 1 - apps/documents/__init__.py | 16 ++++---- apps/documents/admin.py | 4 +- apps/documents/forms.py | 8 ++-- apps/documents/literals.py | 23 ----------- apps/documents/managers.py | 4 +- apps/documents/models.py | 21 +++++----- apps/documents/permissions.py | 24 ++++++++++++ apps/documents/statistics.py | 8 ++-- apps/documents/tests.py | 2 + apps/documents/urls.py | 9 ++--- apps/documents/views.py | 39 +++++++------------ apps/documents/widgets.py | 4 +- apps/documents/wizards.py | 4 +- apps/folders/__init__.py | 4 +- apps/folders/admin.py | 4 +- apps/folders/forms.py | 4 +- apps/folders/views.py | 3 +- apps/history/__init__.py | 7 ++-- apps/history/api.py | 6 ++- apps/history/forms.py | 4 +- apps/history/models.py | 4 +- apps/history/permissions.py | 9 +++++ apps/history/views.py | 10 +++-- apps/linking/__init__.py | 13 ++----- apps/linking/models.py | 4 +- apps/linking/permissions.py | 12 ++++++ apps/linking/views.py | 7 ++-- apps/lock_manager/__init__.py | 6 ++- apps/lock_manager/admin.py | 4 +- apps/lock_manager/managers.py | 4 +- apps/lock_manager/models.py | 6 ++- apps/main/__init__.py | 8 ++-- apps/main/views.py | 6 ++- apps/metadata/__init__.py | 35 ++++++----------- apps/metadata/admin.py | 6 ++- apps/metadata/api.py | 29 ++++++++------ apps/metadata/forms.py | 8 ++-- apps/metadata/models.py | 5 ++- apps/metadata/permissions.py | 22 +++++++++++ apps/metadata/views.py | 28 ++++++------- .../templatetags/navigation_tags.py | 8 ++-- apps/ocr/__init__.py | 20 ++++------ apps/ocr/api.py | 15 ++++--- apps/ocr/managers.py | 4 +- apps/ocr/models.py | 12 +++--- apps/ocr/permissions.py | 13 +++++++ apps/ocr/tasks.py | 18 ++++----- apps/ocr/views.py | 23 +++++------ apps/permissions/__init__.py | 18 ++++----- apps/permissions/admin.py | 4 +- apps/permissions/forms.py | 4 +- apps/permissions/models.py | 4 +- apps/permissions/permissions.py | 14 +++++++ apps/permissions/views.py | 14 ++++--- apps/project_setup/views.py | 4 +- apps/project_tools/views.py | 4 +- apps/rest_api/urls.py | 6 ++- apps/scheduler/api.py | 6 ++- apps/smart_settings/views.py | 4 +- apps/sources/__init__.py | 25 +++++------- apps/sources/admin.py | 4 +- apps/sources/forms.py | 10 +++-- apps/sources/models.py | 16 ++++---- apps/sources/permissions.py | 14 +++++++ apps/sources/staging.py | 2 + apps/sources/urls.py | 6 ++- apps/sources/views.py | 22 ++++++----- apps/tags/__init__.py | 21 ++++------ apps/tags/admin.py | 4 +- apps/tags/forms.py | 4 +- apps/tags/permissions.py | 14 +++++++ apps/tags/utils.py | 4 +- apps/tags/views.py | 14 ++++--- apps/user_management/__init__.py | 18 +++------ apps/user_management/permissions.py | 17 ++++++++ apps/user_management/views.py | 12 +++--- 107 files changed, 693 insertions(+), 468 deletions(-) create mode 100644 apps/acls/permissions.py create mode 100644 apps/document_comments/permissions.py create mode 100644 apps/document_indexing/permissions.py create mode 100644 apps/documents/permissions.py create mode 100644 apps/history/permissions.py create mode 100644 apps/linking/permissions.py create mode 100644 apps/metadata/permissions.py create mode 100644 apps/ocr/permissions.py create mode 100644 apps/permissions/permissions.py create mode 100644 apps/sources/permissions.py create mode 100644 apps/tags/permissions.py create mode 100644 apps/user_management/permissions.py diff --git a/apps/acls/admin.py b/apps/acls/admin.py index 630f1d4afe..6608e6799b 100644 --- a/apps/acls/admin.py +++ b/apps/acls/admin.py @@ -1,10 +1,12 @@ +from __future__ import absolute_import + from django.contrib import admin - -from acls.models import AccessEntry - from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType +from .models import AccessEntry + + #class PermissionHolderInline(admin.StackedInline): # model = PermissionHolder # extra = 1 diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 0e4b68098c..a4fbebf4c5 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django import forms from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group @@ -5,7 +7,7 @@ from django.contrib.auth.models import User, Group from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate, get_object_name -from acls.models import AccessHolder +from .models import AccessHolder def _as_choice_list(holders): diff --git a/apps/acls/models.py b/apps/acls/models.py index 554403e0bf..866c9e11ff 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import sys import types import logging diff --git a/apps/acls/permissions.py b/apps/acls/permissions.py new file mode 100644 index 0000000000..2ab114070a --- /dev/null +++ b/apps/acls/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 + +acls_namespace = PermissionNamespace('acls', _(u'Access control lists')) +acls_setup_namespace = PermissionNamespace('acls_setup', _(u'Access control lists')) + +ACLS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit ACLs')) +ACLS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View ACLs')) + +ACLS_CLASS_EDIT_ACL = Permission.objects.register(acls_setup_namespace, 'acl_class_edit', _(u'Edit class default ACLs')) +ACLS_CLASS_VIEW_ACL = Permission.objects.register(acls_setup_namespace, 'acl_class_view', _(u'View class default ACLs')) diff --git a/apps/acls/widgets.py b/apps/acls/widgets.py index e2a57823e2..8a410fd171 100644 --- a/apps/acls/widgets.py +++ b/apps/acls/widgets.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe from django import forms @@ -8,7 +10,7 @@ from django.contrib.contenttypes.models import ContentType from django.db.models.base import ModelBase from django.template.defaultfilters import capfirst -from acls.literals import CONTENT_TYPE_ICON_MAP +from .literals import CONTENT_TYPE_ICON_MAP def content_type_icon(content_type): diff --git a/apps/common/__init__.py b/apps/common/__init__.py index 6c9e4b6287..4212752ca8 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import tempfile from django.utils.translation import ugettext_lazy as _ @@ -7,8 +9,8 @@ from django.db.models import signals from navigation.api import register_links, register_top_menu -from common.conf import settings as common_settings -from common.utils import validate_path +from .conf import settings as common_settings +from .utils import validate_path def has_usable_password(context): diff --git a/apps/common/forms.py b/apps/common/forms.py index 195bac61da..91aff0b67e 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import os from django import forms @@ -8,9 +10,9 @@ from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import authenticate from django.conf import settings -from common.utils import return_attrib -from common.widgets import DetailSelectMultiple, PlainWidget, \ - TextAreaDiv, EmailInput +from .utils import return_attrib +from .widgets import (DetailSelectMultiple, PlainWidget, TextAreaDiv, + EmailInput) class DetailForm(forms.ModelForm): @@ -90,10 +92,10 @@ class FilterForm(forms.Form): class ChoiceForm(forms.Form): - """ + ''' Form to be used in side by side templates used to add or remove items from a many to many field - """ + ''' def __init__(self, *args, **kwargs): choices = kwargs.pop('choices', []) label = kwargs.pop('label', _(u'Selection')) @@ -106,28 +108,28 @@ class ChoiceForm(forms.Form): class UserForm_view(DetailForm): - """ + ''' Form used to display an user's public details - """ + ''' class Meta: model = User fields = ('username', 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser', 'last_login', 'date_joined', 'groups') class UserForm(forms.ModelForm): - """ + ''' Form used to edit an user's mininal fields by the user himself - """ + ''' class Meta: model = User fields = ('first_name', 'last_name') class EmailAuthenticationForm(AuthenticationForm): - """ + ''' Override the default authentication form to use email address authentication - """ + ''' email = forms.CharField(label=_(u'Email'), max_length=75, widget=EmailInput() ) diff --git a/apps/common/utils.py b/apps/common/utils.py index 3ff3bf9677..da13756918 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -110,7 +110,9 @@ def pretty_size_10(size): # http://www.johncardinal.com/tmgutil/capitalizenames.htm def proper_name(name): - """Does the work of capitalizing a name (can be a full name).""" + ''' + Does the work of capitalizing a name (can be a full name). + ''' mc = re.compile(r'^Mc(\w)(?=\w)', re.I) mac = re.compile(r'^Mac(\w)(?=\w)', re.I) suffixes = [ diff --git a/apps/common/views.py b/apps/common/views.py index 8575e3b788..c88a204362 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect @@ -10,26 +12,25 @@ from django.utils.http import urlencode from django.contrib.auth.views import login from django.utils.simplejson import dumps, loads -from common.forms import ChoiceForm, UserForm, UserForm_view, \ - ChangelogForm, LicenseForm -from common.forms import EmailAuthenticationForm -from common.conf.settings import LOGIN_METHOD +from .forms import (ChoiceForm, UserForm, UserForm_view, ChangelogForm, + LicenseForm, EmailAuthenticationForm) +from .conf.settings import LOGIN_METHOD def password_change_done(request): - """ + ''' View called when the new user password has been accepted - """ + ''' messages.success(request, _(u'Your password has been successfully changed.')) return redirect('home') def multi_object_action_view(request): - """ + ''' Proxy view called first when using a multi object action, which then redirects to the appropiate specialized view - """ + ''' next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) @@ -144,9 +145,9 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef def current_user_details(request): - """ + ''' Display the current user's details - """ + ''' form = UserForm_view(instance=request.user) return render_to_response( @@ -159,9 +160,9 @@ def current_user_details(request): def current_user_edit(request): - """ + ''' Allow an user to edit his own details - """ + ''' next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('current_user_details')))) @@ -184,10 +185,10 @@ def current_user_edit(request): def login_view(request): - """ + ''' Control how the use is to be authenticated, options are 'email' and 'username' - """ + ''' kwargs = {'template_name': 'login.html'} if LOGIN_METHOD == 'email': @@ -197,9 +198,9 @@ def login_view(request): def changelog_view(request): - """ + ''' Display the included Changelog.txt file from the about menu - """ + ''' form = ChangelogForm() return render_to_response( 'generic_detail.html', { @@ -210,9 +211,9 @@ def changelog_view(request): def license_view(request): - """ + ''' Display the included LICENSE file from the about menu - """ + ''' form = LicenseForm() return render_to_response( 'generic_detail.html', { diff --git a/apps/common/widgets.py b/apps/common/widgets.py index 5e39ba4742..bfedfaa776 100644 --- a/apps/common/widgets.py +++ b/apps/common/widgets.py @@ -10,10 +10,10 @@ from django.utils.encoding import force_unicode class PlainWidget(forms.widgets.Widget): - """ + ''' Class to define a form widget that effectively nulls the htmls of a widget and reduces the output to only it's value - """ + ''' def render(self, name, value, attrs=None): return mark_safe(u'%s' % value) @@ -74,10 +74,10 @@ def two_state_template(state, famfam_ok_icon=u'tick', famfam_fail_icon=u'cross') class TextAreaDiv(forms.widgets.Widget): - """ + ''' Class to define a form widget that simulates the behavior of a Textarea widget but using a div tag instead - """ + ''' def __init__(self, attrs=None): # The 'rows' and 'cols' attributes are required for HTML correctness. @@ -98,10 +98,10 @@ class TextAreaDiv(forms.widgets.Widget): # From: http://www.peterbe.com/plog/emailinput-html5-django class EmailInput(forms.widgets.Input): - """ + ''' Class for a login form widget that accepts only well formated email address - """ + ''' input_type = 'email' def render(self, name, value, attrs=None): @@ -114,11 +114,11 @@ class EmailInput(forms.widgets.Input): class ScrollableCheckboxSelectMultiple(forms.widgets.CheckboxSelectMultiple): - """ + ''' Class for a form widget composed of a selection of checkboxes wrapped in a div tag with automatic overflow to add scrollbars when the list exceds the height of the div - """ + ''' def render(self, name, value, attrs=None, choices=()): if value is None: value = [] has_id = attrs and 'id' in attrs diff --git a/apps/common/wizard.py b/apps/common/wizard.py index 4a8cc70e61..914dcd062a 100644 --- a/apps/common/wizard.py +++ b/apps/common/wizard.py @@ -1,4 +1,4 @@ -"""Common abstract classes for forms.""" +'''Common abstract classes for forms.''' try: import cPickle as pickle except ImportError: @@ -15,12 +15,13 @@ __all__ = ('security_hash', 'BoundFormWizard') def security_hash_new(form, exclude=None, *args): - """Calculates a security hash for the given Form/FormSet instance. + ''' + Calculates a security hash for the given Form/FormSet instance. This creates a list of the form field names/values in a deterministic order, pickles the result with the SECRET_KEY setting, then takes an md5 hash of that. - """ + ''' data = [] if exclude is None: @@ -51,19 +52,24 @@ def security_hash_new(form, exclude=None, *args): class BoundFormWizard(FormWizard): - """Render prev_fields as a list of bound form fields in the template - context rather than raw html.""" + ''' + Render prev_fields as a list of bound form fields in the template + context rather than raw html. + ''' + def security_hash(self, request, form): - """Calculates the security hash for the given HttpRequest and + ''' + Calculates the security hash for the given HttpRequest and Form/FormSet instances. Subclasses may want to take into account request-specific information, such as the IP address. - """ + ''' + return security_hash_new(form) def render(self, form, request, step, context=None): - "Renders the given Form object, returning an HttpResponse." + 'Renders the given Form object, returning an HttpResponse.' old_data = request.POST prev_fields = [] if old_data: diff --git a/apps/converter/__init__.py b/apps/converter/__init__.py index de30bc2350..a0417de178 100644 --- a/apps/converter/__init__.py +++ b/apps/converter/__init__.py @@ -1,11 +1,13 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ImproperlyConfigured from navigation.api import register_sidebar_template from project_tools.api import register_tool -from converter.utils import load_backend -from converter.conf.settings import GRAPHICS_BACKEND +from .utils import load_backend +from .conf.settings import GRAPHICS_BACKEND formats_list = {'text': _('file formats'), 'view': 'formats_list', 'famfam': 'pictures', 'icon': 'pictures.png'} diff --git a/apps/converter/api.py b/apps/converter/api.py index ff4e9d645b..8d1239afd2 100644 --- a/apps/converter/api.py +++ b/apps/converter/api.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import os import subprocess import hashlib @@ -7,15 +9,13 @@ from common.conf.settings import TEMPORARY_DIRECTORY from converter.literals import DEFAULT_PAGE_NUMBER, \ DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_FILE_FORMAT -from converter import backend -from converter.literals import TRANSFORMATION_CHOICES -from converter.literals import TRANSFORMATION_RESIZE, \ - TRANSFORMATION_ROTATE, TRANSFORMATION_ZOOM -from converter.literals import DIMENSION_SEPARATOR -from converter.literals import FILE_FORMATS -from converter.utils import cleanup -from converter.runtime import office_converter -from converter.exceptions import OfficeConversionError +from . import backend +from .literals import (TRANSFORMATION_CHOICES, TRANSFORMATION_RESIZE, + TRANSFORMATION_ROTATE, TRANSFORMATION_ZOOM, DIMENSION_SEPARATOR, + FILE_FORMATS) +from .utils import cleanup +from .runtime import office_converter +from .exceptions import OfficeConversionError HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() diff --git a/apps/converter/exceptions.py b/apps/converter/exceptions.py index 1423d38002..74b13a7c56 100644 --- a/apps/converter/exceptions.py +++ b/apps/converter/exceptions.py @@ -1,29 +1,29 @@ class ConvertError(Exception): - """ + ''' Base exception for all coverter app exceptions - """ + ''' pass class UnknownFileFormat(ConvertError): - """ + ''' Raised when the converter backend can't understand a file - """ + ''' pass class IdentifyError(ConvertError): - """ + ''' Raised by the graphcismagick and imagemagics identify program - """ + ''' pass class UnkownConvertError(ConvertError): - """ + ''' Raised when an error is found but there is no disernible way to identify the kind of error - """ + ''' pass diff --git a/apps/converter/office_converter.py b/apps/converter/office_converter.py index a0c93aa6d9..8df298ceed 100644 --- a/apps/converter/office_converter.py +++ b/apps/converter/office_converter.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import os import subprocess import logging @@ -6,8 +8,8 @@ from mimetype.api import get_mimetype from common.conf.settings import TEMPORARY_DIRECTORY from common.utils import id_generator -from converter.conf.settings import UNOCONV_PATH, UNOCONV_USE_PIPE -from converter.exceptions import (OfficeConversionError, +from .conf.settings import UNOCONV_PATH, UNOCONV_USE_PIPE +from .exceptions import (OfficeConversionError, OfficeBackendError, UnknownFileFormat) CACHED_FILE_SUFFIX = u'_office_converter' diff --git a/apps/converter/runtime.py b/apps/converter/runtime.py index 4d2a67cacc..9aad502667 100644 --- a/apps/converter/runtime.py +++ b/apps/converter/runtime.py @@ -1,5 +1,7 @@ -from converter.office_converter import OfficeConverter -from converter.exceptions import OfficeBackendError +from __future__ import absolute_import + +from .office_converter import OfficeConverter +from .exceptions import OfficeBackendError try: diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index 11f64783d0..a52df7339a 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -1,21 +1,17 @@ +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, \ register_sidebar_template from main.api import register_diagnostic, register_maintenance_links -from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup from hkp import Key as KeyServerKey -from django_gpg.api import Key - -django_gpg_namespace = PermissionNamespace('django_gpg', _(u'Key management')) - -PERMISSION_KEY_VIEW = Permission.objects.register(django_gpg_namespace, 'key_view', _(u'View keys')) -PERMISSION_KEY_DELETE = Permission.objects.register(django_gpg_namespace, 'key_delete', _(u'Delete keys')) -PERMISSION_KEYSERVER_QUERY = Permission.objects.register(django_gpg_namespace, 'keyserver_query', _(u'Query keyservers')) -PERMISSION_KEY_RECEIVE = Permission.objects.register(django_gpg_namespace, 'key_receive', _(u'Import keys from keyservers')) +from .api import Key +from .permissions import (PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, + PERMISSION_KEYSERVER_QUERY, PERMISSION_KEY_RECEIVE) # Setup views private_keys = {'text': _(u'private keys'), 'view': 'key_private_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index af95cc924f..ecda9a97a5 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import types from pickle import dumps @@ -12,7 +14,7 @@ from django.utils.http import urlquote_plus from hkp import KeyServer import gnupg -from django_gpg.exceptions import (GPGVerificationError, GPGSigningError, +from .exceptions import (GPGVerificationError, GPGSigningError, GPGDecryptionError, KeyDeleteError, KeyGenerationError, KeyFetchingError, KeyDoesNotExist, KeyImportError) diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index 83fa80cfd7..60d400b018 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from datetime import datetime import logging @@ -15,13 +17,13 @@ from permissions.models import Permission from common.utils import pretty_size, parse_range, urlquote, \ return_diff, encapsulate -from django_gpg.api import Key, SIGNATURE_STATES -from django_gpg.runtime import gpg -from django_gpg.exceptions import (GPGVerificationError, KeyFetchingError, +from .api import Key, SIGNATURE_STATES +from .runtime import gpg +from .exceptions import (GPGVerificationError, KeyFetchingError, KeyImportError) -from django_gpg import (PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, +from .forms import KeySearchForm +from .permissions import (PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, PERMISSION_KEYSERVER_QUERY, PERMISSION_KEY_RECEIVE) -from django_gpg.forms import KeySearchForm logger = logging.getLogger(__name__) diff --git a/apps/document_comments/__init__.py b/apps/document_comments/__init__.py index a0de601ea1..5d4cdec3bb 100644 --- a/apps/document_comments/__init__.py +++ b/apps/document_comments/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.contrib.comments.models import Comment @@ -12,13 +14,10 @@ from documents.models import Document if 'django.contrib.comments' not in settings.INSTALLED_APPS: raise Exception('This app depends on the django.contrib.comments app.') -comments_namespace = PermissionNamespace('comments', _(u'Comments')) - -PERMISSION_COMMENT_CREATE = Permission.objects.register(comments_namespace, 'comment_create', _(u'Create new comments')) -PERMISSION_COMMENT_DELETE = Permission.objects.register(comments_namespace, 'comment_delete', _(u'Delete comments')) -PERMISSION_COMMENT_EDIT = Permission.objects.register(comments_namespace, 'comment_edit', _(u'Edit comments')) -PERMISSION_COMMENT_VIEW = Permission.objects.register(comments_namespace, 'comment_view', _(u'View comments')) - +from .permissions import (PERMISSION_COMMENT_CREATE, + PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_EDIT, + PERMISSION_COMMENT_VIEW) + comment_delete = {'text': _('delete'), 'view': 'comment_delete', 'args': 'object.pk', 'famfam': 'comment_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_multiple_delete = {'text': _('delete'), 'view': 'comment_multiple_delete', 'args': 'object.pk', 'famfam': 'comments_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_add = {'text': _('add comment'), 'view': 'comment_add', 'args': 'object.pk', 'famfam': 'comment_add', 'permissions': [PERMISSION_COMMENT_CREATE]} diff --git a/apps/document_comments/permissions.py b/apps/document_comments/permissions.py new file mode 100644 index 0000000000..820a16ede5 --- /dev/null +++ b/apps/document_comments/permissions.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +comments_namespace = PermissionNamespace('comments', _(u'Comments')) + +PERMISSION_COMMENT_CREATE = Permission.objects.register(comments_namespace, 'comment_create', _(u'Create new comments')) +PERMISSION_COMMENT_DELETE = Permission.objects.register(comments_namespace, 'comment_delete', _(u'Delete comments')) +PERMISSION_COMMENT_EDIT = Permission.objects.register(comments_namespace, 'comment_edit', _(u'Edit comments')) +PERMISSION_COMMENT_VIEW = Permission.objects.register(comments_namespace, 'comment_view', _(u'View comments')) diff --git a/apps/document_comments/utils.py b/apps/document_comments/utils.py index 7f59249a09..cca6e07098 100644 --- a/apps/document_comments/utils.py +++ b/apps/document_comments/utils.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.contrib.comments.models import Comment -from document_comments import comment_delete +from . import comment_delete def get_comments_subtemplate(obj): diff --git a/apps/document_comments/views.py b/apps/document_comments/views.py index e2a57f17b8..9e474a2cb6 100644 --- a/apps/document_comments/views.py +++ b/apps/document_comments/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.shortcuts import render_to_response, get_object_or_404 from django.utils.translation import ugettext_lazy as _ from django.contrib.comments.models import Comment @@ -10,9 +12,10 @@ from django.contrib.sites.models import Site from permissions.models import Permission from documents.models import Document -from document_comments import PERMISSION_COMMENT_DELETE, \ - PERMISSION_COMMENT_CREATE, PERMISSION_COMMENT_VIEW -from document_comments.forms import CommentForm +from .permissions import (PERMISSION_COMMENT_CREATE, + PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_EDIT, + PERMISSION_COMMENT_VIEW) +from .forms import CommentForm def comment_delete(request, comment_id=None, comment_id_list=None): @@ -97,9 +100,9 @@ def comment_add(request, document_id): def comments_for_object(request, document_id): - """ + ''' Show a list of all the comments related to the passed object - """ + ''' Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_VIEW]) document = get_object_or_404(Document, pk=document_id) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 8199bc862a..c71a55f544 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -1,19 +1,18 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from navigation.api import register_top_menu, register_sidebar_template, \ register_links -from permissions.models import PermissionNamespace, Permission from main.api import register_maintenance_links -from documents.literals import PERMISSION_DOCUMENT_VIEW +from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document -from document_indexing.models import IndexInstance +from .models import IndexInstance +from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, + PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) -document_indexing_namespace = PermissionNamespace('document_indexing', _(u'Indexing')) - -PERMISSION_DOCUMENT_INDEXING_VIEW = Permission.objects.register(document_indexing_namespace, 'document_index_view', _(u'View document indexes')) -PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES = Permission.objects.register(document_indexing_namespace, 'document_rebuild_indexes', _(u'Rebuild document indexes')) index_list = {'text': _(u'index list'), 'view': 'index_instance_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True} diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 269d5ceddd..6b996fce17 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.core.urlresolvers import reverse @@ -7,15 +9,13 @@ from django.template.defaultfilters import slugify from documents.models import Document from metadata.classes import MetadataObject -from document_indexing.models import Index, IndexInstance, \ - DocumentRenameCount -from document_indexing.conf.settings import AVAILABLE_INDEXING_FUNCTIONS -from document_indexing.conf.settings import MAX_SUFFIX_COUNT -from document_indexing.filesystem import fs_create_index_directory, \ - fs_create_document_link, fs_delete_document_link, \ - fs_delete_index_directory, fs_delete_directory_recusive -from document_indexing.conf.settings import SLUGIFY_PATHS -from document_indexing.os_specifics import assemble_suffixed_filename +from .models import (Index, IndexInstance, DocumentRenameCount) +from .conf.settings import (AVAILABLE_INDEXING_FUNCTIONS, + MAX_SUFFIX_COUNT, SLUGIFY_PATHS) +from .filesystem import (fs_create_index_directory, + fs_create_document_link, fs_delete_document_link, + fs_delete_index_directory, fs_delete_directory_recusive) +from .os_specifics import assemble_suffixed_filename if SLUGIFY_PATHS == False: # Do not slugify path or filenames and extensions diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py index c89dad4cf6..4b24a9d4d6 100644 --- a/apps/document_indexing/filesystem.py +++ b/apps/document_indexing/filesystem.py @@ -1,12 +1,13 @@ +from __future__ import absolute_import + import errno import os from django.utils.translation import ugettext_lazy as _ -from document_indexing.os_specifics import (assemble_suffixed_filename, +from .os_specifics import (assemble_suffixed_filename, assemble_path_from_list) -from document_indexing.conf.settings import FILESERVING_ENABLE -from document_indexing.conf.settings import FILESERVING_PATH +from .conf.settings import (FILESERVING_ENABLE, FILESERVING_PATH) def get_instance_path(index_instance): diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index a8a1003131..a9df3f4dc2 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -6,7 +8,7 @@ from mptt.fields import TreeForeignKey from documents.models import Document -from document_indexing.conf.settings import AVAILABLE_INDEXING_FUNCTIONS +from .conf.settings import AVAILABLE_INDEXING_FUNCTIONS available_indexing_functions_string = (_(u'Available functions: %s') % u','.join([u'%s()' % name for name, function in AVAILABLE_INDEXING_FUNCTIONS.items()])) if AVAILABLE_INDEXING_FUNCTIONS else u'' diff --git a/apps/document_indexing/os_specifics.py b/apps/document_indexing/os_specifics.py index 90a9ba8a75..97bdc426e4 100644 --- a/apps/document_indexing/os_specifics.py +++ b/apps/document_indexing/os_specifics.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + import os -from document_indexing.conf.settings import SUFFIX_SEPARATOR +from .conf.settings import SUFFIX_SEPARATOR def assemble_suffixed_filename(filename, suffix=0): diff --git a/apps/document_indexing/permissions.py b/apps/document_indexing/permissions.py new file mode 100644 index 0000000000..01f1afa652 --- /dev/null +++ b/apps/document_indexing/permissions.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +document_indexing_namespace = PermissionNamespace('document_indexing', _(u'Indexing')) + +PERMISSION_DOCUMENT_INDEXING_VIEW = Permission.objects.register(document_indexing_namespace, 'document_index_view', _(u'View document indexes')) +PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES = Permission.objects.register(document_indexing_namespace, 'document_rebuild_indexes', _(u'Rebuild document indexes')) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index b79f1ad8ee..0505ad5cac 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect from django.shortcuts import render_to_response, get_object_or_404 @@ -6,18 +8,17 @@ from django.contrib import messages from django.utils.safestring import mark_safe from permissions.models import Permission -from documents.literals import PERMISSION_DOCUMENT_VIEW +from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list from common.utils import encapsulate -from document_indexing import (PERMISSION_DOCUMENT_INDEXING_VIEW, +from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) - -from document_indexing.models import IndexInstance -from document_indexing.api import (get_breadcrumbs, get_instance_link, +from .models import IndexInstance +from .api import (get_breadcrumbs, get_instance_link, do_rebuild_all_indexes) -from document_indexing.widgets import index_instance_item_link +from .widgets import index_instance_item_link def index_instance_list(request, index_id=None): diff --git a/apps/document_signatures/permissions.py b/apps/document_signatures/permissions.py index 8575d4c80c..477f649357 100644 --- a/apps/document_signatures/permissions.py +++ b/apps/document_signatures/permissions.py @@ -2,7 +2,6 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from permissions.api import register_permission, set_namespace_title from permissions.models import PermissionNamespace, Permission document_signatures_namespace = PermissionNamespace('document_signatures', _(u'Document signatures')) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 9f8fc1a59a..1629fe63af 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import tempfile from django.utils.translation import ugettext_lazy as _ @@ -13,22 +15,22 @@ from metadata.api import get_metadata_string from project_setup.api import register_setup from acls.models import class_permissions -from documents.models import (Document, DocumentPage, +from .models import (Document, DocumentPage, DocumentPageTransformation, DocumentType, DocumentTypeFilename, DocumentVersion) -from documents.literals import (PERMISSION_DOCUMENT_CREATE, +from .permissions import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS, PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE, PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW) -from documents.literals import (HISTORY_DOCUMENT_CREATED, +from .literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) -from documents.conf.settings import ZOOM_MAX_LEVEL -from documents.conf.settings import ZOOM_MIN_LEVEL -from documents.conf import settings as document_settings -from documents.widgets import document_thumbnail +from .conf.settings import ZOOM_MAX_LEVEL +from .conf.settings import ZOOM_MIN_LEVEL +from .conf import settings as document_settings +from .widgets import document_thumbnail # Document page links expressions def is_first_page(context): diff --git a/apps/documents/admin.py b/apps/documents/admin.py index 8fc0e838bb..40ac5d0a2b 100644 --- a/apps/documents/admin.py +++ b/apps/documents/admin.py @@ -1,8 +1,10 @@ +from __future__ import absolute_import + from django.contrib import admin from metadata.admin import DocumentMetadataInline -from documents.models import (DocumentType, Document, +from .models import (DocumentType, Document, DocumentTypeFilename, DocumentPage, DocumentPageTransformation, RecentDocument, DocumentVersion) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 63e4470a55..88cfa46395 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django import forms from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext @@ -11,11 +13,11 @@ from common.conf.settings import DEFAULT_PAPER_SIZE from common.conf.settings import DEFAULT_PAGE_ORIENTATION from common.widgets import TextAreaDiv -from documents.models import (Document, DocumentType, +from .models import (Document, DocumentType, DocumentPage, DocumentPageTransformation, DocumentTypeFilename, DocumentVersion) -from documents.widgets import document_html_widget -from documents.literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES) +from .widgets import document_html_widget +from .literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES) # Document page forms class DocumentPageTransformationForm(forms.ModelForm): diff --git a/apps/documents/literals.py b/apps/documents/literals.py index a85ce6119d..0f2aea6d98 100644 --- a/apps/documents/literals.py +++ b/apps/documents/literals.py @@ -1,33 +1,10 @@ from django.utils.translation import ugettext_lazy as _ -from permissions.models import PermissionNamespace, Permission - - PICTURE_ERROR_SMALL = u'picture_error.png' PICTURE_ERROR_MEDIUM = u'1297211435_error.png' PICTURE_UNKNOWN_SMALL = u'1299549572_unknown2.png' PICTURE_UNKNOWN_MEDIUM = u'1299549805_unknown.png' -document_namespace = PermissionNamespace('documents', _(u'Documents')) - -PERMISSION_DOCUMENT_CREATE = Permission.objects.register(document_namespace, 'document_create', _(u'Create documents')) -PERMISSION_DOCUMENT_PROPERTIES_EDIT = Permission.objects.register(document_namespace, 'document_properties_edit', _(u'Edit document properties')) -PERMISSION_DOCUMENT_EDIT = Permission.objects.register(document_namespace, 'document_edit', _(u'Edit documents')) -PERMISSION_DOCUMENT_VIEW = Permission.objects.register(document_namespace, 'document_view', _(u'View documents')) -PERMISSION_DOCUMENT_DELETE = Permission.objects.register(document_namespace, 'document_delete', _(u'Delete documents')) -PERMISSION_DOCUMENT_DOWNLOAD = Permission.objects.register(document_namespace, 'document_download', _(u'Download documents')) -PERMISSION_DOCUMENT_TRANSFORM = Permission.objects.register(document_namespace, 'document_transform', _(u'Transform documents')) -PERMISSION_DOCUMENT_TOOLS = Permission.objects.register(document_namespace, 'document_tools', _(u'Execute document modifying tools')) -PERMISSION_DOCUMENT_VERSION_REVERT = Permission.objects.register(document_namespace, 'document_version_revert', _(u'Revert documents to a previous version')) - -documents_setup_namespace = PermissionNamespace('documents_setup', _(u'Documents setup')) - -PERMISSION_DOCUMENT_TYPE_VIEW = Permission.objects.register(documents_setup_namespace, 'document_type_view', _(u'View document types')) -PERMISSION_DOCUMENT_TYPE_EDIT = Permission.objects.register(documents_setup_namespace, 'document_type_edit', _(u'Edit document types')) -PERMISSION_DOCUMENT_TYPE_DELETE = Permission.objects.register(documents_setup_namespace, 'document_type_delete', _(u'Delete document types')) -PERMISSION_DOCUMENT_TYPE_CREATE = Permission.objects.register(documents_setup_namespace, 'document_type_create', _(u'Create document types')) - - HISTORY_DOCUMENT_CREATED = { 'namespace': 'documents', 'name': 'document_created', 'label': _(u'Document creation'), diff --git a/apps/documents/managers.py b/apps/documents/managers.py index bdc62ddd72..8c07b5ec54 100644 --- a/apps/documents/managers.py +++ b/apps/documents/managers.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import + from ast import literal_eval from datetime import datetime from django.db import models -from documents.conf.settings import RECENT_COUNT +from .conf.settings import RECENT_COUNT class RecentDocumentManager(models.Manager): diff --git a/apps/documents/models.py b/apps/documents/models.py index 2255d487fe..713132db62 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import os import tempfile import hashlib @@ -27,18 +29,13 @@ from mimetype.api import (get_mimetype, get_icon_file_path, from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_PAGE_NUMBER) -from documents.conf.settings import CHECKSUM_FUNCTION -from documents.conf.settings import UUID_FUNCTION -from documents.conf.settings import STORAGE_BACKEND -from documents.conf.settings import PREVIEW_SIZE -from documents.conf.settings import DISPLAY_SIZE -from documents.conf.settings import CACHE_PATH -from documents.conf.settings import ZOOM_MAX_LEVEL -from documents.conf.settings import ZOOM_MIN_LEVEL -from documents.managers import RecentDocumentManager, \ - DocumentPageTransformationManager -from documents.utils import document_save_to_temp_dir -from documents.literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES, +from .conf.settings import (CHECKSUM_FUNCTION, UUID_FUNCTION, + STORAGE_BACKEND, PREVIEW_SIZE, DISPLAY_SIZE, CACHE_PATH, + ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL) +from .managers import (RecentDocumentManager, + DocumentPageTransformationManager) +from .utils import document_save_to_temp_dir +from .literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES, VERSION_UPDATE_MAJOR, VERSION_UPDATE_MINOR, VERSION_UPDATE_MICRO) # document image cache name hash function diff --git a/apps/documents/permissions.py b/apps/documents/permissions.py new file mode 100644 index 0000000000..4dc1657570 --- /dev/null +++ b/apps/documents/permissions.py @@ -0,0 +1,24 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +document_namespace = PermissionNamespace('documents', _(u'Documents')) + +PERMISSION_DOCUMENT_CREATE = Permission.objects.register(document_namespace, 'document_create', _(u'Create documents')) +PERMISSION_DOCUMENT_PROPERTIES_EDIT = Permission.objects.register(document_namespace, 'document_properties_edit', _(u'Edit document properties')) +PERMISSION_DOCUMENT_EDIT = Permission.objects.register(document_namespace, 'document_edit', _(u'Edit documents')) +PERMISSION_DOCUMENT_VIEW = Permission.objects.register(document_namespace, 'document_view', _(u'View documents')) +PERMISSION_DOCUMENT_DELETE = Permission.objects.register(document_namespace, 'document_delete', _(u'Delete documents')) +PERMISSION_DOCUMENT_DOWNLOAD = Permission.objects.register(document_namespace, 'document_download', _(u'Download documents')) +PERMISSION_DOCUMENT_TRANSFORM = Permission.objects.register(document_namespace, 'document_transform', _(u'Transform documents')) +PERMISSION_DOCUMENT_TOOLS = Permission.objects.register(document_namespace, 'document_tools', _(u'Execute document modifying tools')) +PERMISSION_DOCUMENT_VERSION_REVERT = Permission.objects.register(document_namespace, 'document_version_revert', _(u'Revert documents to a previous version')) + +documents_setup_namespace = PermissionNamespace('documents_setup', _(u'Documents setup')) + +PERMISSION_DOCUMENT_TYPE_VIEW = Permission.objects.register(documents_setup_namespace, 'document_type_view', _(u'View document types')) +PERMISSION_DOCUMENT_TYPE_EDIT = Permission.objects.register(documents_setup_namespace, 'document_type_edit', _(u'Edit document types')) +PERMISSION_DOCUMENT_TYPE_DELETE = Permission.objects.register(documents_setup_namespace, 'document_type_delete', _(u'Delete document types')) +PERMISSION_DOCUMENT_TYPE_CREATE = Permission.objects.register(documents_setup_namespace, 'document_type_create', _(u'Create document types')) diff --git a/apps/documents/statistics.py b/apps/documents/statistics.py index 8787c7eb22..508d699a49 100644 --- a/apps/documents/statistics.py +++ b/apps/documents/statistics.py @@ -1,10 +1,12 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ +from django.db.models import Avg, Count, Min, Max from common.utils import pretty_size, pretty_size_10 -from documents.conf.settings import STORAGE_BACKEND -from documents.models import Document, DocumentType, DocumentPage, DocumentVersion -from django.db.models import Avg, Count, Min, Max +from .conf.settings import STORAGE_BACKEND +from .models import Document, DocumentType, DocumentPage, DocumentVersion def get_used_size(path, file_list): diff --git a/apps/documents/tests.py b/apps/documents/tests.py index 72da245be4..8f03074fa6 100644 --- a/apps/documents/tests.py +++ b/apps/documents/tests.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import os from django.utils import unittest diff --git a/apps/documents/urls.py b/apps/documents/urls.py index 14193c1d8a..8818543380 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -1,10 +1,9 @@ +from __future__ import absolute_import + from django.conf.urls.defaults import patterns, url -from documents.conf.settings import PREVIEW_SIZE -from documents.conf.settings import PRINT_SIZE -from documents.conf.settings import THUMBNAIL_SIZE -from documents.conf.settings import DISPLAY_SIZE -from documents.conf.settings import MULTIPAGE_PREVIEW_SIZE +from .conf.settings import (PREVIEW_SIZE, PRINT_SIZE, THUMBNAIL_SIZE, + DISPLAY_SIZE, MULTIPAGE_PREVIEW_SIZE) urlpatterns = patterns('documents.views', url(r'^list/$', 'document_list', (), 'document_list'), diff --git a/apps/documents/views.py b/apps/documents/views.py index 1c2acaef97..5bb4266a35 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import urlparse import copy import logging @@ -29,41 +31,30 @@ from document_indexing.api import update_indexes, delete_indexes from history.api import create_history from acls.models import AccessEntry, PermissionDenied -from documents.conf.settings import PREVIEW_SIZE -from documents.conf.settings import STORAGE_BACKEND -from documents.conf.settings import ZOOM_PERCENT_STEP -from documents.conf.settings import ZOOM_MAX_LEVEL -from documents.conf.settings import ZOOM_MIN_LEVEL -from documents.conf.settings import ROTATION_STEP -from documents.conf.settings import PRINT_SIZE -from documents.conf.settings import RECENT_COUNT - -from documents.literals import (PERMISSION_DOCUMENT_CREATE, - PERMISSION_DOCUMENT_PROPERTIES_EDIT, - PERMISSION_DOCUMENT_VIEW, +from .conf.settings import (PREVIEW_SIZE, STORAGE_BACKEND, ZOOM_PERCENT_STEP, + ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL, ROTATION_STEP, PRINT_SIZE, + RECENT_COUNT) +from .permissions import (PERMISSION_DOCUMENT_CREATE, + PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, - PERMISSION_DOCUMENT_TRANSFORM, - PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_TOOLS, - PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_TYPE_VIEW) -from documents.literals import (HISTORY_DOCUMENT_CREATED, + PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS, + PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT, + PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE, + PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW) +from .literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) - -from documents.forms import (DocumentTypeSelectForm, +from .forms import (DocumentTypeSelectForm, DocumentForm_edit, DocumentPropertiesForm, DocumentPreviewForm, DocumentPageForm, DocumentPageTransformationForm, DocumentContentForm, DocumentPageForm_edit, DocumentPageForm_text, PrintForm, DocumentTypeForm, DocumentTypeFilenameForm, DocumentTypeFilenameForm_create) -from documents.wizards import DocumentCreateWizard -from documents.models import (Document, DocumentType, DocumentPage, +from .wizards import DocumentCreateWizard +from .models import (Document, DocumentType, DocumentPage, DocumentPageTransformation, RecentDocument, DocumentTypeFilename, DocumentVersion) -# Document type permissions -from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT, \ - PERMISSION_DOCUMENT_TYPE_DELETE, PERMISSION_DOCUMENT_TYPE_CREATE - logger = logging.getLogger(__name__) diff --git a/apps/documents/widgets.py b/apps/documents/widgets.py index 031461047f..0bd9ce473e 100644 --- a/apps/documents/widgets.py +++ b/apps/documents/widgets.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.safestring import mark_safe from django.conf import settings from django.utils.translation import ugettext_lazy as _ @@ -9,7 +11,7 @@ from converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, \ from converter.exceptions import UnknownFileFormat, UnkownConvertError from mimetype.api import get_error_icon_url -from documents.conf.settings import DISPLAY_SIZE +from .conf.settings import DISPLAY_SIZE def document_thumbnail(document): diff --git a/apps/documents/wizards.py b/apps/documents/wizards.py index a61ba4960a..d78252dfd7 100644 --- a/apps/documents/wizards.py +++ b/apps/documents/wizards.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect @@ -7,7 +9,7 @@ from common.utils import urlquote from metadata.forms import MetadataSelectionForm, MetadataFormSet -from documents.forms import DocumentTypeSelectForm +from .forms import DocumentTypeSelectForm class DocumentCreateWizard(BoundFormWizard): diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 0f8cb64a3c..5c894224be 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from navigation.api import (register_links, register_top_menu, register_multi_item_links, register_sidebar_template) from documents.models import Document -from documents.literals import PERMISSION_DOCUMENT_VIEW +from documents.permissions import PERMISSION_DOCUMENT_VIEW from acls.models import class_permissions from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL diff --git a/apps/folders/admin.py b/apps/folders/admin.py index 8304db276d..f558ec7922 100644 --- a/apps/folders/admin.py +++ b/apps/folders/admin.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from django.contrib import admin -from folders.models import Folder, FolderDocument +from .models import Folder, FolderDocument class FolderDocumentInline(admin.StackedInline): diff --git a/apps/folders/forms.py b/apps/folders/forms.py index a199b14d9e..0c3ef6a13e 100644 --- a/apps/folders/forms.py +++ b/apps/folders/forms.py @@ -1,7 +1,9 @@ +from __future__ import absolute_import + from django import forms from django.utils.translation import ugettext_lazy as _ -from folders.models import Folder +from .models import Folder class FolderForm(forms.ModelForm): diff --git a/apps/folders/views.py b/apps/folders/views.py index 6b3cdde802..be7373b5cb 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -1,4 +1,5 @@ from __future__ import absolute_import + import logging from django.utils.translation import ugettext_lazy as _ @@ -10,7 +11,7 @@ from django.views.generic.list_detail import object_list from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied -from documents.literals import PERMISSION_DOCUMENT_VIEW +from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list from permissions import Permission diff --git a/apps/history/__init__.py b/apps/history/__init__.py index 5ae801fa03..7e5999508a 100644 --- a/apps/history/__init__.py +++ b/apps/history/__init__.py @@ -1,11 +1,10 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from project_tools.api import register_tool -from permissions.models import PermissionNamespace, Permission -history_namespace = PermissionNamespace('history', _(u'History')) - -PERMISSION_HISTORY_VIEW = Permission.objects.register(history_namespace, 'history_view', _(u'Access the history app')) +from .permissions import PERMISSION_HISTORY_VIEW # TODO: support permissions AND operand # encapsulate into document_history_list and require DOCUMENT_VIEW and HISTORY_VIEW diff --git a/apps/history/api.py b/apps/history/api.py index 467f4c8035..03db0f15d4 100644 --- a/apps/history/api.py +++ b/apps/history/api.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import pickle import json @@ -14,8 +16,8 @@ from django.core import serializers from django.shortcuts import get_object_or_404 from django.db import models -from history.models import HistoryType, History -from history.runtime_data import history_types_dict +from .models import HistoryType, History +from .runtime_data import history_types_dict @transaction.commit_manually diff --git a/apps/history/forms.py b/apps/history/forms.py index 3cad7395d3..bac7cb503c 100644 --- a/apps/history/forms.py +++ b/apps/history/forms.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from common.forms import DetailForm -from history.models import History +from .models import History class HistoryDetailForm(DetailForm): diff --git a/apps/history/models.py b/apps/history/models.py index b45a77091b..82d289594f 100644 --- a/apps/history/models.py +++ b/apps/history/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import json import pickle from datetime import datetime @@ -9,7 +11,7 @@ from django.utils.translation import ugettext_lazy as _ from django.core import serializers #from history.managers import HistoryManager -from history.runtime_data import history_types_dict +from .runtime_data import history_types_dict class HistoryType(models.Model): diff --git a/apps/history/permissions.py b/apps/history/permissions.py new file mode 100644 index 0000000000..4d7b37a1eb --- /dev/null +++ b/apps/history/permissions.py @@ -0,0 +1,9 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +history_namespace = PermissionNamespace('history', _(u'History')) + +PERMISSION_HISTORY_VIEW = Permission.objects.register(history_namespace, 'history_view', _(u'Access the history app')) diff --git a/apps/history/views.py b/apps/history/views.py index dd78079e69..ffd85e7e68 100644 --- a/apps/history/views.py +++ b/apps/history/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 _ @@ -9,10 +11,10 @@ from django.http import Http404 from permissions.models import Permission from common.utils import encapsulate -from history.models import History -from history.forms import HistoryDetailForm -from history import PERMISSION_HISTORY_VIEW -from history.widgets import history_entry_object_link, history_entry_summary +from .models import History +from .forms import HistoryDetailForm +from .permissions import PERMISSION_HISTORY_VIEW +from .widgets import history_entry_object_link, history_entry_summary def history_list(request): diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index 63895ab171..73e4b1cecb 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -3,21 +3,16 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_sidebar_template -from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup -from documents.literals import PERMISSION_DOCUMENT_VIEW +from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document from acls.models import class_permissions from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL from .models import SmartLink, SmartLinkCondition - -linking_namespace = PermissionNamespace('linking', _(u'Smart links')) - -PERMISSION_SMART_LINK_VIEW = Permission.objects.register(linking_namespace, 'smart_link_view', _(u'View existing smart links')) -PERMISSION_SMART_LINK_CREATE = Permission.objects.register(linking_namespace, 'smart_link_create', _(u'Create new smart links')) -PERMISSION_SMART_LINK_DELETE = Permission.objects.register(linking_namespace, 'smart_link_delete', _(u'Delete smart links')) -PERMISSION_SMART_LINK_EDIT = Permission.objects.register(linking_namespace, 'smart_link_edit', _(u'Edit smart links')) +from .permissions import (PERMISSION_SMART_LINK_VIEW, + PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_DELETE, + PERMISSION_SMART_LINK_EDIT) smart_link_instance_view_link = {'text': _(u'smart links actions'), 'view': 'smart_link_instance_view', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} smart_link_instances_for_document = {'text': _(u'smart links'), 'view': 'smart_link_instances_for_document', 'args': 'object.pk', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} diff --git a/apps/linking/models.py b/apps/linking/models.py index 18b145b936..2c75642c9e 100644 --- a/apps/linking/models.py +++ b/apps/linking/models.py @@ -4,8 +4,8 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from .managers import SmartLinkManager -from .literals import OPERATOR_CHOICES, INCLUSION_AND, \ - INCLUSION_CHOICES +from .literals import (OPERATOR_CHOICES, INCLUSION_AND, + INCLUSION_CHOICES) class SmartLink(models.Model): diff --git a/apps/linking/permissions.py b/apps/linking/permissions.py new file mode 100644 index 0000000000..c9b889b084 --- /dev/null +++ b/apps/linking/permissions.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +linking_namespace = PermissionNamespace('linking', _(u'Smart links')) + +PERMISSION_SMART_LINK_VIEW = Permission.objects.register(linking_namespace, 'smart_link_view', _(u'View existing smart links')) +PERMISSION_SMART_LINK_CREATE = Permission.objects.register(linking_namespace, 'smart_link_create', _(u'Create new smart links')) +PERMISSION_SMART_LINK_DELETE = Permission.objects.register(linking_namespace, 'smart_link_delete', _(u'Delete smart links')) +PERMISSION_SMART_LINK_EDIT = Permission.objects.register(linking_namespace, 'smart_link_edit', _(u'Edit smart links')) diff --git a/apps/linking/views.py b/apps/linking/views.py index 2e5d72a626..7aacd67a66 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -1,4 +1,5 @@ -from __future__ import absolute_import +from __future__ import absolute_import + import logging from django.utils.translation import ugettext_lazy as _ @@ -12,7 +13,7 @@ from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template from documents.models import Document from documents.views import document_list -from documents.literals import PERMISSION_DOCUMENT_VIEW +from documents.permissions import PERMISSION_DOCUMENT_VIEW from permissions.models import Permission from acls.views import acl_new_holder_for, acl_list_for, acl_detail_for from acls.models import AccessEntry, PermissionDenied @@ -22,7 +23,7 @@ from .conf.settings import SHOW_EMPTY_SMART_LINKS from .forms import (SmartLinkInstanceForm, SmartLinkForm, SmartLinkConditionForm) from . import smart_link_instance_view_link -from . import (PERMISSION_SMART_LINK_VIEW, +from .permissions import (PERMISSION_SMART_LINK_VIEW, PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_DELETE, PERMISSION_SMART_LINK_EDIT) diff --git a/apps/lock_manager/__init__.py b/apps/lock_manager/__init__.py index 34913f856f..61fe7fbf78 100644 --- a/apps/lock_manager/__init__.py +++ b/apps/lock_manager/__init__.py @@ -1,4 +1,6 @@ -from lock_manager.exceptions import LockError -from lock_manager.models import Lock as LockModel +from __future__ import absolute_import + +from .exceptions import LockError +from .models import Lock as LockModel Lock = LockModel.objects diff --git a/apps/lock_manager/admin.py b/apps/lock_manager/admin.py index 12dbee8fe1..d8c353e7e3 100644 --- a/apps/lock_manager/admin.py +++ b/apps/lock_manager/admin.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from django.contrib import admin -from lock_manager.models import Lock +from .models import Lock class LockAdmin(admin.ModelAdmin): diff --git a/apps/lock_manager/managers.py b/apps/lock_manager/managers.py index f356be42dd..f5613110f4 100644 --- a/apps/lock_manager/managers.py +++ b/apps/lock_manager/managers.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import logging import datetime @@ -6,7 +8,7 @@ from django.db.utils import IntegrityError from django.db import transaction from django.db import models -from lock_manager.exceptions import LockError +from .exceptions import LockError logger = logging.getLogger(__name__) diff --git a/apps/lock_manager/models.py b/apps/lock_manager/models.py index 535d3366a6..25188380c7 100644 --- a/apps/lock_manager/models.py +++ b/apps/lock_manager/models.py @@ -1,10 +1,12 @@ +from __future__ import absolute_import + import datetime from django.db import models from django.utils.translation import ugettext_lazy as _ -from lock_manager.managers import LockManager -from lock_manager.conf.settings import DEFAULT_LOCK_TIMEOUT +from .managers import LockManager +from .conf.settings import DEFAULT_LOCK_TIMEOUT class Lock(models.Model): diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 822a2c8cfa..6da73f8a40 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from navigation.api import register_top_menu @@ -5,8 +7,7 @@ from navigation.api import register_links from project_setup.api import register_setup from project_tools.api import register_tool -from main.conf.settings import SIDE_BAR_SEARCH -from main.conf.settings import DISABLE_HOME_VIEW +from .conf.settings import SIDE_BAR_SEARCH, DISABLE_HOME_VIEW __author__ = 'Roberto Rosario' __copyright__ = 'Copyright 2011 Roberto Rosario' @@ -24,10 +25,10 @@ __version_info__ = { 'serial': 0 } + def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser - maintenance_menu = {'text': _(u'maintenance'), 'view': 'maintenance_menu', 'famfam': 'wrench', 'icon': 'wrench.png'} statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png'} diagnostics = {'text': _(u'diagnostics'), 'view': 'diagnostics', 'famfam': 'pill', 'icon': 'pill.png'} @@ -52,7 +53,6 @@ def get_version(): vers.append('%(releaselevel)s%(serial)i' % __version_info__) return ''.join(vers) - __version__ = get_version() register_setup(admin_site) diff --git a/apps/main/views.py b/apps/main/views.py index e4205b5f38..316b4b6e6d 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 _ @@ -9,8 +11,8 @@ from documents.statistics import get_statistics as documents_statistics from ocr.statistics import get_statistics as ocr_statistics 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): diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index af514ca648..60439c2924 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -1,31 +1,22 @@ +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.models import Permission, PermissionNamespace 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.models import class_permissions -from metadata.models import MetadataType, MetadataSet - -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')) +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']} @@ -47,9 +38,8 @@ setup_metadata_set_create = {'text': _(u'create new'), 'view': 'setup_metadata_s 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]) @@ -69,7 +59,6 @@ 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, diff --git a/apps/metadata/admin.py b/apps/metadata/admin.py index ac32bdc131..53ca6f69cd 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..3473cf5bd0 100644 --- a/apps/metadata/api.py +++ b/apps/metadata/api.py @@ -1,14 +1,17 @@ -"""Metadata handling commonalities""" +'''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': {} @@ -32,19 +35,19 @@ def decode_metadata_from_url(url_dict): def save_metadata_list(metadata_list, document, create=False): - """ + ''' Take a list of metadata dictionaries and associate them to a document - """ + ''' for item in metadata_list: save_metadata(item, document, create) def save_metadata(metadata_dict, document, create=False): - """ + ''' Take a dictionary of metadata type & value and associate it to a document - """ + ''' if create: # Use matched metadata now to create document metadata document_metadata, created = DocumentMetadata.objects.get_or_create( @@ -78,14 +81,16 @@ 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)) def metadata_repr_as_list(metadata_list): - """ + ''' Turn a list of metadata into a list of printable representations - """ + ''' output = [] for metadata_dict in metadata_list: try: @@ -98,7 +103,7 @@ def metadata_repr_as_list(metadata_list): 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')]) diff --git a/apps/metadata/forms.py b/apps/metadata/forms.py index ce921ee47c..0653880301 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/models.py b/apps/metadata/models.py index 8b3d6463ea..d827b615e5 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'' diff --git a/apps/metadata/permissions.py b/apps/metadata/permissions.py new file mode 100644 index 0000000000..5ed8f9cb43 --- /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/views.py b/apps/metadata/views.py index 11aa0a6b87..101192e1e9 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 _ @@ -7,7 +9,7 @@ from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from django.utils.http import urlencode -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.models import Permission from document_indexing.api import update_indexes, delete_indexes @@ -15,18 +17,18 @@ from document_indexing.api import update_indexes, delete_indexes from common.utils import generate_choices_w_labels, encapsulate 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) def metadata_edit(request, document_id=None, document_id_list=None): diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 81dd819c13..d29600c978 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -3,15 +3,15 @@ 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.api import (object_navigation, multi_object_navigation, + top_menu_entries, sidebar_templates) from navigation.forms import MultiItemForm from navigation.utils import resolve_to_name diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 052b228821..403202b49f 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import logging from django.db import transaction @@ -14,21 +16,15 @@ from project_tools.api import register_tool 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 .conf.settings import (AUTOMATIC_OCR, QUEUE_PROCESSING_INTERVAL) +from .models import DocumentQueue, QueueTransformation, QueueDocument +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, PERMISSION_OCR_QUEUE_EDIT) logger = logging.getLogger(__name__) -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')) - #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]} 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/managers.py b/apps/ocr/managers.py index a1fdb80b8c..13c98ece27 100644 --- a/apps/ocr/managers.py +++ b/apps/ocr/managers.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from django.db import models -from ocr.exceptions import AlreadyQueued +from .exceptions import AlreadyQueued class DocumentQueueManager(models.Manager): diff --git a/apps/ocr/models.py b/apps/ocr/models.py index f33ee3fb35..4457c3683d 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): diff --git a/apps/ocr/permissions.py b/apps/ocr/permissions.py new file mode 100644 index 0000000000..fefb6843ce --- /dev/null +++ b/apps/ocr/permissions.py @@ -0,0 +1,13 @@ +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..14c0ce5152 100644 --- a/apps/ocr/tasks.py +++ b/apps/ocr/tasks.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from datetime import timedelta, datetime import platform from time import sleep @@ -9,15 +11,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, + CACHE_URI, QUEUE_PROCESSING_INTERVAL) LOCK_EXPIRE = 60 * 10 # Lock expires in 10 minutes # TODO: Tie LOCK_EXPIRATION with hard task timeout diff --git a/apps/ocr/views.py b/apps/ocr/views.py index 26c030970f..6c37f62ce0 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import socket from django.http import HttpResponseRedirect @@ -14,17 +16,16 @@ from documents.models import Document from documents.widgets import document_link, document_thumbnail from common.utils import encapsulate -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'): diff --git a/apps/permissions/__init__.py b/apps/permissions/__init__.py index 8099230638..77f5c6119e 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,11 @@ 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, 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')) +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) role_list = {'text': _(u'roles'), 'view': 'role_list', 'famfam': 'medal_gold_1', 'icon': 'medal_gold_1.png', 'permissions': [PERMISSION_ROLE_VIEW]} role_create = {'text': _(u'create new role'), 'view': 'role_create', 'famfam': 'medal_gold_add', 'permissions': [PERMISSION_ROLE_CREATE]} diff --git a/apps/permissions/admin.py b/apps/permissions/admin.py index b20d75331c..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 StoredPermission, PermissionHolder, Role, RoleMember +from .models import StoredPermission, PermissionHolder, Role, RoleMember class PermissionHolderInline(admin.StackedInline): 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/models.py b/apps/permissions/models.py index 6e1a7cafe5..744703f1c3 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import logging from django.db import models @@ -8,7 +10,7 @@ from django.contrib.contenttypes import generic from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied -from permissions.managers import (RoleMemberManager, StoredPermissionManager) +from .managers import (RoleMemberManager, StoredPermissionManager) logger = logging.getLogger(__name__) 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/views.py b/apps/permissions/views.py index 3e4cbd4e74..d1fa7c7d04 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import operator import itertools @@ -17,12 +19,12 @@ from common.views import assign_remove from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template -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.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): 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/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/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/smart_settings/views.py b/apps/smart_settings/views.py index e4d1b4d75a..2db39a143e 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): diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 6fb37090f1..8fc456eef5 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, \ @@ -6,22 +8,16 @@ from permissions.models import Permission, PermissionNamespace 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_CREATE from acls.models import class_permissions -from sources.staging import StagingFile -from sources.models import WebForm, StagingFolder, SourceTransformation, \ - WatchFolder -from sources.widgets import staging_file_thumbnail - -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')) - -sources_namespace = PermissionNamespace('sources', _(u'Sources')) -PERMISSION_DOCUMENT_NEW_VERSION = Permission.objects.register(sources_namespace, 'sources_document_new_version', _(u'Create new document version')) +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, PERMISSION_DOCUMENT_NEW_VERSION) 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} @@ -77,7 +73,6 @@ register_model_list_columns(StagingFile, [ }, ]) - register_setup(setup_sources) class_permissions(Document, [ 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..259f900062 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): diff --git a/apps/sources/models.py b/apps/sources/models.py index 3d09915617..6a00a8546f 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from ast import literal_eval from django.db import models @@ -16,13 +18,13 @@ from metadata.models import MetadataType from metadata.api import save_metadata_list from scheduler.api import register_interval_job, remove_job -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 class BaseModel(models.Model): diff --git a/apps/sources/permissions.py b/apps/sources/permissions.py new file mode 100644 index 0000000000..119a366e11 --- /dev/null +++ b/apps/sources/permissions.py @@ -0,0 +1,14 @@ +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')) + +sources_namespace = PermissionNamespace('sources', _(u'Sources')) +PERMISSION_DOCUMENT_NEW_VERSION = Permission.objects.register(sources_namespace, 'sources_document_new_version', _(u'Create new document version')) diff --git a/apps/sources/staging.py b/apps/sources/staging.py index 774bc01db8..ca8c92be9e 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 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/views.py b/apps/sources/views.py index b0701cfece..290c467108 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 @@ -8,7 +10,7 @@ from django.utils.translation import ugettext from django.utils.safestring import mark_safe from django.conf import settings -from documents.literals import PERMISSION_DOCUMENT_CREATE +from documents.permissions import PERMISSION_DOCUMENT_CREATE 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 @@ -17,18 +19,18 @@ from common.utils import encapsulate import sendfile from acls.models import AccessEntry, PermissionDenied -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.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.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, +from .permissions import (PERMISSION_SOURCES_SETUP_VIEW, PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE, PERMISSION_SOURCES_SETUP_CREATE, PERMISSION_DOCUMENT_NEW_VERSION) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index f4f0adad7d..c730620b3b 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -1,8 +1,9 @@ +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.models import PermissionNamespace, Permission +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.models import class_permissions @@ -10,16 +11,10 @@ from acls.models import class_permissions from taggit.models import Tag from taggit.managers import TaggableManager -from tags.widgets import tag_color_block - -tags_namespace = PermissionNamespace('tags', _(u'Tags')) - -PERMISSION_TAG_CREATE = Permission.objects.register(tags_namespace, 'tag_create', _(u'Create new tags')) -PERMISSION_TAG_ATTACH = Permission.objects.register(tags_namespace, 'tag_attach', _(u'Attach exising tags')) -PERMISSION_TAG_REMOVE = Permission.objects.register(tags_namespace, 'tag_remove', _(u'Remove tags from documents')) -PERMISSION_TAG_DELETE = Permission.objects.register(tags_namespace, 'tag_delete', _(u'Delete global tags')) -PERMISSION_TAG_EDIT = Permission.objects.register(tags_namespace, 'tag_edit', _(u'Edit global tags')) -PERMISSION_TAG_VIEW = Permission.objects.register(tags_namespace, 'tag_view', _(u'View a document\'s tags')) +from .widgets import tag_color_block +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'} diff --git a/apps/tags/admin.py b/apps/tags/admin.py index 495fc03066..0ba921af19 100644 --- a/apps/tags/admin.py +++ b/apps/tags/admin.py @@ -1,6 +1,8 @@ +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..01a210494a 100644 --- a/apps/tags/forms.py +++ b/apps/tags/forms.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import + from django import forms from django.utils.translation import ugettext_lazy as _ from taggit.models import Tag -from models import COLOR_CHOICES +from .models import COLOR_CHOICES class AddTagForm(forms.Form): diff --git a/apps/tags/permissions.py b/apps/tags/permissions.py new file mode 100644 index 0000000000..4dc7499222 --- /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_ATTACH = Permission.objects.register(tags_namespace, 'tag_attach', _(u'Attach exising tags')) +PERMISSION_TAG_REMOVE = Permission.objects.register(tags_namespace, 'tag_remove', _(u'Remove tags from documents')) +PERMISSION_TAG_DELETE = Permission.objects.register(tags_namespace, 'tag_delete', _(u'Delete global tags')) +PERMISSION_TAG_EDIT = Permission.objects.register(tags_namespace, 'tag_edit', _(u'Edit global tags')) +PERMISSION_TAG_VIEW = Permission.objects.register(tags_namespace, 'tag_view', _(u'View a document\'s tags')) diff --git a/apps/tags/utils.py b/apps/tags/utils.py index 9496d9e88e..476b5bd17a 100644 --- a/apps/tags/utils.py +++ b/apps/tags/utils.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ -from tags import tag_document_remove, tag_tagged_item_list +from . import tag_document_remove, tag_tagged_item_list def get_tags_subtemplate(obj): diff --git a/apps/tags/views.py b/apps/tags/views.py index 94fd2ff170..12dba9dea9 100644 --- a/apps/tags/views.py +++ b/apps/tags/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 @@ -11,12 +13,12 @@ from documents.models import Document from documents.views import document_list from common.utils import encapsulate -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 AddTagForm, 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) +from . import tag_tagged_item_list as tag_tagged_item_list_link def tag_create(request): diff --git a/apps/user_management/__init__.py b/apps/user_management/__init__.py index e5dbf82d51..133f60df71 100644 --- a/apps/user_management/__init__.py +++ b/apps/user_management/__init__.py @@ -1,22 +1,14 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group from navigation.api import register_links, register_multi_item_links -from permissions.models import PermissionNamespace, Permission - from project_setup.api import register_setup -user_management_namespace = PermissionNamespace('user_management', _(u'User management')) - -PERMISSION_USER_CREATE = Permission.objects.register(user_management_namespace, 'user_create', _(u'Create new users')) -PERMISSION_USER_EDIT = Permission.objects.register(user_management_namespace, 'user_edit', _(u'Edit existing users')) -PERMISSION_USER_VIEW = Permission.objects.register(user_management_namespace, 'user_view', _(u'View existing users')) -PERMISSION_USER_DELETE = Permission.objects.register(user_management_namespace, 'user_delete', _(u'Delete existing users')) - -PERMISSION_GROUP_CREATE = Permission.objects.register(user_management_namespace, 'group_create', _(u'Create new groups')) -PERMISSION_GROUP_EDIT = Permission.objects.register(user_management_namespace, 'group_edit', _(u'Edit existing groups')) -PERMISSION_GROUP_VIEW = Permission.objects.register(user_management_namespace, 'group_view', _(u'View existing groups')) -PERMISSION_GROUP_DELETE = Permission.objects.register(user_management_namespace, 'group_delete', _(u'Delete existing groups')) +from .permissions import (PERMISSION_USER_CREATE, PERMISSION_USER_EDIT, + PERMISSION_USER_VIEW, PERMISSION_USER_DELETE, PERMISSION_GROUP_CREATE, + PERMISSION_GROUP_EDIT, PERMISSION_GROUP_VIEW, PERMISSION_GROUP_DELETE) user_list = {'text': _(u'user list'), 'view': 'user_list', 'famfam': 'user', 'permissions': [PERMISSION_USER_VIEW]} user_setup = {'text': _(u'users'), 'view': 'user_list', 'famfam': 'user', 'icon': 'user.png', 'permissions': [PERMISSION_USER_VIEW]} diff --git a/apps/user_management/permissions.py b/apps/user_management/permissions.py new file mode 100644 index 0000000000..e644b1cb5e --- /dev/null +++ b/apps/user_management/permissions.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +user_management_namespace = PermissionNamespace('user_management', _(u'User management')) + +PERMISSION_USER_CREATE = Permission.objects.register(user_management_namespace, 'user_create', _(u'Create new users')) +PERMISSION_USER_EDIT = Permission.objects.register(user_management_namespace, 'user_edit', _(u'Edit existing users')) +PERMISSION_USER_VIEW = Permission.objects.register(user_management_namespace, 'user_view', _(u'View existing users')) +PERMISSION_USER_DELETE = Permission.objects.register(user_management_namespace, 'user_delete', _(u'Delete existing users')) + +PERMISSION_GROUP_CREATE = Permission.objects.register(user_management_namespace, 'group_create', _(u'Create new groups')) +PERMISSION_GROUP_EDIT = Permission.objects.register(user_management_namespace, 'group_edit', _(u'Edit existing groups')) +PERMISSION_GROUP_VIEW = Permission.objects.register(user_management_namespace, 'group_view', _(u'View existing groups')) +PERMISSION_GROUP_DELETE = Permission.objects.register(user_management_namespace, 'group_delete', _(u'Delete existing groups')) diff --git a/apps/user_management/views.py b/apps/user_management/views.py index e5167dfef5..f859a6940f 100644 --- a/apps/user_management/views.py +++ b/apps/user_management/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect from django.shortcuts import render_to_response, get_object_or_404 @@ -12,12 +14,10 @@ from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template from common.views import assign_remove -from user_management import PERMISSION_USER_VIEW, \ - PERMISSION_USER_EDIT, PERMISSION_USER_CREATE, \ - PERMISSION_USER_DELETE, PERMISSION_GROUP_CREATE, \ - PERMISSION_GROUP_EDIT, PERMISSION_GROUP_VIEW, \ - PERMISSION_GROUP_DELETE -from user_management.forms import UserForm, PasswordForm, GroupForm +from .permissions import (PERMISSION_USER_CREATE, PERMISSION_USER_EDIT, + PERMISSION_USER_VIEW, PERMISSION_USER_DELETE, PERMISSION_GROUP_CREATE, + PERMISSION_GROUP_EDIT, PERMISSION_GROUP_VIEW, PERMISSION_GROUP_DELETE) +from .forms import UserForm, PasswordForm, GroupForm def user_list(request): From 83551c9b909b1fa51838f06152418b05d1f5f090 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 03:49:19 -0400 Subject: [PATCH 132/484] Move django_gpg permissions to a separate file --- apps/django_gpg/permissions.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 apps/django_gpg/permissions.py diff --git a/apps/django_gpg/permissions.py b/apps/django_gpg/permissions.py new file mode 100644 index 0000000000..bfb486789f --- /dev/null +++ b/apps/django_gpg/permissions.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +django_gpg_namespace = PermissionNamespace('django_gpg', _(u'Key management')) + +PERMISSION_KEY_VIEW = Permission.objects.register(django_gpg_namespace, 'key_view', _(u'View keys')) +PERMISSION_KEY_DELETE = Permission.objects.register(django_gpg_namespace, 'key_delete', _(u'Delete keys')) +PERMISSION_KEYSERVER_QUERY = Permission.objects.register(django_gpg_namespace, 'keyserver_query', _(u'Query keyservers')) +PERMISSION_KEY_RECEIVE = Permission.objects.register(django_gpg_namespace, 'key_receive', _(u'Import keys from keyservers')) From b82aa2ccfc4bf537009844061233867fb97ec083 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:39:11 -0400 Subject: [PATCH 133/484] Update the acl app to use absolute imports, rename the acl_detail link text from edit to details, fix class default acl links permissions --- apps/acls/__init__.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index c5ba0faf6a..d0fe93931a 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -1,22 +1,17 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_multi_item_links -from permissions.models import PermissionNamespace, Permission from project_setup.api import register_setup -from acls.models import AccessHolder, AccessObjectClass, ClassAccessHolder +from .models import AccessHolder, AccessObjectClass, ClassAccessHolder +from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, + ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) -acls_namespace = PermissionNamespace('acls', _(u'Access control lists')) -acls_setup_namespace = PermissionNamespace('acls_setup', _(u'Access control lists')) - -ACLS_EDIT_ACL = Permission.objects.register(acls_namespace, 'acl_edit', _(u'Edit ACLs')) -ACLS_VIEW_ACL = Permission.objects.register(acls_namespace, 'acl_view', _(u'View ACLs')) - -ACLS_CLASS_EDIT_ACL = Permission.objects.register(acls_setup_namespace, 'acl_class_edit', _(u'Edit class default ACLs')) -ACLS_CLASS_VIEW_ACL = Permission.objects.register(acls_setup_namespace, 'acl_class_view', _(u'View class default ACLs')) acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -acl_detail = {'text': _(u'edit'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +acl_detail = {'text': _(u'details'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} @@ -25,8 +20,8 @@ acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classe acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} acls_class_acl_detail = {'text': _(u'edit'), 'view': 'acls_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} acl_class_new_holder_for = {'text': _(u'New holder'), 'view': 'acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user'}#, 'permissions': [ACLS_VIEW_ACL]} -acl_class_grant = {'text': _(u'grant'), 'view': 'acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} -acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} +acl_class_grant = {'text': _(u'grant'), 'view': 'acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_CLASS_EDIT_ACL]} +acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_CLASS_EDIT_ACL]} register_links(AccessHolder, [acl_detail]) register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) From 46c40ea7ba9e31f52fb290cb5b933de5a30d02f6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:40:15 -0400 Subject: [PATCH 134/484] Update acls app view module to use absolute importers, improve text formating so that ugettext doesn't complain --- apps/acls/views.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index 3cac1fbabe..b8db4f0fa5 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import logging import operator import itertools @@ -20,12 +22,12 @@ from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template -from acls import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, - ACLS_CLASS_VIEW_ACL) -from acls.models import (AccessEntry, AccessObject, AccessHolder, +from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, + ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) +from .models import (AccessEntry, AccessObject, AccessHolder, DefaultAccessEntry, AccessObjectClass, ClassAccessHolder) -from acls.widgets import object_w_content_type_icon -from acls.forms import HolderSelectionForm +from .widgets import object_w_content_type_icon +from .forms import HolderSelectionForm logger = logging.getLogger(__name__) @@ -95,7 +97,11 @@ def acl_detail_for(request, actor, obj, navigation_object=None): { 'name': u'generic_list_subtemplate.html', 'context': { - 'title': _(u'permissions available to: %s for %s' % (actor, obj)), + 'title': _(u'permissions available to: %(actor)s for %(obj)s' % { + 'actor': actor, + 'obj': obj + } + ), 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': 'namespace'}, @@ -402,7 +408,7 @@ def acl_class_acl_list(request, access_object_class_gid): def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL, ACLS_CLASS_EDIT_ACL]) try: - holder = AccessHolder.get(gid=holder_object_gid) + actor = AccessHolder.get(gid=holder_object_gid) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) except ObjectDoesNotExist: raise Http404 @@ -413,14 +419,18 @@ def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): { 'name': u'generic_list_subtemplate.html', 'context': { - 'title': _(u'permissions available to: %s for class %s' % (holder, access_object_class)), + 'title': _(u'permissions available to: %(actor)s for class %(class)s' % { + 'actor': actor, + 'class': access_object_class + } + ), 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': 'namespace'}, {'name': _(u'label'), 'attribute': 'label'}, { 'name':_(u'has permission'), - 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_access(x, holder.source_object, access_object_class.source_object))) + 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_access(x, actor.source_object, access_object_class.source_object))) }, ], #'hide_link': True, @@ -435,7 +445,7 @@ def acls_class_acl_detail(request, access_object_class_gid, holder_object_gid): 'multi_select_as_buttons': True, 'multi_select_item_properties': { 'permission_pk': lambda x: x.pk, - 'holder_gid': lambda x: holder.gid, + 'holder_gid': lambda x: actor.gid, 'access_object_class_gid': lambda x: access_object_class.gid, }, }, context_instance=RequestContext(request)) From 14ac963fcae7a115da96d401702c0ec1cfe1849b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:40:58 -0400 Subject: [PATCH 135/484] Update import type to use () instead of newline char --- apps/django_gpg/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index a52df7339a..558dae9371 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -2,9 +2,9 @@ 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, \ - register_sidebar_template +from navigation.api import (register_links, register_top_menu, + register_model_list_columns, register_multi_item_links, + register_sidebar_template) from main.api import register_diagnostic, register_maintenance_links from project_setup.api import register_setup from hkp import Key as KeyServerKey From 7a14cd1854eb2f36bb3f5142c554fd3b43ca388f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:41:30 -0400 Subject: [PATCH 136/484] Add the remove_document method to the Folder class --- apps/folders/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/folders/models.py b/apps/folders/models.py index f2a83ff32c..0f48eead9a 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -27,6 +27,10 @@ class Folder(models.Model): @property def documents(self): return [folder_document.document for folder_document in self.folderdocument_set.all()] + + def remove_document(self, document): + folder_document = self.folderdocument_set.get(document=document) + folder_document.delete() class Meta: unique_together = ('title', 'user') From e3f01cba81c8cae607b1bba2aee6d6574d1fa4a2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:41:55 -0400 Subject: [PATCH 137/484] Fix the folder document remove view --- apps/folders/views.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/folders/views.py b/apps/folders/views.py index be7373b5cb..feef2b21f1 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -239,25 +239,28 @@ def folder_document_remove(request, folder_id, document_id=None, document_id_lis folder = get_object_or_404(Folder, pk=folder_id) if document_id: - folder_documents = [get_object_or_404(FolderDocument, folder__pk=folder_id, document__pk=document_id)] + folder_documents = [get_object_or_404(Document, pk=document_id)] elif document_id_list: - folder_documents = [get_object_or_404(FolderDocument, folder__pk=folder_id, document__pk=document_id) for document_id in document_id_list.split(',')] + folder_documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] else: messages.error(request, _(u'Must provide at least one folder document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + logger.debug('folder_documents (pre permission check): %s' % folder_documents) try: Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_REMOVE_DOCUMENT]) except PermissionDenied: folder_documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_REMOVE_DOCUMENT, request.user, folder_documents, exception_on_empty=True) + logger.debug('folder_documents (post permission check): %s' % folder_documents) + 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', '/'))) if request.method == 'POST': for folder_document in folder_documents: try: - folder_document.delete() + folder.remove_document(folder_document) messages.success(request, _(u'Document: %s removed successfully.') % folder_document) except Exception, e: messages.error(request, _(u'Document: %(document)s delete error: %(error)s') % { @@ -273,12 +276,12 @@ def folder_document_remove(request, folder_id, document_id=None, document_id_lis 'object': folder } if len(folder_documents) == 1: - #context['object'] = folder_documents[0] + context['object'] = folder_documents[0] context['title'] = _(u'Are you sure you wish to remove the document: %(document)s from the folder "%(folder)s"?') % { - 'document': ', '.join([unicode(d) for d in folder_documents]), 'folder': folder_documents[0].folder} + 'document': ', '.join([unicode(d) for d in folder_documents]), 'folder': folder} elif len(folder_documents) > 1: context['title'] = _(u'Are you sure you wish to remove the documents: %(documents)s from the folder "%(folder)s"?') % { - 'documents': ', '.join([unicode(d) for d in folder_documents]), 'folder': folder_documents[0].folder} + 'documents': ', '.join([unicode(d) for d in folder_documents]), 'folder': folder} return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) From 2cd91baa33ac3b3fbc4dfe67ab32ca61ab062e93 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:43:33 -0400 Subject: [PATCH 138/484] Initial translation files for the acl app --- apps/acls/locale/en/LC_MESSAGES/django.po | 234 +++++++++++++++++++++ apps/acls/locale/es/LC_MESSAGES/django.po | 235 +++++++++++++++++++++ apps/acls/locale/it/LC_MESSAGES/django.po | 235 +++++++++++++++++++++ apps/acls/locale/pt/LC_MESSAGES/django.po | 235 +++++++++++++++++++++ apps/acls/locale/ru/LC_MESSAGES/django.po | 236 ++++++++++++++++++++++ 5 files changed, 1175 insertions(+) create mode 100644 apps/acls/locale/en/LC_MESSAGES/django.po create mode 100644 apps/acls/locale/es/LC_MESSAGES/django.po create mode 100644 apps/acls/locale/it/LC_MESSAGES/django.po create mode 100644 apps/acls/locale/pt/LC_MESSAGES/django.po create mode 100644 apps/acls/locale/ru/LC_MESSAGES/django.po diff --git a/apps/acls/locale/en/LC_MESSAGES/django.po b/apps/acls/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000000..ac92777769 --- /dev/null +++ b/apps/acls/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,234 @@ +# 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: 2012-01-02 05:42-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: __init__.py:13 +msgid "ACLs" +msgstr "" + +#: __init__.py:14 +msgid "details" +msgstr "" + +#: __init__.py:15 __init__.py:23 +msgid "grant" +msgstr "" + +#: __init__.py:16 __init__.py:24 +msgid "revoke" +msgstr "" + +#: __init__.py:18 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:19 +msgid "List of classes" +msgstr "" + +#: __init__.py:20 +msgid "ACLs for class" +msgstr "" + +#: __init__.py:21 +msgid "edit" +msgstr "" + +#: __init__.py:22 forms.py:18 +msgid "New holder" +msgstr "" + +#: forms.py:34 +msgid "Users" +msgstr "" + +#: forms.py:37 +msgid "Groups" +msgstr "" + +#: forms.py:40 +msgid "Roles" +msgstr "" + +#: models.py:221 models.py:230 +msgid "Insufficient access." +msgstr "" + +#: models.py:296 models.py:400 +msgid "permission" +msgstr "" + +#: models.py:322 +msgid "access entry" +msgstr "" + +#: models.py:323 +msgid "access entries" +msgstr "" + +#: models.py:421 +msgid "default access entry" +msgstr "" + +#: models.py:422 +msgid "default access entries" +msgstr "" + +#: permissions.py:7 permissions.py:8 +msgid "Access control lists" +msgstr "" + +#: permissions.py:10 +msgid "Edit ACLs" +msgstr "" + +#: permissions.py:11 +msgid "View ACLs" +msgstr "" + +#: permissions.py:13 +msgid "Edit class default ACLs" +msgstr "" + +#: permissions.py:14 +msgid "View class default ACLs" +msgstr "" + +#: views.py:50 +#, python-format +msgid "access control lists for: %s" +msgstr "" + +#: views.py:54 views.py:397 +msgid "holder" +msgstr "" + +#: views.py:55 views.py:398 +msgid "permissions" +msgstr "" + +#: views.py:100 +#, python-format +msgid "permissions available to: %(actor)s for %(obj)s" +msgstr "" + +#: views.py:107 views.py:429 +msgid "namespace" +msgstr "" + +#: views.py:108 views.py:430 +msgid "label" +msgstr "" + +#: views.py:110 views.py:432 +msgid "has permission" +msgstr "" + +#: views.py:191 views.py:285 views.py:514 views.py:594 +msgid " and " +msgstr "" + +#: views.py:192 views.py:286 views.py:515 views.py:595 +#, python-format +msgid " for %s" +msgstr "" + +#: views.py:193 views.py:516 +#, python-format +msgid " to %s" +msgstr "" + +#: views.py:196 views.py:519 +#, python-format +msgid "Are you sure you wish to grant the permission %(title_suffix)s?" +msgstr "" + +#: views.py:198 views.py:521 +#, python-format +msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:205 views.py:528 +#, python-format +msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgstr "" + +#: views.py:211 views.py:534 +#, python-format +msgid "" +"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(object)s." +msgstr "" + +#: views.py:287 views.py:596 +#, python-format +msgid " from %s" +msgstr "" + +#: views.py:290 views.py:599 +#, python-format +msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" +msgstr "" + +#: views.py:292 views.py:601 +#, python-format +msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:299 views.py:608 +#, python-format +msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgstr "" + +#: views.py:305 views.py:614 +#, python-format +msgid "" +"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgstr "" + +#: views.py:361 +#, python-format +msgid "add new holder for: %s" +msgstr "" + +#: views.py:378 +msgid "classes" +msgstr "" + +#: views.py:380 +msgid "class" +msgstr "" + +#: views.py:395 +#, python-format +msgid "default access control lists for class: %s" +msgstr "" + +#: views.py:422 +#, python-format +msgid "permissions available to: %(actor)s for class %(class)s" +msgstr "" + +#: views.py:472 +#, python-format +msgid "add new holder for class: %s" +msgstr "" + +#: views.py:474 +msgid "Select" +msgstr "" diff --git a/apps/acls/locale/es/LC_MESSAGES/django.po b/apps/acls/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000..86b384d988 --- /dev/null +++ b/apps/acls/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,235 @@ +# 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: 2012-01-02 05:42-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:13 +msgid "ACLs" +msgstr "" + +#: __init__.py:14 +msgid "details" +msgstr "" + +#: __init__.py:15 __init__.py:23 +msgid "grant" +msgstr "" + +#: __init__.py:16 __init__.py:24 +msgid "revoke" +msgstr "" + +#: __init__.py:18 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:19 +msgid "List of classes" +msgstr "" + +#: __init__.py:20 +msgid "ACLs for class" +msgstr "" + +#: __init__.py:21 +msgid "edit" +msgstr "" + +#: __init__.py:22 forms.py:18 +msgid "New holder" +msgstr "" + +#: forms.py:34 +msgid "Users" +msgstr "" + +#: forms.py:37 +msgid "Groups" +msgstr "" + +#: forms.py:40 +msgid "Roles" +msgstr "" + +#: models.py:221 models.py:230 +msgid "Insufficient access." +msgstr "" + +#: models.py:296 models.py:400 +msgid "permission" +msgstr "" + +#: models.py:322 +msgid "access entry" +msgstr "" + +#: models.py:323 +msgid "access entries" +msgstr "" + +#: models.py:421 +msgid "default access entry" +msgstr "" + +#: models.py:422 +msgid "default access entries" +msgstr "" + +#: permissions.py:7 permissions.py:8 +msgid "Access control lists" +msgstr "" + +#: permissions.py:10 +msgid "Edit ACLs" +msgstr "" + +#: permissions.py:11 +msgid "View ACLs" +msgstr "" + +#: permissions.py:13 +msgid "Edit class default ACLs" +msgstr "" + +#: permissions.py:14 +msgid "View class default ACLs" +msgstr "" + +#: views.py:50 +#, python-format +msgid "access control lists for: %s" +msgstr "" + +#: views.py:54 views.py:397 +msgid "holder" +msgstr "" + +#: views.py:55 views.py:398 +msgid "permissions" +msgstr "" + +#: views.py:100 +#, python-format +msgid "permissions available to: %(actor)s for %(obj)s" +msgstr "" + +#: views.py:107 views.py:429 +msgid "namespace" +msgstr "" + +#: views.py:108 views.py:430 +msgid "label" +msgstr "" + +#: views.py:110 views.py:432 +msgid "has permission" +msgstr "" + +#: views.py:191 views.py:285 views.py:514 views.py:594 +msgid " and " +msgstr "" + +#: views.py:192 views.py:286 views.py:515 views.py:595 +#, python-format +msgid " for %s" +msgstr "" + +#: views.py:193 views.py:516 +#, python-format +msgid " to %s" +msgstr "" + +#: views.py:196 views.py:519 +#, python-format +msgid "Are you sure you wish to grant the permission %(title_suffix)s?" +msgstr "" + +#: views.py:198 views.py:521 +#, python-format +msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:205 views.py:528 +#, python-format +msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgstr "" + +#: views.py:211 views.py:534 +#, python-format +msgid "" +"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(object)s." +msgstr "" + +#: views.py:287 views.py:596 +#, python-format +msgid " from %s" +msgstr "" + +#: views.py:290 views.py:599 +#, python-format +msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" +msgstr "" + +#: views.py:292 views.py:601 +#, python-format +msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:299 views.py:608 +#, python-format +msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgstr "" + +#: views.py:305 views.py:614 +#, python-format +msgid "" +"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgstr "" + +#: views.py:361 +#, python-format +msgid "add new holder for: %s" +msgstr "" + +#: views.py:378 +msgid "classes" +msgstr "" + +#: views.py:380 +msgid "class" +msgstr "" + +#: views.py:395 +#, python-format +msgid "default access control lists for class: %s" +msgstr "" + +#: views.py:422 +#, python-format +msgid "permissions available to: %(actor)s for class %(class)s" +msgstr "" + +#: views.py:472 +#, python-format +msgid "add new holder for class: %s" +msgstr "" + +#: views.py:474 +msgid "Select" +msgstr "" diff --git a/apps/acls/locale/it/LC_MESSAGES/django.po b/apps/acls/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..86b384d988 --- /dev/null +++ b/apps/acls/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,235 @@ +# 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: 2012-01-02 05:42-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:13 +msgid "ACLs" +msgstr "" + +#: __init__.py:14 +msgid "details" +msgstr "" + +#: __init__.py:15 __init__.py:23 +msgid "grant" +msgstr "" + +#: __init__.py:16 __init__.py:24 +msgid "revoke" +msgstr "" + +#: __init__.py:18 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:19 +msgid "List of classes" +msgstr "" + +#: __init__.py:20 +msgid "ACLs for class" +msgstr "" + +#: __init__.py:21 +msgid "edit" +msgstr "" + +#: __init__.py:22 forms.py:18 +msgid "New holder" +msgstr "" + +#: forms.py:34 +msgid "Users" +msgstr "" + +#: forms.py:37 +msgid "Groups" +msgstr "" + +#: forms.py:40 +msgid "Roles" +msgstr "" + +#: models.py:221 models.py:230 +msgid "Insufficient access." +msgstr "" + +#: models.py:296 models.py:400 +msgid "permission" +msgstr "" + +#: models.py:322 +msgid "access entry" +msgstr "" + +#: models.py:323 +msgid "access entries" +msgstr "" + +#: models.py:421 +msgid "default access entry" +msgstr "" + +#: models.py:422 +msgid "default access entries" +msgstr "" + +#: permissions.py:7 permissions.py:8 +msgid "Access control lists" +msgstr "" + +#: permissions.py:10 +msgid "Edit ACLs" +msgstr "" + +#: permissions.py:11 +msgid "View ACLs" +msgstr "" + +#: permissions.py:13 +msgid "Edit class default ACLs" +msgstr "" + +#: permissions.py:14 +msgid "View class default ACLs" +msgstr "" + +#: views.py:50 +#, python-format +msgid "access control lists for: %s" +msgstr "" + +#: views.py:54 views.py:397 +msgid "holder" +msgstr "" + +#: views.py:55 views.py:398 +msgid "permissions" +msgstr "" + +#: views.py:100 +#, python-format +msgid "permissions available to: %(actor)s for %(obj)s" +msgstr "" + +#: views.py:107 views.py:429 +msgid "namespace" +msgstr "" + +#: views.py:108 views.py:430 +msgid "label" +msgstr "" + +#: views.py:110 views.py:432 +msgid "has permission" +msgstr "" + +#: views.py:191 views.py:285 views.py:514 views.py:594 +msgid " and " +msgstr "" + +#: views.py:192 views.py:286 views.py:515 views.py:595 +#, python-format +msgid " for %s" +msgstr "" + +#: views.py:193 views.py:516 +#, python-format +msgid " to %s" +msgstr "" + +#: views.py:196 views.py:519 +#, python-format +msgid "Are you sure you wish to grant the permission %(title_suffix)s?" +msgstr "" + +#: views.py:198 views.py:521 +#, python-format +msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:205 views.py:528 +#, python-format +msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgstr "" + +#: views.py:211 views.py:534 +#, python-format +msgid "" +"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(object)s." +msgstr "" + +#: views.py:287 views.py:596 +#, python-format +msgid " from %s" +msgstr "" + +#: views.py:290 views.py:599 +#, python-format +msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" +msgstr "" + +#: views.py:292 views.py:601 +#, python-format +msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:299 views.py:608 +#, python-format +msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgstr "" + +#: views.py:305 views.py:614 +#, python-format +msgid "" +"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgstr "" + +#: views.py:361 +#, python-format +msgid "add new holder for: %s" +msgstr "" + +#: views.py:378 +msgid "classes" +msgstr "" + +#: views.py:380 +msgid "class" +msgstr "" + +#: views.py:395 +#, python-format +msgid "default access control lists for class: %s" +msgstr "" + +#: views.py:422 +#, python-format +msgid "permissions available to: %(actor)s for class %(class)s" +msgstr "" + +#: views.py:472 +#, python-format +msgid "add new holder for class: %s" +msgstr "" + +#: views.py:474 +msgid "Select" +msgstr "" diff --git a/apps/acls/locale/pt/LC_MESSAGES/django.po b/apps/acls/locale/pt/LC_MESSAGES/django.po new file mode 100644 index 0000000000..86b384d988 --- /dev/null +++ b/apps/acls/locale/pt/LC_MESSAGES/django.po @@ -0,0 +1,235 @@ +# 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: 2012-01-02 05:42-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:13 +msgid "ACLs" +msgstr "" + +#: __init__.py:14 +msgid "details" +msgstr "" + +#: __init__.py:15 __init__.py:23 +msgid "grant" +msgstr "" + +#: __init__.py:16 __init__.py:24 +msgid "revoke" +msgstr "" + +#: __init__.py:18 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:19 +msgid "List of classes" +msgstr "" + +#: __init__.py:20 +msgid "ACLs for class" +msgstr "" + +#: __init__.py:21 +msgid "edit" +msgstr "" + +#: __init__.py:22 forms.py:18 +msgid "New holder" +msgstr "" + +#: forms.py:34 +msgid "Users" +msgstr "" + +#: forms.py:37 +msgid "Groups" +msgstr "" + +#: forms.py:40 +msgid "Roles" +msgstr "" + +#: models.py:221 models.py:230 +msgid "Insufficient access." +msgstr "" + +#: models.py:296 models.py:400 +msgid "permission" +msgstr "" + +#: models.py:322 +msgid "access entry" +msgstr "" + +#: models.py:323 +msgid "access entries" +msgstr "" + +#: models.py:421 +msgid "default access entry" +msgstr "" + +#: models.py:422 +msgid "default access entries" +msgstr "" + +#: permissions.py:7 permissions.py:8 +msgid "Access control lists" +msgstr "" + +#: permissions.py:10 +msgid "Edit ACLs" +msgstr "" + +#: permissions.py:11 +msgid "View ACLs" +msgstr "" + +#: permissions.py:13 +msgid "Edit class default ACLs" +msgstr "" + +#: permissions.py:14 +msgid "View class default ACLs" +msgstr "" + +#: views.py:50 +#, python-format +msgid "access control lists for: %s" +msgstr "" + +#: views.py:54 views.py:397 +msgid "holder" +msgstr "" + +#: views.py:55 views.py:398 +msgid "permissions" +msgstr "" + +#: views.py:100 +#, python-format +msgid "permissions available to: %(actor)s for %(obj)s" +msgstr "" + +#: views.py:107 views.py:429 +msgid "namespace" +msgstr "" + +#: views.py:108 views.py:430 +msgid "label" +msgstr "" + +#: views.py:110 views.py:432 +msgid "has permission" +msgstr "" + +#: views.py:191 views.py:285 views.py:514 views.py:594 +msgid " and " +msgstr "" + +#: views.py:192 views.py:286 views.py:515 views.py:595 +#, python-format +msgid " for %s" +msgstr "" + +#: views.py:193 views.py:516 +#, python-format +msgid " to %s" +msgstr "" + +#: views.py:196 views.py:519 +#, python-format +msgid "Are you sure you wish to grant the permission %(title_suffix)s?" +msgstr "" + +#: views.py:198 views.py:521 +#, python-format +msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:205 views.py:528 +#, python-format +msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgstr "" + +#: views.py:211 views.py:534 +#, python-format +msgid "" +"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(object)s." +msgstr "" + +#: views.py:287 views.py:596 +#, python-format +msgid " from %s" +msgstr "" + +#: views.py:290 views.py:599 +#, python-format +msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" +msgstr "" + +#: views.py:292 views.py:601 +#, python-format +msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:299 views.py:608 +#, python-format +msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgstr "" + +#: views.py:305 views.py:614 +#, python-format +msgid "" +"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgstr "" + +#: views.py:361 +#, python-format +msgid "add new holder for: %s" +msgstr "" + +#: views.py:378 +msgid "classes" +msgstr "" + +#: views.py:380 +msgid "class" +msgstr "" + +#: views.py:395 +#, python-format +msgid "default access control lists for class: %s" +msgstr "" + +#: views.py:422 +#, python-format +msgid "permissions available to: %(actor)s for class %(class)s" +msgstr "" + +#: views.py:472 +#, python-format +msgid "add new holder for class: %s" +msgstr "" + +#: views.py:474 +msgid "Select" +msgstr "" diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.po b/apps/acls/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000000..74824ab8cf --- /dev/null +++ b/apps/acls/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,236 @@ +# 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: 2012-01-02 05:42-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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 "ACLs" +msgstr "" + +#: __init__.py:14 +msgid "details" +msgstr "" + +#: __init__.py:15 __init__.py:23 +msgid "grant" +msgstr "" + +#: __init__.py:16 __init__.py:24 +msgid "revoke" +msgstr "" + +#: __init__.py:18 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:19 +msgid "List of classes" +msgstr "" + +#: __init__.py:20 +msgid "ACLs for class" +msgstr "" + +#: __init__.py:21 +msgid "edit" +msgstr "" + +#: __init__.py:22 forms.py:18 +msgid "New holder" +msgstr "" + +#: forms.py:34 +msgid "Users" +msgstr "" + +#: forms.py:37 +msgid "Groups" +msgstr "" + +#: forms.py:40 +msgid "Roles" +msgstr "" + +#: models.py:221 models.py:230 +msgid "Insufficient access." +msgstr "" + +#: models.py:296 models.py:400 +msgid "permission" +msgstr "" + +#: models.py:322 +msgid "access entry" +msgstr "" + +#: models.py:323 +msgid "access entries" +msgstr "" + +#: models.py:421 +msgid "default access entry" +msgstr "" + +#: models.py:422 +msgid "default access entries" +msgstr "" + +#: permissions.py:7 permissions.py:8 +msgid "Access control lists" +msgstr "" + +#: permissions.py:10 +msgid "Edit ACLs" +msgstr "" + +#: permissions.py:11 +msgid "View ACLs" +msgstr "" + +#: permissions.py:13 +msgid "Edit class default ACLs" +msgstr "" + +#: permissions.py:14 +msgid "View class default ACLs" +msgstr "" + +#: views.py:50 +#, python-format +msgid "access control lists for: %s" +msgstr "" + +#: views.py:54 views.py:397 +msgid "holder" +msgstr "" + +#: views.py:55 views.py:398 +msgid "permissions" +msgstr "" + +#: views.py:100 +#, python-format +msgid "permissions available to: %(actor)s for %(obj)s" +msgstr "" + +#: views.py:107 views.py:429 +msgid "namespace" +msgstr "" + +#: views.py:108 views.py:430 +msgid "label" +msgstr "" + +#: views.py:110 views.py:432 +msgid "has permission" +msgstr "" + +#: views.py:191 views.py:285 views.py:514 views.py:594 +msgid " and " +msgstr "" + +#: views.py:192 views.py:286 views.py:515 views.py:595 +#, python-format +msgid " for %s" +msgstr "" + +#: views.py:193 views.py:516 +#, python-format +msgid " to %s" +msgstr "" + +#: views.py:196 views.py:519 +#, python-format +msgid "Are you sure you wish to grant the permission %(title_suffix)s?" +msgstr "" + +#: views.py:198 views.py:521 +#, python-format +msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:205 views.py:528 +#, python-format +msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgstr "" + +#: views.py:211 views.py:534 +#, python-format +msgid "" +"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(object)s." +msgstr "" + +#: views.py:287 views.py:596 +#, python-format +msgid " from %s" +msgstr "" + +#: views.py:290 views.py:599 +#, python-format +msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" +msgstr "" + +#: views.py:292 views.py:601 +#, python-format +msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:299 views.py:608 +#, python-format +msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgstr "" + +#: views.py:305 views.py:614 +#, python-format +msgid "" +"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgstr "" + +#: views.py:361 +#, python-format +msgid "add new holder for: %s" +msgstr "" + +#: views.py:378 +msgid "classes" +msgstr "" + +#: views.py:380 +msgid "class" +msgstr "" + +#: views.py:395 +#, python-format +msgid "default access control lists for class: %s" +msgstr "" + +#: views.py:422 +#, python-format +msgid "permissions available to: %(actor)s for class %(class)s" +msgstr "" + +#: views.py:472 +#, python-format +msgid "add new holder for class: %s" +msgstr "" + +#: views.py:474 +msgid "Select" +msgstr "" From 0389b1af14807917c36f018274af48cb75c816d0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:44:44 -0400 Subject: [PATCH 139/484] Add the acl app to the transifex resource file --- .tx/config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.tx/config b/.tx/config index 751a29b59d..74323075fb 100644 --- a/.tx/config +++ b/.tx/config @@ -184,3 +184,11 @@ trans.es = apps/document_signatures/locale/es/LC_MESSAGES/django.po trans.pt = apps/document_signatures/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_signatures/locale/ru/LC_MESSAGES/django.po trans.it = apps/document_signatures/locale/it/LC_MESSAGES/django.po + +[mayan-edms.apps-acl] +source_file = apps/acl/locale/en/LC_MESSAGES/django.po +source_lang = en +trans.es = apps/acl/locale/es/LC_MESSAGES/django.po +trans.pt = apps/acl/locale/pt/LC_MESSAGES/django.po +trans.ru = apps/acl/locale/ru/LC_MESSAGES/django.po +trans.it = apps/acl/locale/it/LC_MESSAGES/django.po From 655e1aa7607395fc349c7c01b47e5519f28eb712 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:45:00 -0400 Subject: [PATCH 140/484] Add the acl app to the translation helper scripts --- misc/compilemessages_all.sh | 6 ++++++ misc/makemessages_all.sh | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index b37e263fac..72267a899e 100755 --- a/misc/compilemessages_all.sh +++ b/misc/compilemessages_all.sh @@ -140,3 +140,9 @@ $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es $COMPILEMESSAGES -l it + +cd $BASE/apps/acl +$COMPILEMESSAGES -l pt +$COMPILEMESSAGES -l ru +$COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh index beba6e7d53..efaa5de78a 100755 --- a/misc/makemessages_all.sh +++ b/misc/makemessages_all.sh @@ -163,3 +163,10 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it + +cd $BASE/apps/acl +$MAKEMESSAGES -l en +$MAKEMESSAGES -l pt +$MAKEMESSAGES -l ru +$MAKEMESSAGES -l es +$MAKEMESSAGES -l it From 6fd2f02e6a3096996ecd4d8fc9454e11bc1efb60 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:46:29 -0400 Subject: [PATCH 141/484] Fix translation related acl app name typo --- .tx/config | 12 ++++++------ misc/compilemessages_all.sh | 2 +- misc/makemessages_all.sh | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.tx/config b/.tx/config index 74323075fb..59fd72f84b 100644 --- a/.tx/config +++ b/.tx/config @@ -185,10 +185,10 @@ trans.pt = apps/document_signatures/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_signatures/locale/ru/LC_MESSAGES/django.po trans.it = apps/document_signatures/locale/it/LC_MESSAGES/django.po -[mayan-edms.apps-acl] -source_file = apps/acl/locale/en/LC_MESSAGES/django.po +[mayan-edms.apps-acls] +source_file = apps/acls/locale/en/LC_MESSAGES/django.po source_lang = en -trans.es = apps/acl/locale/es/LC_MESSAGES/django.po -trans.pt = apps/acl/locale/pt/LC_MESSAGES/django.po -trans.ru = apps/acl/locale/ru/LC_MESSAGES/django.po -trans.it = apps/acl/locale/it/LC_MESSAGES/django.po +trans.es = apps/acls/locale/es/LC_MESSAGES/django.po +trans.pt = apps/acls/locale/pt/LC_MESSAGES/django.po +trans.ru = apps/acls/locale/ru/LC_MESSAGES/django.po +trans.it = apps/acls/locale/it/LC_MESSAGES/django.po diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index 72267a899e..a58cb01188 100755 --- a/misc/compilemessages_all.sh +++ b/misc/compilemessages_all.sh @@ -141,7 +141,7 @@ $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es $COMPILEMESSAGES -l it -cd $BASE/apps/acl +cd $BASE/apps/acls $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh index efaa5de78a..3a91f8de95 100755 --- a/misc/makemessages_all.sh +++ b/misc/makemessages_all.sh @@ -164,7 +164,7 @@ $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it -cd $BASE/apps/acl +cd $BASE/apps/acls $MAKEMESSAGES -l en $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru From 8c19caa37a51a65fa3833fc81ce5967d404168fc Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:58:49 -0400 Subject: [PATCH 142/484] Initial translation for the acls app --- apps/acls/locale/es/LC_MESSAGES/django.mo | Bin 0 -> 2725 bytes apps/acls/locale/es/LC_MESSAGES/django.po | 86 +++++++++++----------- apps/acls/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 378 bytes apps/acls/locale/it/LC_MESSAGES/django.po | 6 +- apps/acls/locale/pt/LC_MESSAGES/django.mo | Bin 0 -> 378 bytes apps/acls/locale/pt/LC_MESSAGES/django.po | 6 +- apps/acls/locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 378 bytes apps/acls/locale/ru/LC_MESSAGES/django.po | 7 +- 8 files changed, 52 insertions(+), 53 deletions(-) create mode 100644 apps/acls/locale/es/LC_MESSAGES/django.mo create mode 100644 apps/acls/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/acls/locale/pt/LC_MESSAGES/django.mo create mode 100644 apps/acls/locale/ru/LC_MESSAGES/django.mo diff --git a/apps/acls/locale/es/LC_MESSAGES/django.mo b/apps/acls/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f542cabb062b968eb8d89a551139925f99dc14ee GIT binary patch literal 2725 zcmb7_&u<$=6vqczewk7r{3;EFArP=Zn>tZJkz3Lj+X)6c3HgOUNNBPu3CAyMD}rI&K)p&SqgDj~H85S2I}A;f`-KY$xtxbc0n>)0Ww5Tnd~#QydC@kycN6z?gzgH4}zD$`@w7A zN$_`Y8su1X02JUIU<5t{Zh~az3`pO71l|o^1ashJunK+$l8ys-5Qp#}JBL8BGXj$S z5=c5;18KijHg7@vu`_s(A7{Y_!OuY2_p5CF2M}AapFsSvU+^G%zk#Ilk8J)=koNx@ zB%S;4@=ov|coaMg()yS2m_|%r1rZAN0XC=jodxOrIS?k;1(4of1n&hefy3Yxa0PV0=@@2dm#C90i<=`fOmn{z%uwNNVtlCFwMrm$H3>oC&5*4 z2z(bLJ@120gP((>_j{1``w@H;{24p~{sofVA&8^*!ywro0ZGR*+3!h^)=h)7Pd%G| zGn)@Uieo36{}el{YfMno}>*Cp>t(^1wc9r4k8tm06oAapE%bdD8O`@SD%g?KQyGxc zqj@7wCDO*y6l@yXyk2`-`fWY=dvQ-7+PO}^Bp)^&sGu&jdMCX&egnFZ3 zbKvI|6G6bEZR!03bRVWi+4Ha$nt|`h+#b_gn2d!AEt7~bbEnJJg&jCumc=R*Ycgb! z=t$cYzGVGq4Gitzn2QaV7HgqI5Fs-!{8;aZV8JpYH}pG_Ef`Jl^y-1Pia;W(N_?SQ zd8IsCmU6UFffuQ=`% zCwTF>(lLyW6^mHtEy@i=#j6}DgfZ!6J zS!p!*T)A1}Cu+@dy)j*`Ru^kaOH)`HwG+{n-m(;(5^t2}W>-k^iAG~ORAbt-r*h4D zv(|TNe5{zO;I83}z2&Vg#Kv+nKH3e1ijH%CT^K9l7gm;MyvhDL($bQ~t3|#JRMal< z$u$*k?~WiazJ+Vw6-K!09!LlGqfsd{^z>yY+&z%)R^Xhmuy^w@bP1!`m2Yb{zIvWp z*-nh+NPVoc5})eGm$*1whFONt<@opI|L@O3-ODfxNb4>ePB4lXau#W!8I=HGIQh~a za^ypA1)14)Zq_7Sos~At6;%c0ih@kbfuPlNTW~Ap5@aBU4@oF`6+!b|LFaa6z;@k`EQ`c$%Y#bUu3dJ#r8*K)A*4crKx*8aHW;H8_x@RE{7S, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,162 +12,161 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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" +"Language: \n" #: __init__.py:13 msgid "ACLs" -msgstr "" +msgstr "LCA" #: __init__.py:14 msgid "details" -msgstr "" +msgstr "detalles" #: __init__.py:15 __init__.py:23 msgid "grant" -msgstr "" +msgstr "otorgar" #: __init__.py:16 __init__.py:24 msgid "revoke" -msgstr "" +msgstr "revocar" #: __init__.py:18 msgid "Default ACLs" -msgstr "" +msgstr "LCA por defecto" #: __init__.py:19 msgid "List of classes" -msgstr "" +msgstr "Lista de clases" #: __init__.py:20 msgid "ACLs for class" -msgstr "" +msgstr "LCA para la clase" #: __init__.py:21 msgid "edit" -msgstr "" +msgstr "editar" #: __init__.py:22 forms.py:18 msgid "New holder" -msgstr "" +msgstr "Nuevo titular" #: forms.py:34 msgid "Users" -msgstr "" +msgstr "Usuarios" #: forms.py:37 msgid "Groups" -msgstr "" +msgstr "Grupos" #: forms.py:40 msgid "Roles" -msgstr "" +msgstr "Funciones" #: models.py:221 models.py:230 msgid "Insufficient access." -msgstr "" +msgstr "Acceso insuficiente." #: models.py:296 models.py:400 msgid "permission" -msgstr "" +msgstr "permiso" #: models.py:322 msgid "access entry" -msgstr "" +msgstr "entrada de acceso" #: models.py:323 msgid "access entries" -msgstr "" +msgstr "entradas de acceso" #: models.py:421 msgid "default access entry" -msgstr "" +msgstr "entrada de acceso por defecto" #: models.py:422 msgid "default access entries" -msgstr "" +msgstr "entradas de acceso por defecto" #: permissions.py:7 permissions.py:8 msgid "Access control lists" -msgstr "" +msgstr "Listas de control de acceso" #: permissions.py:10 msgid "Edit ACLs" -msgstr "" +msgstr "Editar LCA" #: permissions.py:11 msgid "View ACLs" -msgstr "" +msgstr "Ver LCA" #: permissions.py:13 msgid "Edit class default ACLs" -msgstr "" +msgstr "Editar LCA por defecto de la clase" #: permissions.py:14 msgid "View class default ACLs" -msgstr "" +msgstr "Ver LCA por defecto de la clase" #: views.py:50 #, python-format msgid "access control lists for: %s" -msgstr "" +msgstr "listas de control de acceso para: %s" #: views.py:54 views.py:397 msgid "holder" -msgstr "" +msgstr "titular" #: views.py:55 views.py:398 msgid "permissions" -msgstr "" +msgstr "permisos" #: views.py:100 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" -msgstr "" +msgstr "permisos disponibles a: %(actor)s para %(obj)s " #: views.py:107 views.py:429 msgid "namespace" -msgstr "" +msgstr "espacio de nombres" #: views.py:108 views.py:430 msgid "label" -msgstr "" +msgstr "etiqueta" #: views.py:110 views.py:432 msgid "has permission" -msgstr "" +msgstr "tiene permiso" #: views.py:191 views.py:285 views.py:514 views.py:594 msgid " and " -msgstr "" +msgstr " y " #: views.py:192 views.py:286 views.py:515 views.py:595 #, python-format msgid " for %s" -msgstr "" +msgstr " para %s" #: views.py:193 views.py:516 #, python-format msgid " to %s" -msgstr "" +msgstr " a %s" #: views.py:196 views.py:519 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" -msgstr "" +msgstr "¿Está seguro que desea conceder el permiso %(title_suffix)s?" #: views.py:198 views.py:521 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" -msgstr "" +msgstr "¿Está seguro que desea conceder los permisos de %(title_suffix)s?" #: views.py:205 views.py:528 #, python-format msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." -msgstr "" +msgstr "Permiso \"%(permission)s\" concedido a %(requester)s de %(object)s." #: views.py:211 views.py:534 #, python-format @@ -179,7 +178,7 @@ msgstr "" #: views.py:287 views.py:596 #, python-format msgid " from %s" -msgstr "" +msgstr " de %s" #: views.py:290 views.py:599 #, python-format @@ -209,11 +208,11 @@ msgstr "" #: views.py:378 msgid "classes" -msgstr "" +msgstr "clases" #: views.py:380 msgid "class" -msgstr "" +msgstr "clase" #: views.py:395 #, python-format @@ -228,8 +227,9 @@ msgstr "" #: views.py:472 #, python-format msgid "add new holder for class: %s" -msgstr "" +msgstr "añadir nuevo titular para la clase: %s" #: views.py:474 msgid "Select" msgstr "" + diff --git a/apps/acls/locale/it/LC_MESSAGES/django.mo b/apps/acls/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..96ba9bff70db90ca7580704965d08d185be4417e GIT binary patch literal 378 zcmYL_!A=4(5QZ^&+M{O=J$Tc>g, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,11 +12,10 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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" +"Language: \n" #: __init__.py:13 msgid "ACLs" @@ -233,3 +232,4 @@ msgstr "" #: views.py:474 msgid "Select" msgstr "" + diff --git a/apps/acls/locale/pt/LC_MESSAGES/django.mo b/apps/acls/locale/pt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..96ba9bff70db90ca7580704965d08d185be4417e GIT binary patch literal 378 zcmYL_!A=4(5QZ^&+M{O=J$Tc>g, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,11 +12,10 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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" +"Language: \n" #: __init__.py:13 msgid "ACLs" @@ -233,3 +232,4 @@ msgstr "" #: views.py:474 msgid "Select" msgstr "" + diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.mo b/apps/acls/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..96ba9bff70db90ca7580704965d08d185be4417e GIT binary patch literal 378 zcmYL_!A=4(5QZ^&+M{O=J$Tc>g, YEAR. -# +# #, fuzzy msgid "" msgstr "" @@ -12,12 +12,10 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -"Language: \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: \n" #: __init__.py:13 msgid "ACLs" @@ -234,3 +232,4 @@ msgstr "" #: views.py:474 msgid "Select" msgstr "" + From 233725cc58bc89d56fdd267d6f5c6ea2d71dea62 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 05:59:07 -0400 Subject: [PATCH 143/484] Rename request to actor in more translatable texts --- apps/acls/views.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index b8db4f0fa5..00b655ec44 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -202,14 +202,14 @@ def acl_grant(request): for obj, permissions in object_permissions.items(): for permission in permissions: if AccessEntry.objects.grant(permission, requester.source_object, obj.source_object): - messages.success(request, _(u'Permission "%(permission)s" granted to %(requester)s for %(object)s.') % { + messages.success(request, _(u'Permission "%(permission)s" granted to %(actor)s for %(object)s.') % { 'permission': permission, - 'requester': requester, + 'actor': requester, 'object': obj }) else: - messages.warning(request, _(u'%(requester)s, already had the permission "%(permission)s" granted for %(object)s.') % { - 'requester': requester, + messages.warning(request, _(u'%(actor)s, already had the permission "%(permission)s" granted for %(object)s.') % { + 'actor': requester, 'permission': permission, 'object': obj, }) @@ -296,14 +296,14 @@ def acl_revoke(request): for obj, permissions in object_permissions.items(): for permission in permissions: if AccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): - messages.success(request, _(u'Permission "%(permission)s" revoked of %(requester)s for %(object)s.') % { + messages.success(request, _(u'Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % { 'permission': permission, - 'requester': requester, + 'actor': requester, 'object': obj }) else: - messages.warning(request, _(u'%(requester)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { - 'requester': requester, + messages.warning(request, _(u'%(actor)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { + 'actor': requester, 'permission': permission, 'object': obj, }) @@ -525,14 +525,14 @@ def acl_class_multiple_grant(request): for obj, permissions in object_permissions.items(): for permission in permissions: if DefaultAccessEntry.objects.grant(permission, requester.source_object, obj.source_object): - messages.success(request, _(u'Permission "%(permission)s" granted to %(requester)s for %(object)s.') % { + messages.success(request, _(u'Permission "%(permission)s" granted to %(actor)s for %(object)s.') % { 'permission': permission, - 'requester': requester, + 'actor': requester, 'object': obj }) else: - messages.warning(request, _(u'%(requester)s, already had the permission "%(permission)s" granted for %(object)s.') % { - 'requester': requester, + messages.warning(request, _(u'%(actor)s, already had the permission "%(permission)s" granted for %(object)s.') % { + 'actor': requester, 'permission': permission, 'object': obj, }) @@ -605,14 +605,14 @@ def acl_class_multiple_revoke(request): for obj, permissions in object_permissions.items(): for permission in permissions: if DefaultAccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): - messages.success(request, _(u'Permission "%(permission)s" revoked of %(requester)s for %(object)s.') % { + messages.success(request, _(u'Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % { 'permission': permission, - 'requester': requester, + 'actor': requester, 'object': obj }) else: - messages.warning(request, _(u'%(requester)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { - 'requester': requester, + messages.warning(request, _(u'%(actor)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { + 'actor': requester, 'permission': permission, 'object': obj, }) From d50f0f9910a71428205f7c8dbf5ab958cdf3dc9c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:44:12 -0400 Subject: [PATCH 144/484] Add an 'add_document' method to the Folder class --- apps/folders/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/folders/models.py b/apps/folders/models.py index 0f48eead9a..20c2eda7a7 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -31,6 +31,10 @@ class Folder(models.Model): def remove_document(self, document): folder_document = self.folderdocument_set.get(document=document) folder_document.delete() + + def add_document(self, document): + folder_document, created = FolderDocument.objects.get_or_create(folder=self, document=document) + return created class Meta: unique_together = ('title', 'user') From 0682736c487d6efc80ecdbc2ac95c8e8392d624d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:44:38 -0400 Subject: [PATCH 145/484] Change comment style --- apps/dynamic_search/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dynamic_search/models.py b/apps/dynamic_search/models.py index acf8f4ed97..9e7cc552bc 100644 --- a/apps/dynamic_search/models.py +++ b/apps/dynamic_search/models.py @@ -14,9 +14,9 @@ from dynamic_search.api import registered_search_dict class RecentSearch(models.Model): - """ + ''' Keeps a list of the n most recent search keywords for a given user - """ + ''' user = models.ForeignKey(User, verbose_name=_(u'user'), editable=False) query = models.TextField(verbose_name=_(u'query'), editable=False) datetime_created = models.DateTimeField(verbose_name=_(u'datetime created'), editable=False) From db7f748e722c7b1093f50908866c24ce14ac4cda Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:44:55 -0400 Subject: [PATCH 146/484] Simplify database creation error catching for the history app --- apps/history/api.py | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/apps/history/api.py b/apps/history/api.py index 03db0f15d4..04e212d3a2 100644 --- a/apps/history/api.py +++ b/apps/history/api.py @@ -3,15 +3,7 @@ from __future__ import absolute_import import pickle import json -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.core import serializers from django.shortcuts import get_object_or_404 from django.db import models @@ -20,33 +12,23 @@ from .models import HistoryType, History from .runtime_data import history_types_dict -@transaction.commit_manually +@transaction.commit_on_success def register_history_type(history_type_dict): namespace = history_type_dict['namespace'] name = history_type_dict['name'] - try: - # Permanent - history_type_obj, created = HistoryType.objects.get_or_create( - namespace=namespace, name=name) - history_type_obj.save() - # Runtime - history_types_dict.setdefault(namespace, {}) - history_types_dict[namespace][name] = { - 'label': history_type_dict['label'], - 'summary': history_type_dict.get('summary', u''), - 'details': history_type_dict.get('details', u''), - 'expressions': history_type_dict.get('expressions', []), - } - 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() + history_type_obj, created = HistoryType.objects.get_or_create( + namespace=namespace, name=name) + history_type_obj.save() + + # Runtime + history_types_dict.setdefault(namespace, {}) + history_types_dict[namespace][name] = { + 'label': history_type_dict['label'], + 'summary': history_type_dict.get('summary', u''), + 'details': history_type_dict.get('details', u''), + 'expressions': history_type_dict.get('expressions', []), + } def create_history(history_type_dict, source_object=None, data=None): From fb62835af5828b6f6cbb9fd8094b1a182fe587b8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:45:37 -0400 Subject: [PATCH 147/484] Remove remarked code --- apps/folders/urls.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/folders/urls.py b/apps/folders/urls.py index 46c569bc11..46ad85b478 100644 --- a/apps/folders/urls.py +++ b/apps/folders/urls.py @@ -9,7 +9,6 @@ urlpatterns = patterns('folders.views', url(r'^(?P\d+)/$', 'folder_view', (), 'folder_view'), url(r'^(?P\d+)/remove/document/multiple/$', 'folder_document_multiple_remove', (), 'folder_document_multiple_remove'), - #url(r'^document/(?P\d+)/folder/add/sidebar/$', 'folder_add_document_sidebar', (), 'folder_add_document_sidebar'), url(r'^document/(?P\d+)/folder/add/$', 'folder_add_document', (), 'folder_add_document'), url(r'^document/(?P\d+)/folder/list/$', 'document_folder_list', (), 'document_folder_list'), From 09b252453a8f43cbd4e343746e6b3b8e393e1e92 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:45:56 -0400 Subject: [PATCH 148/484] Simplify document to folder inclusion view, form and logic, add proper acl checking for folder document inclusion, add proper folder permission and acl checks to folder document inclusion form --- apps/folders/forms.py | 32 +++++++++++++++++++++----------- apps/folders/views.py | 29 +++++++++-------------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/apps/folders/forms.py b/apps/folders/forms.py index 0c3ef6a13e..a17c3a3d27 100644 --- a/apps/folders/forms.py +++ b/apps/folders/forms.py @@ -1,9 +1,18 @@ 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 acls.models import AccessEntry +from permissions.models import Permission from .models import Folder +from .permissions import PERMISSION_FOLDER_VIEW + +logger = logging.getLogger(__name__) class FolderForm(forms.ModelForm): @@ -12,17 +21,18 @@ class FolderForm(forms.ModelForm): fields = ('title',) -class AddDocumentForm(forms.ModelForm): +class FolderListForm(forms.Form): def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) - super(AddDocumentForm, self).__init__(*args, **kwargs) - self.fields['existing_folder'] = forms.ModelChoiceField( - required=False, - queryset=Folder.objects.filter(user=user), - label=_(u'Existing folders')) - self.fields['title'].required = False - self.fields['title'].label = _(u'New folder') + logger.debug('user: %s' % user) + super(FolderListForm, self).__init__(*args, **kwargs) - class Meta: - model = Folder - fields = ('title',) + queryset = Folder.objects.all() + try: + Permission.objects.check_permissions(user, [PERMISSION_FOLDER_VIEW]) + except PermissionDenied: + queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_VIEW, user, queryset) + + self.fields['folder'] = forms.ModelChoiceField( + queryset=queryset, + label=_(u'Folder')) diff --git a/apps/folders/views.py b/apps/folders/views.py index feef2b21f1..cf217f0485 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -20,7 +20,7 @@ from acls.models import AccessEntry, PermissionDenied from acls.views import acl_list_for, acl_new_holder_for from .models import Folder, FolderDocument -from .forms import FolderForm, AddDocumentForm +from .forms import FolderForm, FolderListForm from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, @@ -36,7 +36,8 @@ def folder_list(request, queryset=None, extra_context=None): 'extra_columns': [ {'name': _(u'created'), 'attribute': 'datetime_created'}, {'name': _(u'documents'), 'attribute': encapsulate(lambda x: x.folderdocument_set.count())} - ] + ], + 'hide_link': True, } if extra_context: context.update(extra_context) @@ -176,26 +177,13 @@ def folder_add_document(request, document_id): except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_FOLDER_ADD_DOCUMENT, request.user, document) - next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/')))#reverse('document_tags', args=[document.pk])))) + next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) if request.method == 'POST': - form = AddDocumentForm(request.POST, user=request.user) + form = FolderListForm(request.POST, user=request.user) if form.is_valid(): - if form.cleaned_data['existing_folder']: - folder = form.cleaned_data['existing_folder'] - elif form.cleaned_data['title']: - folder, created = Folder.objects.get_or_create(user=request.user, title=form.cleaned_data['title']) - if created: - messages.success(request, _(u'Folder "%s" created successfully') % form.cleaned_data['title']) - else: - messages.error(request, _(u'A folder named: %s, already exists.') % form.cleaned_data['title']) - return HttpResponseRedirect(next) - else: - messages.error(request, _(u'Must specify a new folder or an existing one.')) - return HttpResponseRedirect(next) - - folder_document, created = FolderDocument.objects.get_or_create(folder=folder, document=document) - if created: + folder = form.cleaned_data['folder'] + if folder.add_document(document): messages.success(request, _(u'Document: %(document)s added to folder: %(folder)s successfully.') % { 'document': document, 'folder': folder}) else: @@ -204,7 +192,8 @@ def folder_add_document(request, document_id): return HttpResponseRedirect(next) else: - form = AddDocumentForm(user=request.user) + form = FolderListForm(user=request.user) + return render_to_response('generic_form.html', { 'title': _(u'add document "%s" to a folder') % document, From 30416a094f33962e19fc5661d2354102861253ac Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:47:25 -0400 Subject: [PATCH 149/484] Add superuser and staff user support to the filter_objects_by_access acl manager method --- apps/acls/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/acls/models.py b/apps/acls/models.py index 866c9e11ff..c39a37709e 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -269,6 +269,11 @@ class AccessEntryManager(models.Manager): def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False): logger.debug('exception_on_empty: %s' % exception_on_empty) logger.debug('object_list: %s' % object_list) + + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: + return object_list + try: # Try to process as a QuerySet qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) From 32bc77589068de4fe949154adf67556c457952f6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 06:47:53 -0400 Subject: [PATCH 150/484] Update comment style --- apps/main/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 6da73f8a40..b3c1b6a1e8 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -42,9 +42,9 @@ if not SIDE_BAR_SEARCH: def get_version(): - """ + ''' Return the formatted version information - """ + ''' vers = ['%(major)i.%(minor)i' % __version_info__, ] if __version_info__['micro']: From 877259bdbf7367bbde1b73f760441b3d619f9de4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 07:00:58 -0400 Subject: [PATCH 151/484] Don't change the cursor to a hand on disabled links to let the user know the link is not active --- apps/navigation/templates/generic_link_instance.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 %} From aaee4a3c8c48fc7065ee39b572627d6f7697623d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 07:16:35 -0400 Subject: [PATCH 152/484] Fixed document_signatures app data migration --- .../migrations/0002_move_signatures_to_new_app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py index 2fef743da0..8b210583fb 100644 --- a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py +++ b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py @@ -7,7 +7,7 @@ from django.db import models class Migration(DataMigration): def forwards(self, orm): - for document_version in orm.DocumentVersion.objects.all(): + for document_version in orm['documents.DocumentVersion'].objects.all(): if document_version.signature_state or document_version.signature_file: document_signature = orm.DocumentVersionSignature( document_version=document_version, @@ -20,8 +20,8 @@ class Migration(DataMigration): def backwards(self, orm): for document_signature in orm.DocumentVersionSignature.objects.all(): try: - document_version = orm.DocumentVersion.objects.get(document_version=document_version) - except orm.DocumentVersion.DoesNotExists: + document_version = orm['documents.DocumentVersion'].objects.get(document_version=document_version) + except orm['documents.DocumentVersion'].DoesNotExists: pass else: document_version.signature_state=document_signature.signature_state From 7100014d9685e3e1c75d16c14e91007c336346e4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 07:23:07 -0400 Subject: [PATCH 153/484] Add document signatures app external migration dependecy --- .../migrations/0002_move_signatures_to_new_app.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py index 8b210583fb..06cc84f703 100644 --- a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py +++ b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py @@ -6,6 +6,10 @@ from django.db import models class Migration(DataMigration): + depends_on = ( + ('documents', '0012_auto__add_field_documentversion_signature_file'), + ) + def forwards(self, orm): for document_version in orm['documents.DocumentVersion'].objects.all(): if document_version.signature_state or document_version.signature_file: From 7f66a5fad364a853c4344d7a2d1d89c8c9f23ac9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 07:23:34 -0400 Subject: [PATCH 154/484] Remove remarked code --- apps/documents/models.py | 85 ++-------------------------------------- 1 file changed, 3 insertions(+), 82 deletions(-) diff --git a/apps/documents/models.py b/apps/documents/models.py index 713132db62..eb5da0f5cc 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -272,22 +272,8 @@ class Document(models.Model): return version.save() filename = property(_get_filename, _set_filename) - - #TODO: remove after migration - """ - def add_detached_signature(self, *args, **kwargs): - return self.latest_version.add_detached_signature(*args, **kwargs) - def has_detached_signature(self): - return self.latest_version.has_detached_signature() - - def detached_signature(self): - return self.latest_version.detached_signature() - def verify_signature(self): - return self.latest_version.verify_signature() - """ - class DocumentVersion(models.Model): ''' Model that describes a document version and its properties @@ -321,11 +307,7 @@ class DocumentVersion(models.Model): encoding = models.CharField(max_length=64, default='', editable=False) filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) - - #TODO: to be removed after migration - signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False) - signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) - + class Meta: unique_together = ('document', 'major', 'minor', 'micro', 'release_level', 'serial') verbose_name = _(u'document version') @@ -387,9 +369,6 @@ class DocumentVersion(models.Model): if new_document: #Only do this for new documents - #Only do this for new documents - # TODO: remove after migration - #self.update_signed_state(save=False) self.update_checksum(save=False) self.update_mimetype(save=False) self.save() @@ -462,22 +441,7 @@ class DocumentVersion(models.Model): ''' for version in self.document.versions.filter(timestamp__gt=self.timestamp): version.delete() - - #TODO: remove after migration - """ - def update_signed_state(self, save=True): - if self.exists(): - try: - self.signature_state = gpg.verify_file(self.open()).status - # TODO: give use choice for auto public key fetch? - # OR maybe new config option - except GPGVerificationError: - self.signature_state = None - - if save: - self.save() - """ - + def update_mimetype(self, save=True): ''' Read a document verions's file and determine the mimetype by calling the @@ -517,19 +481,6 @@ class DocumentVersion(models.Model): result = DocumentVersion._pre_open_hooks[key](result) return result - #TODO: remove after migration - """ - if self.signature_state and not raw: - try: - result = gpg.decrypt_file(self.file.storage.open(self.file.path)) - # gpg return a string, turn it into a file like object - return StringIO(result.data) - except GPGDecryptionError: - # At least return the original raw content - return self.file.storage.open(self.file.path) - else: - return self.file.storage.open(self.file.path) - """ def save_to_file(self, filepath, buffer_size=1024 * 1024): ''' @@ -555,37 +506,7 @@ class DocumentVersion(models.Model): return self.file.storage.size(self.file.path) else: return None - #TODO: remove after migration - """ - def add_detached_signature(self, detached_signature): - if not self.signature_state: - self.signature_file = detached_signature - self.save() - else: - raise Exception('document already has an embedded signature') - - def has_detached_signature(self): - if self.signature_file: - return self.signature_file.storage.exists(self.signature_file.path) - else: - return False - - def detached_signature(self): - return self.signature_file.storage.open(self.signature_file.path) - - def verify_signature(self): - try: - if self.has_detached_signature(): - logger.debug('has detached signature') - signature = gpg.verify_w_retry(self.open(), self.detached_signature()) - else: - signature = gpg.verify_w_retry(self.open(raw=True)) - except GPGVerificationError: - signature = None - - return signature - """ - + class DocumentTypeFilename(models.Model): ''' From e72173e8037d2cf569f73a33e9fdf76fb8d56e8a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 07:23:44 -0400 Subject: [PATCH 155/484] Add documents external migration dependency --- ..._signature_file__del_field_documentvers.py | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 apps/documents/migrations/0013_auto__del_field_documentversion_signature_file__del_field_documentvers.py diff --git a/apps/documents/migrations/0013_auto__del_field_documentversion_signature_file__del_field_documentvers.py b/apps/documents/migrations/0013_auto__del_field_documentversion_signature_file__del_field_documentvers.py new file mode 100644 index 0000000000..c656de35ed --- /dev/null +++ b/apps/documents/migrations/0013_auto__del_field_documentversion_signature_file__del_field_documentvers.py @@ -0,0 +1,165 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + depends_on = ( + ('document_signatures', '0002_move_signatures_to_new_app'), + ) + + def forwards(self, orm): + + # Deleting field 'DocumentVersion.signature_file' + db.delete_column('documents_documentversion', 'signature_file') + + # Deleting field 'DocumentVersion.signature_state' + db.delete_column('documents_documentversion', 'signature_state') + + + def backwards(self, orm): + + # Adding field 'DocumentVersion.signature_file' + db.add_column('documents_documentversion', 'signature_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True, blank=True), keep_default=False) + + # Adding field 'DocumentVersion.signature_state' + db.add_column('documents_documentversion', 'signature_state', self.gf('django.db.models.fields.CharField')(max_length=16, null=True, blank=True), keep_default=False) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] From cc7d55933a977604c37e275cdb81d018cc7b3086 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 16:53:45 -0400 Subject: [PATCH 156/484] Move tag literals to their own module --- apps/tags/literals.py | 41 +++++++++++++++++++++++++++++++++++++++++ apps/tags/utils.py | 21 --------------------- 2 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 apps/tags/literals.py delete mode 100644 apps/tags/utils.py 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/utils.py b/apps/tags/utils.py deleted file mode 100644 index 476b5bd17a..0000000000 --- a/apps/tags/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import absolute_import - -from django.utils.translation import ugettext_lazy as _ - -from . 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], - } - } From 8478c338982a6b3a78fd72152022ca07750f89bb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 16:54:19 -0400 Subject: [PATCH 157/484] Implement ACL support for tags --- apps/tags/__init__.py | 26 +++--- apps/tags/admin.py | 1 - apps/tags/forms.py | 37 ++++++--- apps/tags/models.py | 39 +-------- apps/tags/tests.py | 3 +- apps/tags/urls.py | 6 +- apps/tags/views.py | 188 +++++++++++++++++++++--------------------- apps/tags/widgets.py | 8 +- 8 files changed, 145 insertions(+), 163 deletions(-) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index c730620b3b..8cf8fc2307 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -7,6 +7,7 @@ from navigation.api import (register_links, register_top_menu, from common.utils import encapsulate from documents.models import Document from acls.models import class_permissions +from acls.permissions import ACLS_VIEW_ACL from taggit.models import Tag from taggit.managers import TaggableManager @@ -17,8 +18,8 @@ from .permissions import (PERMISSION_TAG_CREATE, PERMISSION_TAG_ATTACH, 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', 'permission': [PERMISSION_TAG_CREATE]} +tag_attach = {'text': _(u'attach tag'), 'view': 'tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permission': [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']} @@ -26,6 +27,8 @@ tag_delete = {'text': _(u'delete'), 'view': 'tag_delete', 'args': 'object.id', ' 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]} +tag_new_holder = {'text': _(u'New holder'), 'view': 'tag_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} register_model_list_columns(Tag, [ { @@ -35,22 +38,21 @@ register_model_list_columns(Tag, [ { '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_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_path_regex=[r'^tags/[^d]'])#TODO: change to children view regex or list +register_links(['tag_acl_list', 'tag_new_holder'], [tag_new_holder], menu_name='sidebar') 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_add_attach', 'tag_remove', 'tag_multiple_remove'], [tag_attach], menu_name='sidebar') register_multi_item_links(['document_tags'], [tag_document_remove_multiple]) class_permissions(Document, [ diff --git a/apps/tags/admin.py b/apps/tags/admin.py index 0ba921af19..009033002f 100644 --- a/apps/tags/admin.py +++ b/apps/tags/admin.py @@ -4,5 +4,4 @@ from django.contrib import admin from .models import TagProperties - admin.site.register(TagProperties) diff --git a/apps/tags/forms.py b/apps/tags/forms.py index 01a210494a..15ccc66411 100644 --- a/apps/tags/forms.py +++ b/apps/tags/forms.py @@ -1,26 +1,41 @@ from __future__ import absolute_import +import logging + from django import forms from django.utils.translation import ugettext_lazy as _ from taggit.models import Tag +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): - """ + ''' Form to edit an existing tag's properties - """ + ''' 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/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/tests.py b/apps/tags/tests.py index 612cd1803e..094293d35c 100644 --- a/apps/tags/tests.py +++ b/apps/tags/tests.py @@ -1,6 +1,7 @@ from django.utils import unittest -from .models import Tag, TagProperties, COLOR_RED +from .models import Tag, TagProperties +from .literals import COLOR_RED class TagTestCase(unittest.TestCase): diff --git a/apps/tags/urls.py b/apps/tags/urls.py index d649819642..403d4c258d 100644 --- a/apps/tags/urls.py +++ b/apps/tags/urls.py @@ -10,7 +10,9 @@ 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'), + url(r'^(?P\d+)/acl/holder/new/$', 'tag_new_holder', (), 'tag_new_holder'), ) diff --git a/apps/tags/views.py b/apps/tags/views.py index 12dba9dea9..8083f8d696 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -1,5 +1,7 @@ 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 @@ -7,22 +9,26 @@ from django.contrib import messages from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ -from permissions.models import Permission +from permissions import Permission from taggit.models import Tag from documents.models import Document from documents.views import document_list +from documents.permissions import PERMISSION_DOCUMENT_VIEW from common.utils import encapsulate +from acls.models import AccessEntry, PermissionDenied +from acls.views import acl_list_for, acl_new_holder_for -from .forms import AddTagForm, TagForm +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) -from . import tag_tagged_item_list as tag_tagged_item_list_link + +logger = logging.getLogger(__name__) def tag_create(request): - #Permission.objects.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))) @@ -51,85 +57,30 @@ def tag_create(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']: - Permission.objects.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']: - Permission.objects.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']: - Permission.objects.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']: - Permission.objects.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, @@ -140,23 +91,31 @@ 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)) + } + 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): - Permission.objects.check_permissions(request.user, [PERMISSION_TAG_DELETE]) post_action_redirect = None if tag_id: @@ -167,6 +126,11 @@ def tag_delete(request, tag_id=None, tag_id_list=None): else: 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', '/'))) @@ -209,9 +173,13 @@ def tag_multiple_delete(request): def tag_edit(request, tag_id): - Permission.objects.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(): @@ -253,24 +221,29 @@ def tag_tagged_item_list(request, tag_id): def document_tags(request, document_id): - Permission.objects.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): - Permission.objects.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 @@ -282,8 +255,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', '/'))) @@ -317,3 +288,28 @@ 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, + } + ) + + +def tag_new_holder(request, tag_pk): + tag = get_object_or_404(Tag, pk=tag_pk) + return acl_new_holder_for( + request, + tag, + extra_context={ + #'tag': tag, + 'object': tag, + } + ) diff --git a/apps/tags/widgets.py b/apps/tags/widgets.py index ab1b6762b1..b9dcb0266b 100644 --- a/apps/tags/widgets.py +++ b/apps/tags/widgets.py @@ -3,9 +3,9 @@ from django.utils.safestring import mark_safe def get_tags_inline_widget(document): - """ + ''' A tag widget that includes the total tag count for a given document - """ + ''' tags_template = [] tag_count = document.tags.count() if tag_count: @@ -20,10 +20,10 @@ 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 - """ + ''' tags_template = [] tag_count = document.tags.count() From f22a6f4ab04c0a96cab0f1508e1a08f61b58c473 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 2 Jan 2012 16:54:39 -0400 Subject: [PATCH 158/484] Add proper label and icon for the new holder form submit button --- apps/acls/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/acls/views.py b/apps/acls/views.py index 00b655ec44..6658d74255 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -359,6 +359,8 @@ def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None) context = { 'form': form, 'title': _(u'add new holder for: %s') % obj, + 'submit_label': _(u'Select'), + 'submit_icon_famfam': 'tick', } if extra_context: From 3fc6a09703d9483c79abd15798bfeeb22b81417e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 02:22:10 -0400 Subject: [PATCH 159/484] Enable class acl permissions for the Tag class --- apps/tags/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 8cf8fc2307..cb9edd1fb0 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -22,7 +22,7 @@ tag_create = {'text': _(u'create new tag'), 'view': 'tag_create', 'famfam': 'tag tag_attach = {'text': _(u'attach tag'), 'view': 'tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permission': [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'} @@ -60,10 +60,10 @@ class_permissions(Document, [ PERMISSION_TAG_REMOVE, ]) -#class_permissions(Tag, [ -# PERMISSION_TAG_DELETE, -# PERMISSION_TAG_EDIT, -# PERMISSION_TAG_VIEW, -#]) +class_permissions(Tag, [ + PERMISSION_TAG_DELETE, + PERMISSION_TAG_EDIT, + PERMISSION_TAG_VIEW, +]) Document.add_to_class('tags', TaggableManager()) From ae512a79f8879140036b184fc4ab7cfedc606c4c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 02:22:37 -0400 Subject: [PATCH 160/484] Add missing exception import --- apps/tags/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/tags/forms.py b/apps/tags/forms.py index 15ccc66411..cd2bead2c2 100644 --- a/apps/tags/forms.py +++ b/apps/tags/forms.py @@ -4,6 +4,7 @@ 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 43c52d64e7027a547c44bbbe29866699f4c8a1c6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 02:26:29 -0400 Subject: [PATCH 161/484] Add empty object_list support to the 'filter_objects_by_access' manager method --- apps/acls/models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/acls/models.py b/apps/acls/models.py index c39a37709e..bb9692a54b 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -274,6 +274,14 @@ class AccessEntryManager(models.Manager): if actor.is_superuser or actor.is_staff: return object_list + try: + if object_list.count() == 0: + return object_list + except TypeError: + # object_list is not a queryset + if len(object_list) == 0: + return object_list + try: # Try to process as a QuerySet qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) From 32b953db1287d34826fc55c4b07421d3751d809f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 02:27:09 -0400 Subject: [PATCH 162/484] Improve tag permissions texts --- apps/tags/permissions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/tags/permissions.py b/apps/tags/permissions.py index 4dc7499222..cb4c7f9ae7 100644 --- a/apps/tags/permissions.py +++ b/apps/tags/permissions.py @@ -7,8 +7,8 @@ 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_ATTACH = Permission.objects.register(tags_namespace, 'tag_attach', _(u'Attach exising 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')) -PERMISSION_TAG_DELETE = Permission.objects.register(tags_namespace, 'tag_delete', _(u'Delete global tags')) -PERMISSION_TAG_EDIT = Permission.objects.register(tags_namespace, 'tag_edit', _(u'Edit global tags')) -PERMISSION_TAG_VIEW = Permission.objects.register(tags_namespace, 'tag_view', _(u'View a document\'s tags')) From 40d3426202d300658a8580cc672422d98f852e1f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:03:51 -0400 Subject: [PATCH 163/484] Split acls models module into models, managers, classes and api --- apps/acls/__init__.py | 2 +- apps/acls/api.py | 13 ++ apps/acls/classes.py | 136 +++++++++++++++ apps/acls/forms.py | 2 +- apps/acls/managers.py | 236 +++++++++++++++++++++++++++ apps/acls/models.py | 372 ++---------------------------------------- apps/acls/views.py | 9 +- 7 files changed, 402 insertions(+), 368 deletions(-) create mode 100644 apps/acls/api.py create mode 100644 apps/acls/classes.py create mode 100644 apps/acls/managers.py diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index d0fe93931a..5ca2e83361 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -5,7 +5,7 @@ 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 .models import AccessHolder, AccessObjectClass, ClassAccessHolder +from .classes import AccessHolder, AccessObjectClass, ClassAccessHolder from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) diff --git a/apps/acls/api.py b/apps/acls/api.py new file mode 100644 index 0000000000..8dc3f2d931 --- /dev/null +++ b/apps/acls/api.py @@ -0,0 +1,13 @@ +from django.contrib.contenttypes.models import ContentType + +_class_permissions = {} + + +def class_permissions(cls, permission_list): + stored_permissions = _class_permissions.setdefault(cls, []) + stored_permissions.extend(permission_list) + + +def get_class_permissions_for(obj): + content_type = ContentType.objects.get_for_model(obj) + return _class_permissions.get(content_type.model_class(), []) diff --git a/apps/acls/classes.py b/apps/acls/classes.py new file mode 100644 index 0000000000..1b6820c9e6 --- /dev/null +++ b/apps/acls/classes.py @@ -0,0 +1,136 @@ +import logging +import sys +import types + +from django.contrib.contenttypes.models import ContentType +from django.db.models.base import ModelBase + +logger = logging.getLogger(__name__) + +_cache = {} + + +class EncapsulatedObject(object): + source_object_name = u'source_object' + + @classmethod + def add_to_class(cls, name, value): + if hasattr(value, 'contribute_to_class'): + value.contribute_to_class(cls, name) + else: + setattr(cls, name, value) + + @classmethod + def set_source_object_name(cls, new_name): + cls.source_object_name = new_name + + @classmethod + def encapsulate(cls, source_object=None, app_label=None, model=None, pk=None): + if source_object: + content_type = ContentType.objects.get_for_model(source_object) + elif app_label and model: + try: + content_type = ContentType.objects.get(app_label=app_label, model=model) + source_object_model_class = content_type.model_class() + if pk: + source_object = content_type.get_object_for_this_type(pk=pk) + else: + source_object = source_object_model_class + except ContentType.DoesNotExist: + #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) + #raise cls.DoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) + raise ObjectDoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) + except source_object_model_class.DoesNotExist: + #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) + #raise cls.DoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) + raise ObjectDoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) + + if hasattr(source_object, 'pk'): + # Object + object_key = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) + else: + # Class + object_key = '%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model) + + try: + return _cache[object_key] + except KeyError: + encapsulated_object = cls(source_object) + _cache[object_key] = encapsulated_object + return encapsulated_object + + @classmethod + def get(cls, gid): + elements = gid.split('.') + if len(elements) == 3: + app_label, model, pk = elements[0], elements[1], elements[2] + object_key = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) + elif len(elements) == 2: + app_label, model = elements[0], elements[1] + pk = None + object_key = '%s.%s.%s' % (cls.__name__, app_label, model) + + try: + return _cache[object_key] + except KeyError: + if pk: + return cls.encapsulate(app_label=app_label, model=model, pk=pk) + else: + return cls.encapsulate(app_label=app_label, model=model) + + def __init__(self, source_object): + self.content_type = ContentType.objects.get_for_model(source_object) + self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.name) + + if isinstance(source_object, ModelBase): + # Class + self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.model) + else: + # Object + self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.model, source_object.pk) + + setattr(self, self.__class__.source_object_name, source_object) + + def __unicode__(self): + if isinstance(self.source_object, ModelBase): + return capfirst(unicode(self.source_object._meta.verbose_name_plural)) + + elif self.ct_fullname == 'auth.user': + return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name()) + else: + return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object) + + def __repr__(self): + return self.__unicode__() + + @property + def source_object(self): + return getattr(self, self.__class__.source_object_name, None) + + def get_class_permissions(self): + return _class_permissions.get(self.content_type.model_class(), []) + + +class AccessHolder(EncapsulatedObject): + source_object_name = u'holder_object' + + +class AccessObject(EncapsulatedObject): + source_object_name = u'obj' + + +class AccessObjectClass(EncapsulatedObject): + source_object_name = u'cls' + + +class ClassAccessHolder(EncapsulatedObject): + source_object_name = u'class_holder' + + +if sys.version_info < (2, 5): + # Prior to Python 2.5, Exception was an old-style class + def subclass_exception(name, parents, unused): + return types.ClassType(name, parents, {}) +else: + def subclass_exception(name, parents, module): + return type(name, parents, {'__module__': module}) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index a4fbebf4c5..8adfaef90e 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -7,7 +7,7 @@ from django.contrib.auth.models import User, Group from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate, get_object_name -from .models import AccessHolder +from .classes import AccessHolder def _as_choice_list(holders): diff --git a/apps/acls/managers.py b/apps/acls/managers.py new file mode 100644 index 0000000000..6d674bbc59 --- /dev/null +++ b/apps/acls/managers.py @@ -0,0 +1,236 @@ +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.auth.models import User +from django.core.exceptions import PermissionDenied + +from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder + +logger = logging.getLogger(__name__) + + +class AccessEntryManager(models.Manager): + def source_object(self, obj): + if isinstance(obj, EncapsulatedObject): + return obj.source_object + else: + return obj + + def grant(self, permission, actor, obj): + ''' + Grant a permission (what), (to) an actor, (on) a specific object + ''' + obj = self.source_object(obj) + actor = self.source_object(actor) + + access_entry, created = self.model.objects.get_or_create( + permission=permission, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return created + + def revoke(self, permission, actor, obj): + ''' + Revoke a permission (what), (from) an actor, (on) a specific object + ''' + obj = self.source_object(obj) + actor = self.source_object(actor) + + try: + access_entry = self.model.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + access_entry.delete() + return True + except self.model.DoesNotExist: + return False + + def has_access(self, permission, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) + + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: + return True + + try: + access_entry = self.model.objects.get( + permission=permission.get_stored_permission(), + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, + content_type=ContentType.objects.get_for_model(obj), + object_id=obj.pk + ) + return True + except self.model.DoesNotExist: + return False + + def check_access(self, permission, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) + + if self.has_access(permission, actor, obj): + return True + else: + raise PermissionDenied(ugettext(u'Insufficient access.')) + + def check_accesses(self, permission_list, actor, obj): + obj = self.source_object(obj) + actor = self.source_object(actor) + for permission in permission_list: + if self.has_access(permission, actor, obj): + return True + + raise PermissionDenied(ugettext(u'Insufficient access.')) + + def get_allowed_class_objects(self, permission, actor, cls): + actor_type = ContentType.objects.get_for_model(actor) + content_type = ContentType.objects.get_for_model(cls) + + return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) + + def get_acl_url(self, obj): + content_type = ContentType.objects.get_for_model(obj) + return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) + + def get_new_holder_url(self, obj): + content_type = ContentType.objects.get_for_model(obj) + return reverse('acl_new_holder_for', args=[content_type.app_label, content_type.model, obj.pk]) + + def get_holders_for(self, obj): + content_type = ContentType.objects.get_for_model(obj) + holder_list = [] + for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): + entry = AccessHolder.encapsulate(access_entry.holder_object) + + if entry not in holder_list: + holder_list.append(entry) + + return holder_list + + def get_holder_permissions_for(self, obj, actor): + logger.debug('obj: %s' % obj) + logger.debug('actor: %s' % actor) + + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: + return Permission.objects.all() + + actor_type = ContentType.objects.get_for_model(actor) + content_type = ContentType.objects.get_for_model(obj) + return (access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=actor_type, holder_id=actor.pk)) + + def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False): + logger.debug('exception_on_empty: %s' % exception_on_empty) + logger.debug('object_list: %s' % object_list) + + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: + return object_list + + try: + if object_list.count() == 0: + return object_list + except TypeError: + # object_list is not a queryset + if len(object_list) == 0: + return object_list + + try: + # Try to process as a QuerySet + qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) + logger.debug('qs: %s' % qs) + + if qs.count() == 0 and exception_on_empty == True: + raise PermissionDenied + + return qs + except AttributeError: + # Fallback to a list filtered list + obj_list = list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0]))) + logger.debug('obj_list: %s' % obj_list) + if len(obj_list) == 0 and exception_on_empty == True: + raise PermissionDenied + + return obj_list + + +class DefaultAccessEntryManager(models.Manager): + def get_holders_for(self, cls): + if isinstance(cls, EncapsulatedObject): + cls = cls.source_object + + content_type = ContentType.objects.get_for_model(cls) + holder_list = [] + for access_entry in self.model.objects.filter(content_type=content_type): + entry = ClassAccessHolder.encapsulate(access_entry.holder_object) + + if entry not in holder_list: + holder_list.append(entry) + + return holder_list + + def has_access(self, permission, actor, cls): + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: + return True + + try: + access_entry = self.model.objects.get( + permission=permission.get_stored_permission(), + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, + content_type=ContentType.objects.get_for_model(cls), + ) + return True + except self.model.DoesNotExist: + return False + + def grant(self, permission, actor, cls): + ''' + Grant a permission (what), (to) an actor, (on) a specific class + ''' + access_entry, created = self.model.objects.get_or_create( + permission=permission, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, + content_type=ContentType.objects.get_for_model(cls), + ) + return created + + def revoke(self, permission, actor, cls): + ''' + Revoke a permission (what), (from) an actor, (on) a specific class + ''' + try: + access_entry = self.model.objects.get( + permission=permission, + holder_type=ContentType.objects.get_for_model(actor), + holder_id=actor.pk, + content_type=ContentType.objects.get_for_model(cls), + ) + access_entry.delete() + return True + except self.model.DoesNotExist: + return False + + def get_holder_permissions_for(self, cls, actor): + if isinstance(actor, User): + if actor.is_superuser or actor.is_staff: + return Permission.objects.all() + + actor_type = ContentType.objects.get_for_model(actor) + content_type = ContentType.objects.get_for_model(cls) + return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=actor_type, holder_id=actor.pk)] diff --git a/apps/acls/models.py b/apps/acls/models.py index bb9692a54b..b175601949 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -1,7 +1,5 @@ from __future__ import absolute_import -import sys -import types import logging from django.db import models @@ -9,303 +7,24 @@ 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 django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import get_object_or_404 -from django.db.models.base import ModelBase from django.template.defaultfilters import capfirst from permissions.models import StoredPermission -_cache = {} - -_class_permissions = {} +from .managers import AccessEntryManager, DefaultAccessEntryManager logger = logging.getLogger(__name__) -def class_permissions(cls, permission_list): - stored_permissions = _class_permissions.setdefault(cls, []) - stored_permissions.extend(permission_list) - - -class EncapsulatedObject(object): - source_object_name = u'source_object' - - @classmethod - def add_to_class(cls, name, value): - if hasattr(value, 'contribute_to_class'): - value.contribute_to_class(cls, name) - else: - setattr(cls, name, value) - - @classmethod - def set_source_object_name(cls, new_name): - cls.source_object_name = new_name - - @classmethod - def encapsulate(cls, source_object=None, app_label=None, model=None, pk=None): - if source_object: - content_type = ContentType.objects.get_for_model(source_object) - elif app_label and model: - try: - content_type = ContentType.objects.get(app_label=app_label, model=model) - source_object_model_class = content_type.model_class() - if pk: - source_object = content_type.get_object_for_this_type(pk=pk) - else: - source_object = source_object_model_class - except ContentType.DoesNotExist: - #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) - #raise cls.DoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) - raise ObjectDoesNotExist("%s matching query does not exist." % ContentType._meta.object_name) - except source_object_model_class.DoesNotExist: - #cls.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', (ObjectDoesNotExist,), cls.__name__)) - #raise cls.DoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) - raise ObjectDoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) - - if hasattr(source_object, 'pk'): - # Object - object_key = '%s.%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model, source_object.pk) - else: - # Class - object_key = '%s.%s.%s' % (cls.__name__, content_type.app_label, content_type.model) - - try: - return _cache[object_key] - except KeyError: - encapsulated_object = cls(source_object) - _cache[object_key] = encapsulated_object - return encapsulated_object - - @classmethod - def get(cls, gid): - elements = gid.split('.') - if len(elements) == 3: - app_label, model, pk = elements[0], elements[1], elements[2] - object_key = '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) - elif len(elements) == 2: - app_label, model = elements[0], elements[1] - pk = None - object_key = '%s.%s.%s' % (cls.__name__, app_label, model) - - try: - return _cache[object_key] - except KeyError: - if pk: - return cls.encapsulate(app_label=app_label, model=model, pk=pk) - else: - return cls.encapsulate(app_label=app_label, model=model) - - def __init__(self, source_object): - self.content_type = ContentType.objects.get_for_model(source_object) - self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.name) - - if isinstance(source_object, ModelBase): - # Class - self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.model) - else: - # Object - self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.model, source_object.pk) - - setattr(self, self.__class__.source_object_name, source_object) - - def __unicode__(self): - if isinstance(self.source_object, ModelBase): - return capfirst(unicode(self.source_object._meta.verbose_name_plural)) - - elif self.ct_fullname == 'auth.user': - return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name()) - else: - #label = unicode(obj) - return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object) - - #return unicode(getattr(self, self.__class__.source_object_name, None)) - - def __repr__(self): - return self.__unicode__() - - @property - def source_object(self): - return getattr(self, self.__class__.source_object_name, None) - - def get_class_permissions(self): - return _class_permissions.get(self.content_type.model_class(), []) - - -class AccessHolder(EncapsulatedObject): - source_object_name = u'holder_object' - - -class AccessObject(EncapsulatedObject): - source_object_name = u'obj' - - -class AccessObjectClass(EncapsulatedObject): - source_object_name = u'cls' - - -class ClassAccessHolder(EncapsulatedObject): - source_object_name = u'class_holder' - - -class AccessEntryManager(models.Manager): - def source_object(self, obj): - if isinstance(obj, EncapsulatedObject): - return obj.source_object - else: - return obj - - def grant(self, permission, actor, obj): - ''' - Grant a permission (what), (to) a requester, (on) a specific object - ''' - obj = self.source_object(obj) - actor = self.source_object(actor) - - access_entry, created = self.model.objects.get_or_create( - permission=permission, - holder_type=ContentType.objects.get_for_model(actor), - holder_id=actor.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) - return created - - def revoke(self, permission, actor, obj): - obj = self.source_object(obj) - actor = self.source_object(actor) - - try: - access_entry = self.model.objects.get( - permission=permission, - holder_type=ContentType.objects.get_for_model(actor), - holder_id=actor.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) - access_entry.delete() - return True - except self.model.DoesNotExist: - return False - - def has_access(self, permission, actor, obj): - obj = self.source_object(obj) - actor = self.source_object(actor) - - if isinstance(actor, User): - if actor.is_superuser or actor.is_staff: - return True - - try: - access_entry = self.model.objects.get( - permission=permission.get_stored_permission(), - holder_type=ContentType.objects.get_for_model(actor), - holder_id=actor.pk, - content_type=ContentType.objects.get_for_model(obj), - object_id=obj.pk - ) - return True - except self.model.DoesNotExist: - return False - - def check_access(self, permission, actor, obj): - obj = self.source_object(obj) - actor = self.source_object(actor) - - if self.has_access(permission, actor, obj): - return True - else: - raise PermissionDenied(ugettext(u'Insufficient access.')) - - def check_accesses(self, permission_list, actor, obj): - obj = self.source_object(obj) - actor = self.source_object(actor) - for permission in permission_list: - if self.has_access(permission, actor, obj): - return True - - raise PermissionDenied(ugettext(u'Insufficient access.')) - - def get_allowed_class_objects(self, permission, actor, cls): - actor_type = ContentType.objects.get_for_model(actor) - content_type = ContentType.objects.get_for_model(cls) - - return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) - - def get_acl_url(self, obj): - content_type = ContentType.objects.get_for_model(obj) - return reverse('acl_list', args=[content_type.app_label, content_type.model, obj.pk]) - - def get_new_holder_url(self, obj): - content_type = ContentType.objects.get_for_model(obj) - return reverse('acl_new_holder_for', args=[content_type.app_label, content_type.model, obj.pk]) - - def get_holders_for(self, obj): - content_type = ContentType.objects.get_for_model(obj) - holder_list = [] - for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): - entry = AccessHolder.encapsulate(access_entry.holder_object) - - if entry not in holder_list: - holder_list.append(entry) - - return holder_list - - def get_holder_permissions_for(self, obj, actor): - logger.debug('obj: %s' % obj) - logger.debug('actor: %s' % actor) - - if isinstance(actor, User): - if actor.is_superuser or actor.is_staff: - return Permission.objects.all() - - actor_type = ContentType.objects.get_for_model(actor) - content_type = ContentType.objects.get_for_model(obj) - return (access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=actor_type, holder_id=actor.pk)) - - def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False): - logger.debug('exception_on_empty: %s' % exception_on_empty) - logger.debug('object_list: %s' % object_list) - - if isinstance(actor, User): - if actor.is_superuser or actor.is_staff: - return object_list - - try: - if object_list.count() == 0: - return object_list - except TypeError: - # object_list is not a queryset - if len(object_list) == 0: - return object_list - - try: - # Try to process as a QuerySet - qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) - logger.debug('qs: %s' % qs) - - if qs.count() == 0 and exception_on_empty == True: - raise PermissionDenied - - return qs - except AttributeError: - # Fallback to a list filtered list - obj_list = list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0]))) - logger.debug('obj_list: %s' % obj_list) - if len(obj_list) == 0 and exception_on_empty == True: - raise PermissionDenied - - return obj_list - - def get_class_permissions_for(self, obj): - content_type = ContentType.objects.get_for_model(obj) - return _class_permissions.get(content_type.model_class(), []) - - class AccessEntry(models.Model): + ''' + Model that hold the permission, object, actor relationship + ''' + permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) holder_type = models.ForeignKey( @@ -339,73 +58,12 @@ class AccessEntry(models.Model): return u'%s: %s' % (self.content_type, self.content_object) -class DefaultAccessEntryManager(models.Manager): - def get_holders_for(self, cls): - if isinstance(cls, EncapsulatedObject): - cls = cls.source_object - - content_type = ContentType.objects.get_for_model(cls) - holder_list = [] - for access_entry in self.model.objects.filter(content_type=content_type): - entry = ClassAccessHolder.encapsulate(access_entry.holder_object) - - if entry not in holder_list: - holder_list.append(entry) - - return holder_list - - def has_access(self, permission, actor, cls): - if isinstance(actor, User): - if actor.is_superuser or actor.is_staff: - return True - - try: - access_entry = self.model.objects.get( - permission=permission.get_stored_permission(), - holder_type=ContentType.objects.get_for_model(actor), - holder_id=actor.pk, - content_type=ContentType.objects.get_for_model(cls), - ) - return True - except self.model.DoesNotExist: - return False - - def grant(self, permission, actor, cls): - ''' - Grant a permission (what), (to) a requester, (on) a specific class - ''' - access_entry, created = self.model.objects.get_or_create( - permission=permission, - holder_type=ContentType.objects.get_for_model(actor), - holder_id=actor.pk, - content_type=ContentType.objects.get_for_model(cls), - ) - return created - - def revoke(self, permission, actor, cls): - try: - access_entry = self.model.objects.get( - permission=permission, - holder_type=ContentType.objects.get_for_model(actor), - holder_id=actor.pk, - content_type=ContentType.objects.get_for_model(cls), - ) - access_entry.delete() - return True - except self.model.DoesNotExist: - return False - - def get_holder_permissions_for(self, cls, actor): - if isinstance(actor, User): - if actor.is_superuser or actor.is_staff: - return Permission.objects.all() - - actor_type = ContentType.objects.get_for_model(actor) - content_type = ContentType.objects.get_for_model(cls) - return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=actor_type, holder_id=actor.pk)] - - class DefaultAccessEntry(models.Model): + ''' + Model that holds the permission, class, actor relationship, that will + be added upon the creation of an instance of said class + ''' + @classmethod def get_classes(cls): return [AccessObjectClass.encapsulate(cls) for cls in _class_permissions.keys()] @@ -436,13 +94,3 @@ class DefaultAccessEntry(models.Model): def __unicode__(self): return u'%s: %s' % (self.content_type, self.content_object) - - -if sys.version_info < (2, 5): - # Prior to Python 2.5, Exception was an old-style class - def subclass_exception(name, parents, unused): - return types.ClassType(name, parents, {}) -else: - def subclass_exception(name, parents, module): - return type(name, parents, {'__module__': module}) - diff --git a/apps/acls/views.py b/apps/acls/views.py index 6658d74255..25445a9bbc 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -24,10 +24,12 @@ from common.widgets import two_state_template from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) -from .models import (AccessEntry, AccessObject, AccessHolder, - DefaultAccessEntry, AccessObjectClass, ClassAccessHolder) +from .models import AccessEntry, DefaultAccessEntry +from .classes import (AccessHolder, AccessObject, AccessObjectClass, + ClassAccessHolder) from .widgets import object_w_content_type_icon from .forms import HolderSelectionForm +from .api import get_class_permissions_for logger = logging.getLogger(__name__) @@ -89,8 +91,7 @@ def acl_detail_for(request, actor, obj, navigation_object=None): except PermissionDenied: AccessEntry.objects.check_accesses([ACLS_VIEW_ACL, ACLS_EDIT_ACL], actor, obj) - #permission_list = list(obj.get_class_permissions()) - permission_list = AccessEntry.objects.get_class_permissions_for(obj) + permission_list = get_class_permissions_for(obj) #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ From e5cc2e3f7a8c6a45a6be5809cc00065807259e75 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:04:32 -0400 Subject: [PATCH 164/484] Update the apps to the new acls module split --- apps/document_acls/__init__.py | 2 +- apps/document_acls/views.py | 2 -- apps/documents/__init__.py | 2 +- apps/folders/__init__.py | 2 +- apps/linking/__init__.py | 2 +- apps/metadata/__init__.py | 2 +- apps/sources/__init__.py | 2 +- apps/tags/__init__.py | 2 +- 8 files changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index acafb97d50..ff6d1f32bb 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -4,7 +4,7 @@ from documents.models import Document from navigation.api import register_links, register_multi_item_links from project_setup.api import register_setup from acls import ACLS_VIEW_ACL, ACLS_EDIT_ACL -from acls.models import class_permissions +from acls.api import class_permissions acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} document_new_holder = {'text': _(u'New holder'), 'view': 'document_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 5f723f166e..505770fa99 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -24,7 +24,5 @@ def document_new_holder(request, document_id): document, extra_context={ 'object': document, - 'submit_label': _(u'Select'), - 'submit_icon_famfam': 'tick' } ) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 1629fe63af..0c9ce41042 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -13,7 +13,7 @@ from tags.widgets import get_tags_inline_widget_simple from history.api import register_history_type from metadata.api import get_metadata_string from project_setup.api import register_setup -from acls.models import class_permissions +from acls.api import class_permissions from .models import (Document, DocumentPage, DocumentPageTransformation, DocumentType, DocumentTypeFilename, diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 5c894224be..0a89298148 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -6,7 +6,7 @@ from navigation.api import (register_links, register_top_menu, register_multi_item_links, register_sidebar_template) from documents.models import Document from documents.permissions import PERMISSION_DOCUMENT_VIEW -from acls.models import class_permissions +from acls.api import class_permissions from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL from .models import Folder diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index 73e4b1cecb..0354346f7e 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -6,7 +6,7 @@ from navigation.api import register_links, register_sidebar_template from project_setup.api import register_setup from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document -from acls.models import class_permissions +from acls.api import class_permissions from acls import ACLS_EDIT_ACL, ACLS_VIEW_ACL from .models import SmartLink, SmartLinkCondition diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index 60439c2924..97f5de443a 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -7,7 +7,7 @@ from navigation.api import register_links, register_multi_item_links, \ from documents.models import Document, DocumentType from documents.permissions import PERMISSION_DOCUMENT_TYPE_EDIT from project_setup.api import register_setup -from acls.models import class_permissions +from acls.api import class_permissions from .models import MetadataType, MetadataSet from .permissions import (PERMISSION_METADATA_DOCUMENT_EDIT, diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 8fc456eef5..ecdbe086a5 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -9,7 +9,7 @@ from common.utils import encapsulate from project_setup.api import register_setup from documents.models import Document from documents.permissions import PERMISSION_DOCUMENT_CREATE -from acls.models import class_permissions +from acls.api import class_permissions from .staging import StagingFile from .models import (WebForm, StagingFolder, SourceTransformation, diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index cb9edd1fb0..357b4b878c 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -6,7 +6,7 @@ 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.models import class_permissions +from acls.api import class_permissions from acls.permissions import ACLS_VIEW_ACL from taggit.models import Tag From 29ef0e3f426c3f0e38dc5daf6a40733ad92c8059 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:13:39 -0400 Subject: [PATCH 165/484] Proper 'PermissionDenied' exception import --- apps/documents/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index 5bb4266a35..14ec65e855 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -12,6 +12,7 @@ from django.contrib import messages from django.views.generic.list_detail import object_list from django.core.urlresolvers import reverse from django.utils.http import urlencode +from django.core.exceptions import PermissionDenied import sendfile from common.utils import pretty_size, parse_range, urlquote, \ @@ -29,7 +30,7 @@ from navigation.utils import resolve_to_name from permissions.models import Permission from document_indexing.api import update_indexes, delete_indexes from history.api import create_history -from acls.models import AccessEntry, PermissionDenied +from acls.models import AccessEntry from .conf.settings import (PREVIEW_SIZE, STORAGE_BACKEND, ZOOM_PERCENT_STEP, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL, ROTATION_STEP, PRINT_SIZE, From 3fd64d230bbe52940ed7f05a5f6d9c40eb4e49e9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:13:58 -0400 Subject: [PATCH 166/484] Add ACL support to the document signatures app --- apps/document_signatures/__init__.py | 9 ++++++++- apps/document_signatures/views.py | 21 +++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index 0a34ed064d..e899fd4c18 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -1,4 +1,5 @@ from __future__ import absolute_import + import logging try: @@ -11,9 +12,9 @@ from django.db.models.signals import post_save from documents.models import Document, DocumentVersion from navigation.api import register_links - from django_gpg.runtime import gpg from django_gpg.exceptions import GPGDecryptionError +from acls.api import class_permissions from .models import DocumentVersionSignature from .permissions import ( @@ -59,3 +60,9 @@ register_links(['document_verify', 'document_signature_upload', 'document_signat DocumentVersion.register_pre_open_hook(1, document_pre_open_hook) post_save.connect(document_post_save, sender=DocumentVersion) + +class_permissions(Document, [ + PERMISSION_DOCUMENT_VERIFY, + PERMISSION_SIGNATURE_UPLOAD, + PERMISSION_SIGNATURE_DOWNLOAD +]) diff --git a/apps/document_signatures/views.py b/apps/document_signatures/views.py index b69f7aba38..fc33c87a2a 100644 --- a/apps/document_signatures/views.py +++ b/apps/document_signatures/views.py @@ -11,10 +11,12 @@ from django.contrib import messages from django.utils.safestring import mark_safe from django.conf import settings from django.template.defaultfilters import force_escape +from django.core.exceptions import PermissionDenied from documents.models import Document, RecentDocument from permissions.models import Permission from filetransfers.api import serve_file +from acls.models import AccessEntry from django_gpg.api import SIGNATURE_STATES @@ -27,9 +29,13 @@ logger = logging.getLogger(__name__) def document_verify(request, document_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) document = get_object_or_404(Document, pk=document_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERIFY]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERIFY, request.user, document) + RecentDocument.objects.add_document_for_user(request.user, document) signature = DocumentVersionSignature.objects.verify_signature(document) @@ -69,10 +75,13 @@ def document_verify(request, document_pk): def document_signature_upload(request, document_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) - document = get_object_or_404(Document, pk=document_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_UPLOAD]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_SIGNATURE_UPLOAD, request.user, document) + RecentDocument.objects.add_document_for_user(request.user, document) post_action_redirect = None @@ -103,9 +112,13 @@ def document_signature_upload(request, document_pk): def document_signature_download(request, document_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) document = get_object_or_404(Document, pk=document_pk) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_SIGNATURE_DOWNLOAD, request.user, document) + try: if DocumentVersionSignature.objects.has_detached_signature(document): signature = DocumentVersionSignature.objects.detached_signature(document) From f45c8ca2f547725fcf8c1765c38e766095f32f6b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:15:10 -0400 Subject: [PATCH 167/484] Removed unnedeed top level locale dir --- locale/es/LC_MESSAGES/django.mo | Bin 542 -> 0 bytes locale/es/LC_MESSAGES/django.po | 28 ---------------------------- 2 files changed, 28 deletions(-) delete mode 100644 locale/es/LC_MESSAGES/django.mo delete mode 100644 locale/es/LC_MESSAGES/django.po diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo deleted file mode 100644 index f3e6b3187d449994c10026b72741e1bbf0810203..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 542 zcmZuu%T59@6s@mlCUIlp&PCnn;*J9%Ap;l?M?)Nt;9%ToVd_vawqsj}euyi-z@^{d zfA}rlL4q4^a&pdX?&Gxm-dTSm7;A_c638SKW=w7}CUfp-HQ^%*?HF#kHbP0C_L{A$=4C){gZ@qXy6g0LrnH5Q zNkj~1)5JieeCqVBBWP*PEH=S8v)rdeuTTK*7`zjdez6Q*$@8!f`g|tx;s4f^%1+3P zg-A1LQf8I*XJLm)>g z7BcZ^Whm@&JHEx;(mao0VCFUP1l=h>>dJH2$OSqc|QKN+9OY@V8Wu}Xhs b{Xo+FIxQSl9n!|X`uZ>=Fd6&$R4MrZ*!Goy 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" From 67c6467df0575b43811f9a9d6b9e8166f98a1e97 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:16:18 -0400 Subject: [PATCH 168/484] Remove old project file --- misc/mayan.geany | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 misc/mayan.geany 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 From 3833e07d03b3b21acd93272edf0913024c7dc549 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:28:01 -0400 Subject: [PATCH 169/484] Remove repeated import --- apps/folders/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/folders/views.py b/apps/folders/views.py index cf217f0485..d4eeadbaed 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -16,7 +16,7 @@ from documents.models import Document from documents.views import document_list from permissions import Permission from common.utils import encapsulate -from acls.models import AccessEntry, PermissionDenied +from acls.models import AccessEntry from acls.views import acl_list_for, acl_new_holder_for from .models import Folder, FolderDocument From d270e155a28d2934cad55042cf7ac0cceca1dcae Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 03:28:17 -0400 Subject: [PATCH 170/484] Add ACL support to the history app --- apps/documents/__init__.py | 6 ++++-- apps/history/__init__.py | 3 +-- apps/history/permissions.py | 3 +-- apps/history/views.py | 16 ++++++++++++---- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 0c9ce41042..ad95e977d7 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -11,6 +11,7 @@ from navigation.api import register_links, register_top_menu, \ from main.api import register_diagnostic, register_maintenance_links from tags.widgets import get_tags_inline_widget_simple from history.api import register_history_type +from history.permissions import PERMISSION_HISTORY_VIEW from metadata.api import get_metadata_string from project_setup.api import register_setup from acls.api import class_permissions @@ -75,7 +76,7 @@ document_update_page_count = {'text': _(u'update office documents\' page count') document_clear_transformations = {'text': _(u'clear transformations'), 'view': 'document_clear_transformations', 'args': 'object.id', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_multiple_clear_transformations = {'text': _(u'clear transformations'), 'view': 'document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_print = {'text': _(u'print'), 'view': 'document_print', 'args': 'object.id', 'famfam': 'printer', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_history_view = {'text': _(u'history'), 'view': 'history_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_history_view = {'text': _(u'history'), 'view': 'history_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_HISTORY_VIEW]} document_missing_list = {'text': _(u'Find missing document files'), 'view': 'document_missing_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} # Tools @@ -204,5 +205,6 @@ class_permissions(Document, [ PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, PERMISSION_DOCUMENT_TRANSFORM, - PERMISSION_DOCUMENT_VERSION_REVERT + PERMISSION_DOCUMENT_VERSION_REVERT, + PERMISSION_HISTORY_VIEW ]) diff --git a/apps/history/__init__.py b/apps/history/__init__.py index 7e5999508a..c347cd6fcc 100644 --- a/apps/history/__init__.py +++ b/apps/history/__init__.py @@ -6,8 +6,7 @@ from project_tools.api import register_tool from .permissions import PERMISSION_HISTORY_VIEW -# TODO: support permissions AND operand -# encapsulate into document_history_list and require DOCUMENT_VIEW and HISTORY_VIEW + history_list = {'text': _(u'history'), 'view': 'history_list', 'famfam': 'book', 'icon': 'book.png', 'permissions': [PERMISSION_HISTORY_VIEW], 'children_views': ['history_view']} register_tool(history_list) diff --git a/apps/history/permissions.py b/apps/history/permissions.py index 4d7b37a1eb..7de8447eb6 100644 --- a/apps/history/permissions.py +++ b/apps/history/permissions.py @@ -5,5 +5,4 @@ from django.utils.translation import ugettext_lazy as _ from permissions.models import PermissionNamespace, Permission history_namespace = PermissionNamespace('history', _(u'History')) - -PERMISSION_HISTORY_VIEW = Permission.objects.register(history_namespace, 'history_view', _(u'Access the history app')) +PERMISSION_HISTORY_VIEW = Permission.objects.register(history_namespace, 'history_view', _(u'Access the history of an object')) diff --git a/apps/history/views.py b/apps/history/views.py index ffd85e7e68..2212c7e5ef 100644 --- a/apps/history/views.py +++ b/apps/history/views.py @@ -7,9 +7,11 @@ from django.shortcuts import get_object_or_404 from django.contrib.contenttypes.models import ContentType from django.db.models.loading import get_model from django.http import Http404 +from django.core.exceptions import PermissionDenied from permissions.models import Permission from common.utils import encapsulate +from acls.models import AccessEntry from .models import History from .forms import HistoryDetailForm @@ -45,14 +47,17 @@ def history_list(request): def history_for_object(request, app_label, module_name, object_id): - Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) - model = get_model(app_label, module_name) if not model: raise Http404 content_object = get_object_or_404(model, pk=object_id) content_type = ContentType.objects.get_for_model(model) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_HISTORY_VIEW, request.user, content_object) + context = { 'object_list': History.objects.filter(content_type=content_type, object_id=object_id), 'title': _(u'history events for: %s') % content_object, @@ -75,9 +80,12 @@ def history_for_object(request, app_label, module_name, object_id): def history_view(request, object_id): - Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) - history = get_object_or_404(History, pk=object_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_HISTORY_VIEW, request.user, history.content_object) form = HistoryDetailForm(instance=history, extra_fields=[ {'label': _(u'Date'), 'field':lambda x: x.datetime.date()}, From 5de44256bcdcdbc23200c89476411f1e1cd68307 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:16:16 -0400 Subject: [PATCH 171/484] Improve coding style --- apps/metadata/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/metadata/forms.py b/apps/metadata/forms.py index 0653880301..e319ff3f92 100644 --- a/apps/metadata/forms.py +++ b/apps/metadata/forms.py @@ -6,8 +6,8 @@ from django.forms.formsets import formset_factory from common.widgets import ScrollableCheckboxSelectMultiple -from .conf.settings import (AVAILABLE_MODELS, AVAILABLE_FUNCTIONS) -from .models import (MetadataSet, MetadataType, DocumentTypeDefaults) +from .conf.settings import AVAILABLE_MODELS, AVAILABLE_FUNCTIONS +from .models import MetadataSet, MetadataType, DocumentTypeDefaults class MetadataForm(forms.Form): From 807444eddd242e479c1cd7d1b7058bcaf827d0b1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:16:40 -0400 Subject: [PATCH 172/484] User correct permission for the metadata view form header link, use proper coding style --- apps/metadata/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index 97f5de443a..c2d97b87d9 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -2,8 +2,8 @@ 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 navigation.api import (register_links, register_multi_item_links, + register_sidebar_template) from documents.models import Document, DocumentType from documents.permissions import PERMISSION_DOCUMENT_TYPE_EDIT from project_setup.api import register_setup @@ -19,7 +19,7 @@ from .permissions import (PERMISSION_METADATA_DOCUMENT_EDIT, 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]} From 24da6f4796c424f808599dc4a45bc65afcd2c443 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:17:44 -0400 Subject: [PATCH 173/484] Add ACL support to the metadata app --- apps/metadata/models.py | 20 +++++++++---------- apps/metadata/views.py | 43 +++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/apps/metadata/models.py b/apps/metadata/models.py index d827b615e5..1c7fda9249 100644 --- a/apps/metadata/models.py +++ b/apps/metadata/models.py @@ -12,9 +12,9 @@ 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, @@ -35,9 +35,9 @@ class MetadataType(models.Model): class MetadataSet(models.Model): - """ + ''' Define a group of metadata types - """ + ''' title = models.CharField(max_length=48, verbose_name=_(u'title')) def __unicode__(self): @@ -50,10 +50,10 @@ class MetadataSet(models.Model): class MetadataSetItem(models.Model): - """ + ''' Define the set of metadata that relates to a set or group of metadata fields - """ + ''' metadata_set = models.ForeignKey(MetadataSet, verbose_name=_(u'metadata set')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) #required = models.BooleanField(default=True, verbose_name=_(u'required')) @@ -67,10 +67,10 @@ class MetadataSetItem(models.Model): class DocumentMetadata(models.Model): - """ + ''' Link a document to a specific instance of a metadata type with it's current value - """ + ''' document = models.ForeignKey(Document, verbose_name=_(u'document')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'type')) value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value'), db_index=True) @@ -84,10 +84,10 @@ class DocumentMetadata(models.Model): 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/views.py b/apps/metadata/views.py index 101192e1e9..6f570beed8 100644 --- a/apps/metadata/views.py +++ b/apps/metadata/views.py @@ -8,11 +8,13 @@ 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.permissions import PERMISSION_DOCUMENT_TYPE_EDIT from documents.models import Document, RecentDocument, DocumentType 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.views import assign_remove @@ -32,8 +34,6 @@ from .models import (DocumentMetadata, MetadataType, MetadataSet, def metadata_edit(request, document_id=None, document_id_list=None): - Permission.objects.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: @@ -41,9 +41,15 @@ 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', '/')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) post_action_redirect = reverse('document_list_recent') @@ -123,15 +129,19 @@ def metadata_multiple_edit(request): def metadata_add(request, document_id=None, document_id_list=None): - Permission.objects.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', '/')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) for document in documents: RecentDocument.objects.add_document_for_user(request.user, document) @@ -187,8 +197,6 @@ def metadata_multiple_add(request): def metadata_remove(request, document_id=None, document_id_list=None): - Permission.objects.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: @@ -197,7 +205,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', '/')) @@ -276,9 +290,13 @@ def metadata_multiple_remove(request): def metadata_view(request, document_id): - Permission.objects.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(), @@ -288,6 +306,7 @@ def metadata_view(request, document_id): }, context_instance=RequestContext(request)) +# Setup views def setup_metadata_type_list(request): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_VIEW]) From 19b2412e039342ae8305e2866fe18ade7fed9311 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:26:31 -0400 Subject: [PATCH 174/484] Move the 'PERMISSION_DOCUMENT_NEW_VERSION' permission from the sources to the documents app --- apps/documents/__init__.py | 4 +++- apps/documents/permissions.py | 1 + apps/sources/__init__.py | 9 +++------ apps/sources/permissions.py | 3 --- apps/sources/views.py | 5 +++-- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index ad95e977d7..0fe9f1aecb 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -25,7 +25,8 @@ from .permissions import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_TOOLS, PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_TYPE_EDIT, PERMISSION_DOCUMENT_TYPE_DELETE, - PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW) + PERMISSION_DOCUMENT_TYPE_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW, + PERMISSION_DOCUMENT_NEW_VERSION) from .literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) from .conf.settings import ZOOM_MAX_LEVEL @@ -205,6 +206,7 @@ class_permissions(Document, [ PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, PERMISSION_DOCUMENT_TRANSFORM, + PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_HISTORY_VIEW ]) diff --git a/apps/documents/permissions.py b/apps/documents/permissions.py index 4dc1657570..93d6bda51a 100644 --- a/apps/documents/permissions.py +++ b/apps/documents/permissions.py @@ -15,6 +15,7 @@ PERMISSION_DOCUMENT_DOWNLOAD = Permission.objects.register(document_namespace, ' PERMISSION_DOCUMENT_TRANSFORM = Permission.objects.register(document_namespace, 'document_transform', _(u'Transform documents')) PERMISSION_DOCUMENT_TOOLS = Permission.objects.register(document_namespace, 'document_tools', _(u'Execute document modifying tools')) PERMISSION_DOCUMENT_VERSION_REVERT = Permission.objects.register(document_namespace, 'document_version_revert', _(u'Revert documents to a previous version')) +PERMISSION_DOCUMENT_NEW_VERSION = Permission.objects.register(document_namespace, 'document_new_version', _(u'Create new document versions')) documents_setup_namespace = PermissionNamespace('documents_setup', _(u'Documents setup')) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index ecdbe086a5..9fc8b93965 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -8,7 +8,8 @@ from permissions.models import Permission, PermissionNamespace from common.utils import encapsulate from project_setup.api import register_setup from documents.models import Document -from documents.permissions import PERMISSION_DOCUMENT_CREATE +from documents.permissions import (PERMISSION_DOCUMENT_CREATE, + PERMISSION_DOCUMENT_NEW_VERSION) from acls.api import class_permissions from .staging import StagingFile @@ -17,7 +18,7 @@ from .models import (WebForm, StagingFolder, SourceTransformation, 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, PERMISSION_DOCUMENT_NEW_VERSION) + 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} @@ -74,7 +75,3 @@ register_model_list_columns(StagingFile, [ ]) register_setup(setup_sources) - -class_permissions(Document, [ - PERMISSION_DOCUMENT_NEW_VERSION -]) diff --git a/apps/sources/permissions.py b/apps/sources/permissions.py index 119a366e11..e5911fe72c 100644 --- a/apps/sources/permissions.py +++ b/apps/sources/permissions.py @@ -9,6 +9,3 @@ PERMISSION_SOURCES_SETUP_VIEW = Permission.objects.register(sources_setup_namesp 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')) - -sources_namespace = PermissionNamespace('sources', _(u'Sources')) -PERMISSION_DOCUMENT_NEW_VERSION = Permission.objects.register(sources_namespace, 'sources_document_new_version', _(u'Create new document version')) diff --git a/apps/sources/views.py b/apps/sources/views.py index 290c467108..1f98826d2c 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -10,7 +10,8 @@ from django.utils.translation import ugettext from django.utils.safestring import mark_safe from django.conf import settings -from documents.permissions 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 @@ -32,7 +33,7 @@ from sources.forms import WebFormSetupForm, StagingFolderSetupForm from sources.forms import SourceTransformationForm, SourceTransformationForm_create from .permissions import (PERMISSION_SOURCES_SETUP_VIEW, PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE, - PERMISSION_SOURCES_SETUP_CREATE, PERMISSION_DOCUMENT_NEW_VERSION) + PERMISSION_SOURCES_SETUP_CREATE) def return_function(obj): From b89c55ed18951a04e0fef47d54c1def792dfd905 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:37:03 -0400 Subject: [PATCH 175/484] Codying style update, added comments --- apps/ocr/exceptions.py | 10 ++++++++-- apps/ocr/managers.py | 4 ++-- apps/ocr/models.py | 8 ++++---- apps/ocr/permissions.py | 1 - 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/ocr/exceptions.py b/apps/ocr/exceptions.py index 704e0ae9c7..0b6f4a129a 100644 --- a/apps/ocr/exceptions.py +++ b/apps/ocr/exceptions.py @@ -1,15 +1,21 @@ class AlreadyQueued(Exception): + ''' + Raised when a trying to queue document already in the queue + ''' pass class TesseractError(Exception): + ''' + Raised by tesseract + ''' pass class UnpaperError(Exception): - """ + ''' Raised by unpaper - """ + ''' pass diff --git a/apps/ocr/managers.py b/apps/ocr/managers.py index 13c98ece27..b4596356d6 100644 --- a/apps/ocr/managers.py +++ b/apps/ocr/managers.py @@ -6,10 +6,10 @@ 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 4457c3683d..3717f0ffe9 100644 --- a/apps/ocr/models.py +++ b/apps/ocr/models.py @@ -89,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) @@ -100,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/permissions.py b/apps/ocr/permissions.py index fefb6843ce..f74f1ec267 100644 --- a/apps/ocr/permissions.py +++ b/apps/ocr/permissions.py @@ -5,7 +5,6 @@ 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')) From 1f44b1bc6cb1edc70d9cca2c5574f168bc0854cd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:37:30 -0400 Subject: [PATCH 176/484] Add ACL support to the OCR app --- apps/ocr/__init__.py | 5 +++++ apps/ocr/views.py | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 403202b49f..bf2321c698 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -13,6 +13,7 @@ from permissions.models import Permission, PermissionNamespace from documents.models import Document 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 @@ -92,3 +93,7 @@ create_default_queue() 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/views.py b/apps/ocr/views.py index 6c37f62ce0..be640952b4 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -9,12 +9,14 @@ 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.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 .permissions import (PERMISSION_OCR_DOCUMENT, PERMISSION_OCR_DOCUMENT_DELETE, PERMISSION_OCR_QUEUE_ENABLE_DISABLE, @@ -126,15 +128,21 @@ def submit_document_multiple(request): def submit_document(request, document_id): - Permission.objects.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) @@ -331,6 +339,7 @@ def node_active_list(request): }, context_instance=RequestContext(request)) +# Setup views def setup_queue_transformation_list(request, document_queue_id): Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT]) From ebfb3e547f4d2a0200f307f03135cd10c11093fe Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:56:15 -0400 Subject: [PATCH 177/484] Comment style update --- apps/sources/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 6a00a8546f..8bf86d7a0c 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -220,9 +220,9 @@ class ArgumentsValidator(object): self.code = code def __call__(self, value): - """ + ''' Validates that the input evaluates correctly. - """ + ''' value = value.strip() try: literal_eval(value) @@ -231,10 +231,10 @@ class ArgumentsValidator(object): class SourceTransformation(models.Model): - """ + ''' Model that stores the transformation and transformation arguments for a given document source - """ + ''' content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') From 5ec2386ec16113972dd7cd5ee75e2dc3a6a7decf Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 04:56:25 -0400 Subject: [PATCH 178/484] Update the OCR app to apply auto OCR queueing to new document version not only to the initial document upload --- apps/ocr/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index bf2321c698..78f3f297c2 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -10,7 +10,7 @@ from django.dispatch import receiver from navigation.api import register_links, register_top_menu, register_multi_item_links from permissions.models import Permission, PermissionNamespace -from documents.models import Document +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 @@ -70,24 +70,25 @@ def create_default_queue(): 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) + DocumentQueue.objects.queue_document(instance.document) # 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): # logger.debug('got call_queue signal: %s' % kwargs) # task_process_document_queues() - create_default_queue() register_interval_job('task_process_document_queues', _(u'Checks the OCR queue for pending documents.'), task_process_document_queues, seconds=QUEUE_PROCESSING_INTERVAL) From c70f915b491a9d10120bd2d11c8048e1a87ebddd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 06:53:44 -0400 Subject: [PATCH 179/484] Add 'has_embedded_signature' helper method to the GPG class --- apps/django_gpg/api.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index ecda9a97a5..329ffe612e 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -278,6 +278,14 @@ class GPG(object): if not destination: return signed_data + def has_embedded_signature(self, *args, **kwargs): + try: + self.decrypt_file(*args, **kwargs) + except GPGDecryptionError: + return False + else: + return True + def decrypt_file(self, file_input, close_descriptor=True): input_descriptor = GPG.get_descriptor(file_input) From 6a8c86b0a4181dabe5b04052e629986d0225ddd6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 06:54:34 -0400 Subject: [PATCH 180/484] Add _post_save_hooks support to the DocumentVersion class --- apps/documents/models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/documents/models.py b/apps/documents/models.py index eb5da0f5cc..963a5e056f 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -279,6 +279,7 @@ class DocumentVersion(models.Model): Model that describes a document version and its properties ''' _pre_open_hooks = {} + _post_save_hooks = {} @staticmethod def get_version_update_choices(document_version): @@ -291,6 +292,10 @@ class DocumentVersion(models.Model): @classmethod def register_pre_open_hook(cls, order, func): cls._pre_open_hooks[order] = func + + @classmethod + def register_post_save_hook(cls, order, func): + cls._post_save_hooks[order] = func document = models.ForeignKey(Document, verbose_name=_(u'document'), editable=False) major = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1, editable=False) @@ -366,6 +371,9 @@ class DocumentVersion(models.Model): #Only do this for new documents transformations = kwargs.pop('transformations', None) super(DocumentVersion, self).save(*args, **kwargs) + + for key in sorted(DocumentVersion._post_save_hooks): + DocumentVersion._post_save_hooks[key](self) if new_document: #Only do this for new documents @@ -478,7 +486,7 @@ class DocumentVersion(models.Model): else: result = self.file.storage.open(self.file.path) for key in sorted(DocumentVersion._pre_open_hooks): - result = DocumentVersion._pre_open_hooks[key](result) + result = DocumentVersion._pre_open_hooks[key](result, self) return result From 4ded57f27decb3b5687f9706d894710ff74efade Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 06:55:08 -0400 Subject: [PATCH 181/484] Improved, simplified and optimized the document signature verification model and manager --- apps/document_signatures/__init__.py | 59 ++++++-- apps/document_signatures/managers.py | 73 +++------- ...versionsignature_has_embedded_signature.py | 133 +++++++++++++++++ .../0004_embedded_signature_state_copy.py | 136 ++++++++++++++++++ ...ocumentversionsignature_signature_state.py | 132 +++++++++++++++++ apps/document_signatures/models.py | 11 +- apps/document_signatures/permissions.py | 1 - 7 files changed, 478 insertions(+), 67 deletions(-) create mode 100644 apps/document_signatures/migrations/0003_auto__add_field_documentversionsignature_has_embedded_signature.py create mode 100644 apps/document_signatures/migrations/0004_embedded_signature_state_copy.py create mode 100644 apps/document_signatures/migrations/0005_auto__del_field_documentversionsignature_signature_state.py diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index e899fd4c18..cd9a120cc3 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -8,7 +8,8 @@ except ImportError: from StringIO import StringIO from django.utils.translation import ugettext_lazy as _ -from django.db.models.signals import post_save +#from django.db.models.signals import post_save +#from django.dispatch import receiver from documents.models import Document, DocumentVersion from navigation.api import register_links @@ -34,21 +35,50 @@ def doesnt_have_detached_signature(context): return DocumentVersionSignature.objects.has_detached_signature(context['object']) == False -def document_pre_open_hook(descriptor): - try: - result = gpg.decrypt_file(descriptor, close_descriptor=False) - # gpg return a string, turn it into a file like object - except GPGDecryptionError: - # At least return the original raw content - descriptor.seek(0) - return descriptor +def document_pre_open_hook(descriptor, instance): + if DocumentVersionSignature.objects.has_embedded_signature(instance.document): + # If it has an embedded signature decrypt + try: + result = gpg.decrypt_file(descriptor, close_descriptor=False) + # gpg return a string, turn it into a file like object + except GPGDecryptionError: + # At least return the original raw content + descriptor.seek(0) + return descriptor + else: + descriptor.close() + return StringIO(result.data) else: - return StringIO(result.data) + # It no embedded signature pass along + # Doing this single DB lookup avoids trying to decrypt non signed + # files always, which could result in slow down for big non signed + # files + #descriptor.seek(0) + return descriptor + + #try: + # result = gpg.decrypt_file(descriptor, close_descriptor=False) + # # gpg return a string, turn it into a file like object + #except GPGDecryptionError: + # # At least return the original raw content + # descriptor.seek(0) + # return descriptor + #else: + # descriptor.close() + # return StringIO(result.data) -def document_post_save(sender, instance, **kwargs): - if kwargs.get('created', False): - DocumentVersionSignature.objects.signature_state(instance.document) +def document_post_save_hook(instance): + if not instance.pk: + document_signature, created = DocumentVersionSignature.objects.get_or_create( + document_version=instance.latest_version, + ) + #DocumentVersionSignature.objects.update_signed_state(instance.document) + +#@receiver(post_save, dispatch_uid='check_document_signature_state', sender=DocumentVersion) +#def check_document_signature_state(sender, instance, **kwargs): +# if kwargs.get('created', False): +# DocumentVersionSignature.objects.signature_state(instance.document) document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} @@ -58,8 +88,7 @@ register_links(Document, [document_verify], menu_name='form_header') register_links(['document_verify', 'document_signature_upload', 'document_signature_download'], [document_signature_upload, document_signature_download], menu_name='sidebar') DocumentVersion.register_pre_open_hook(1, document_pre_open_hook) - -post_save.connect(document_post_save, sender=DocumentVersion) +DocumentVersion.register_post_save_hook(1, document_post_save_hook) class_permissions(Document, [ PERMISSION_DOCUMENT_VERIFY, diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index f4ed8c28f9..915fba4644 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -9,35 +9,31 @@ logger = logging.getLogger(__name__) class DocumentVersionSignatureManager(models.Manager): - #def update_signed_state(self, document): - # document_signature, created = self.model.get_or_create( - # document_version=document.latest_version, - # ) - # if document.exists(): - # descriptor = document.open() - # try: - # document_signature.signature_state = gpg.verify_file(descriptor).status - # # TODO: give use choice for auto public key fetch? - # # OR maybe new config option - # except GPGVerificationError: - # document_signature.signature_state = None - # finally: - # document_signature.save() - - def add_detached_signature(self, document, detached_signature): + def get_document_signature(self, document): document_signature, created = self.model.objects.get_or_create( document_version=document.latest_version, ) - if not self.signature_state(document): + + return document_signature + + def add_detached_signature(self, document, detached_signature): + document_signature = self.get_document_signature(document) + + if document_signature.has_embedded_signature: + raise Exception('document already has an embedded signature') + else: + if document_signature.signature_file: + logger.debug('Existing detached signature') + document_signature.delete_detached_signature() + document_signature.signature_file = None + document_signature.save() + document_signature.signature_file = detached_signature document_signature.save() - else: - raise Exception('document already has an embedded signature') def has_detached_signature(self, document): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) + document_signature = self.get_document_signature(document) + if document_signature.signature_file: return True else: @@ -46,36 +42,13 @@ class DocumentVersionSignatureManager(models.Manager): def has_embedded_signature(self, document): logger.debug('document: %s' % document) - if self.signature_state(document): - return True - else: - return False - - def signature_state(self, document): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) - logger.debug('created: %s' % created) - if created and document.exists(): - descriptor = document.open(raw=True) - try: - document_signature.signature_state = gpg.verify_file(descriptor).status - # TODO: give use choice for auto public key fetch? - # OR maybe new config option - except GPGVerificationError: - document_signature.signature_state = None - finally: - document_signature.save() - - #document_signature.signature_state = self.verify_signature(document).status - #document_signature.save() - - return document_signature.signature_state + document_signature = self.get_document_signature(document) + + return document_signature.has_embedded_signature def detached_signature(self, document): - document_signature, created = self.model.objects.get_or_create( - document_version=document.latest_version, - ) + document_signature = self.get_document_signature(document) + return document_signature.signature_file.storage.open(document_signature.signature_file.path) def verify_signature(self, document): diff --git a/apps/document_signatures/migrations/0003_auto__add_field_documentversionsignature_has_embedded_signature.py b/apps/document_signatures/migrations/0003_auto__add_field_documentversionsignature_has_embedded_signature.py new file mode 100644 index 0000000000..f75c27b0ce --- /dev/null +++ b/apps/document_signatures/migrations/0003_auto__add_field_documentversionsignature_has_embedded_signature.py @@ -0,0 +1,133 @@ +# 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 field 'DocumentVersionSignature.has_embedded_signature' + db.add_column('document_signatures_documentversionsignature', 'has_embedded_signature', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'DocumentVersionSignature.has_embedded_signature' + db.delete_column('document_signatures_documentversionsignature', 'has_embedded_signature') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_signatures.documentversionsignature': { + 'Meta': {'object_name': 'DocumentVersionSignature'}, + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'has_embedded_signature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'signature_state': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_signatures'] diff --git a/apps/document_signatures/migrations/0004_embedded_signature_state_copy.py b/apps/document_signatures/migrations/0004_embedded_signature_state_copy.py new file mode 100644 index 0000000000..9d14908825 --- /dev/null +++ b/apps/document_signatures/migrations/0004_embedded_signature_state_copy.py @@ -0,0 +1,136 @@ +# 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 document_signature in orm.DocumentVersionSignature.objects.all(): + if document_signature.signature_state: + document_signature.has_embedded_signature = True + else: + document_signature.has_embedded_signature = False + + document_signature.save() + + def backwards(self, orm): + # The content of signature_state is lost during the forward migration + # No way to revert + raise RuntimeError("Cannot reverse this migration.") + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_signatures.documentversionsignature': { + 'Meta': {'object_name': 'DocumentVersionSignature'}, + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'has_embedded_signature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'signature_state': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'blank': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_signatures'] diff --git a/apps/document_signatures/migrations/0005_auto__del_field_documentversionsignature_signature_state.py b/apps/document_signatures/migrations/0005_auto__del_field_documentversionsignature_signature_state.py new file mode 100644 index 0000000000..11084f6aa1 --- /dev/null +++ b/apps/document_signatures/migrations/0005_auto__del_field_documentversionsignature_signature_state.py @@ -0,0 +1,132 @@ +# 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): + + # Deleting field 'DocumentVersionSignature.signature_state' + db.delete_column('document_signatures_documentversionsignature', 'signature_state') + + + def backwards(self, orm): + + # Adding field 'DocumentVersionSignature.signature_state' + db.add_column('document_signatures_documentversionsignature', 'signature_state', self.gf('django.db.models.fields.CharField')(max_length=16, null=True, blank=True), keep_default=False) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_signatures.documentversionsignature': { + 'Meta': {'object_name': 'DocumentVersionSignature'}, + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'has_embedded_signature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'signature_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_signatures'] diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 0f82666b84..2c15523574 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import DocumentVersion, get_filename_from_uuid from documents.conf.settings import STORAGE_BACKEND +from django_gpg.runtime import gpg from .managers import DocumentVersionSignatureManager @@ -17,11 +18,19 @@ class DocumentVersionSignature(models.Model): Model that describes a document version signature properties ''' document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'), editable=False) - signature_state = models.CharField(blank=True, null=True, max_length=16, verbose_name=_(u'signature state'), editable=False) signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) + has_embedded_signature = models.BooleanField(default=False, verbose_name=_(u'has embedded signature'), editable=False) objects = DocumentVersionSignatureManager() + def delete_detached_signature(self): + self.signature_file.storage.delete(self.signature_file.path) + + def save(self, *args, **kwargs): + if not self.pk: + self.has_embedded_signature = gpg.has_embedded_signature(self.document_version.open(raw=True)) + super(DocumentVersionSignature, self).save(*args, **kwargs) + class Meta: verbose_name = _(u'document version signature') verbose_name_plural = _(u'document version signatures') diff --git a/apps/document_signatures/permissions.py b/apps/document_signatures/permissions.py index 477f649357..e4f05bc1b7 100644 --- a/apps/document_signatures/permissions.py +++ b/apps/document_signatures/permissions.py @@ -5,7 +5,6 @@ from django.utils.translation import ugettext_lazy as _ from permissions.models import PermissionNamespace, Permission document_signatures_namespace = PermissionNamespace('document_signatures', _(u'Document signatures')) - PERMISSION_DOCUMENT_VERIFY = Permission.objects.register(document_signatures_namespace, 'document_verify', _(u'Verify document signatures')) PERMISSION_SIGNATURE_UPLOAD = Permission.objects.register(document_signatures_namespace, 'signature_upload', _(u'Upload detached signatures')) PERMISSION_SIGNATURE_DOWNLOAD = Permission.objects.register(document_signatures_namespace, 'signature_download', _(u'Download detached signatures')) From 1cd3c4e7d0f87dabb53a566de92dc9c2a59b4927 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 18:47:28 -0400 Subject: [PATCH 182/484] Add related support to 'filter_objects_by_access' and 'get_allowed_class_objects' methods --- apps/acls/managers.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 6d674bbc59..0b22db3cbd 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -95,11 +95,20 @@ class AccessEntryManager(models.Manager): raise PermissionDenied(ugettext(u'Insufficient access.')) - def get_allowed_class_objects(self, permission, actor, cls): + def get_allowed_class_objects(self, permission, actor, cls, related=None): + logger.debug('related: %s' % related) + actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) - - return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) + if related: + master_list = [obj.content_object for obj in self.model.objects.select_related().filter(holder_type=actor_type, holder_id=actor.pk, permission=permission.get_stored_permission)] + logger.debug('master_list: %s' % master_list) + # TODO: update to use Q objects and check performance diff + # kwargs = {'%s__in' % related: master_list} + # Q(**kwargs) + return (obj for obj in cls.objects.all() if getattr(obj, related) in master_list) + else: + return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) @@ -132,7 +141,7 @@ class AccessEntryManager(models.Manager): content_type = ContentType.objects.get_for_model(obj) return (access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=actor_type, holder_id=actor.pk)) - def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False): + def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False, related=None): logger.debug('exception_on_empty: %s' % exception_on_empty) logger.debug('object_list: %s' % object_list) @@ -150,7 +159,7 @@ class AccessEntryManager(models.Manager): try: # Try to process as a QuerySet - qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0])]) + qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0].__class__, related)]) logger.debug('qs: %s' % qs) if qs.count() == 0 and exception_on_empty == True: @@ -158,13 +167,13 @@ class AccessEntryManager(models.Manager): return qs except AttributeError: - # Fallback to a list filtered list - obj_list = list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0]))) - logger.debug('obj_list: %s' % obj_list) - if len(obj_list) == 0 and exception_on_empty == True: + # Fallback to a filtered list + object_list = list(set(object_list) & set(self.get_allowed_class_objects(permission, actor, object_list[0].__class__, related))) + logger.debug('object_list: %s' % object_list) + if len(object_list) == 0 and exception_on_empty == True: raise PermissionDenied - return obj_list + return object_list class DefaultAccessEntryManager(models.Manager): From 268c1386f09c9abd329a670264a9f3dd3b6f5196 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 18:48:12 -0400 Subject: [PATCH 183/484] Remove the unimplemented PERMISSION_COMMENT_EDIT permission --- apps/document_comments/permissions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/document_comments/permissions.py b/apps/document_comments/permissions.py index 820a16ede5..37e1391b61 100644 --- a/apps/document_comments/permissions.py +++ b/apps/document_comments/permissions.py @@ -8,5 +8,4 @@ comments_namespace = PermissionNamespace('comments', _(u'Comments')) PERMISSION_COMMENT_CREATE = Permission.objects.register(comments_namespace, 'comment_create', _(u'Create new comments')) PERMISSION_COMMENT_DELETE = Permission.objects.register(comments_namespace, 'comment_delete', _(u'Delete comments')) -PERMISSION_COMMENT_EDIT = Permission.objects.register(comments_namespace, 'comment_edit', _(u'Edit comments')) PERMISSION_COMMENT_VIEW = Permission.objects.register(comments_namespace, 'comment_view', _(u'View comments')) From ffd90c03406a9b109dec955144fa44aad86e8ff3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 18:48:42 -0400 Subject: [PATCH 184/484] Remove unneeded module --- apps/document_comments/utils.py | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 apps/document_comments/utils.py diff --git a/apps/document_comments/utils.py b/apps/document_comments/utils.py deleted file mode 100644 index cca6e07098..0000000000 --- a/apps/document_comments/utils.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import absolute_import - -from django.utils.translation import ugettext_lazy as _ -from django.contrib.comments.models import Comment -from . import comment_delete - - -def get_comments_subtemplate(obj): - """ - Return all the settings to render a subtemplate containing an - object's comments - """ - return { - 'name': 'generic_list_subtemplate.html', - 'context': { - 'title': _(u'comments'), - 'object_list': Comment.objects.for_model(obj).order_by('-submit_date'), - 'hide_link': True, - 'hide_object': True, - 'navigation_object_links': [comment_delete], - 'scrollable_content': True, - 'scrollable_content_height': '200px', - } - } From edd344b924da6dfebb7a102d846c9797ff70fd85 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 3 Jan 2012 18:49:03 -0400 Subject: [PATCH 185/484] Add ACL support to the document comments app --- apps/document_comments/__init__.py | 17 +++++++++------ apps/document_comments/urls.py | 8 +++---- apps/document_comments/views.py | 34 +++++++++++++++++++++--------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/apps/document_comments/__init__.py b/apps/document_comments/__init__.py index 5d4cdec3bb..6758a06811 100644 --- a/apps/document_comments/__init__.py +++ b/apps/document_comments/__init__.py @@ -8,20 +8,19 @@ from django.contrib.contenttypes import generic from navigation.api import register_links, register_model_list_columns from permissions.models import PermissionNamespace, Permission from common.utils import encapsulate - +from acls.api import class_permissions from documents.models import Document if 'django.contrib.comments' not in settings.INSTALLED_APPS: raise Exception('This app depends on the django.contrib.comments app.') from .permissions import (PERMISSION_COMMENT_CREATE, - PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_EDIT, - PERMISSION_COMMENT_VIEW) + PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_VIEW) comment_delete = {'text': _('delete'), 'view': 'comment_delete', 'args': 'object.pk', 'famfam': 'comment_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_multiple_delete = {'text': _('delete'), 'view': 'comment_multiple_delete', 'args': 'object.pk', 'famfam': 'comments_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_add = {'text': _('add comment'), 'view': 'comment_add', 'args': 'object.pk', 'famfam': 'comment_add', 'permissions': [PERMISSION_COMMENT_CREATE]} -comments_for_object = {'text': _('comments'), 'view': 'comments_for_object', 'args': 'object.pk', 'famfam': 'comments', 'permissions': [PERMISSION_COMMENT_VIEW], 'children_view_regex': ['comment']} +comments_for_document = {'text': _('comments'), 'view': 'comments_for_document', 'args': 'object.pk', 'famfam': 'comments', 'permissions': [PERMISSION_COMMENT_VIEW], 'children_view_regex': ['comment']} register_model_list_columns(Comment, [ { @@ -38,9 +37,9 @@ register_model_list_columns(Comment, [ } ]) -register_links(['comments_for_object', 'comment_add', 'comment_delete', 'comment_multiple_delete'], [comment_add], menu_name='sidebar') +register_links(['comments_for_document', 'comment_add', 'comment_delete', 'comment_multiple_delete'], [comment_add], menu_name='sidebar') register_links(Comment, [comment_delete]) -register_links(Document, [comments_for_object], menu_name='form_header') +register_links(Document, [comments_for_document], menu_name='form_header') Document.add_to_class( 'comments', @@ -50,3 +49,9 @@ Document.add_to_class( object_id_field='object_pk' ) ) + +class_permissions(Document, [ + PERMISSION_COMMENT_CREATE, + PERMISSION_COMMENT_DELETE, + PERMISSION_COMMENT_VIEW +]) diff --git a/apps/document_comments/urls.py b/apps/document_comments/urls.py index f977004825..d9230c22d5 100644 --- a/apps/document_comments/urls.py +++ b/apps/document_comments/urls.py @@ -1,8 +1,8 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('document_comments.views', - url(r'^(?P\d+)/delete/$', 'comment_delete', (), 'comment_delete'), - url(r'^multiple/delete/$', 'comment_multiple_delete', (), 'comment_multiple_delete'), - url(r'^add_to_document/(?P\d+)/$', 'comment_add', (), 'comment_add'), - url(r'^for/object/(?P\d+)/$', 'comments_for_object', (), 'comments_for_object'), + url(r'^comment/(?P\d+)/delete/$', 'comment_delete', (), 'comment_delete'), + url(r'^comment/multiple/delete/$', 'comment_multiple_delete', (), 'comment_multiple_delete'), + url(r'^(?P\d+)/comment/add/$', 'comment_add', (), 'comment_add'), + url(r'^(?P\d+)/comment/list/$', 'comments_for_document', (), 'comments_for_document'), ) diff --git a/apps/document_comments/views.py b/apps/document_comments/views.py index 9e474a2cb6..cb9cc0a92e 100644 --- a/apps/document_comments/views.py +++ b/apps/document_comments/views.py @@ -8,27 +8,33 @@ from django.template import RequestContext from django.contrib import messages from django.contrib.contenttypes.models import ContentType from django.contrib.sites.models import Site +from django.core.exceptions import PermissionDenied +from acls.models import AccessEntry from permissions.models import Permission from documents.models import Document from .permissions import (PERMISSION_COMMENT_CREATE, - PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_EDIT, - PERMISSION_COMMENT_VIEW) + PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_VIEW) from .forms import CommentForm def comment_delete(request, comment_id=None, comment_id_list=None): - Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_DELETE]) post_action_redirect = None if comment_id: comments = [get_object_or_404(Comment, pk=comment_id)] elif comment_id_list: comments = [get_object_or_404(Comment, pk=comment_id) for comment_id in comment_id_list.split(',')] - else: + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_DELETE]) + except PermissionDenied: + comments = AccessEntry.objects.filter_objects_by_access(PERMISSION_COMMENT_DELETE, request.user, comments, related='content_object') + + if not comments: messages.error(request, _(u'Must provide at least one comment.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) 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', '/'))) @@ -69,9 +75,13 @@ def comment_multiple_delete(request): def comment_add(request, document_id): - Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_CREATE]) - document = get_object_or_404(Document, pk=document_id) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_CREATE]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_COMMENT_CREATE, request.user, document) + post_action_redirect = None next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) @@ -99,16 +109,20 @@ def comment_add(request, document_id): }, context_instance=RequestContext(request)) -def comments_for_object(request, document_id): +def comments_for_document(request, document_id): ''' Show a list of all the comments related to the passed object ''' - Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_VIEW]) - document = get_object_or_404(Document, pk=document_id) + try: + Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_COMMENT_VIEW, request.user, document) + return render_to_response('generic_list.html', { 'object': document, + 'access_object': document, 'title': _(u'comments: %s') % document, 'object_list': Comment.objects.for_model(document).order_by('-submit_date'), 'hide_link': True, From dfcf2b8b17fd4b9903ff79862f32f2384acd0fc3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 4 Jan 2012 02:08:50 -0400 Subject: [PATCH 186/484] Add generic class for handling reading, appending and creating Zip files --- apps/common/compressed_files.py | 84 +++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 apps/common/compressed_files.py diff --git a/apps/common/compressed_files.py b/apps/common/compressed_files.py new file mode 100644 index 0000000000..6737bbc9ed --- /dev/null +++ b/apps/common/compressed_files.py @@ -0,0 +1,84 @@ +import os, tempfile, zipfile + +try: + import zlib + COMPRESSION = zipfile.ZIP_DEFLATED +except: + COMPRESSION = zipfile.ZIP_STORED + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +from django.core.files.uploadedfile import SimpleUploadedFile + + +class NotACompressedFile(Exception): + pass + + +class CompressedFile(object): + def __init__(self, file_input=None): + if file_input: + self._open(file_input) + else: + self._create() + + def _create(self): + self.descriptor = StringIO() + self.zf = zipfile.ZipFile(self.descriptor, mode='w') + + def _open(self, file_input): + try: + # Is it a file like object? + file_input.seek(0) + except AttributeError: + # If not, try open it. + self.descriptor = open(file_input, 'r+b') + else: + self.descriptor = file_input + + try: + test = zipfile.ZipFile(self.descriptor, mode='r') + except zipfile.BadZipfile: + raise NotACompressedFile + else: + test.close() + self.descriptor.seek(0) + self.zf = zipfile.ZipFile(self.descriptor, mode='a') + + def add_file(self, file_input, arcname=None): + try: + # Is it a file like object? + file_input.seek(0) + except AttributeError: + # If not, keep it + self.zf.write(filename, arcname=arcname, compress_type=COMPRESSION) + else: + self.zf.writestr(arcname, file_input.read()) + + def contents(self): + return [filename for filename in self.zf.namelist() if not filename.endswith('/')] + + def get_content(self, filename): + return self.zf.read(filename) + + def write(self, filename=None): + # fix for Linux zip files read in Windows + for file in self.zf.filelist: + file.create_system = 0 + + self.descriptor.seek(0) + + if filename: + descriptor = open(filename, 'w') + descriptor.write(self.descriptor.read()) + else: + return self.descriptor + + def as_file(self, filename): + return SimpleUploadedFile(name=filename, content=self.write().read()) + + def close(self): + self.zf.close() From 3a517036d1f3d546f82a2250eccbfea247442901 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 4 Jan 2012 02:09:30 -0400 Subject: [PATCH 187/484] Add bulk download support to the document app --- apps/documents/__init__.py | 9 +++-- apps/documents/urls.py | 1 + apps/documents/views.py | 81 +++++++++++++++++++++++++++++--------- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 0fe9f1aecb..aa8ec09269 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -5,9 +5,9 @@ import tempfile from django.utils.translation import ugettext_lazy as _ from common.utils import validate_path, encapsulate -from navigation.api import register_links, register_top_menu, \ - register_model_list_columns, register_multi_item_links, \ - register_sidebar_template +from navigation.api import (register_links, register_top_menu, + register_model_list_columns, register_multi_item_links, + register_sidebar_template) from main.api import register_diagnostic, register_maintenance_links from tags.widgets import get_tags_inline_widget_simple from history.api import register_history_type @@ -70,6 +70,7 @@ document_multiple_delete = {'text': _(u'delete'), 'view': 'document_multiple_del document_edit = {'text': _(u'edit'), 'view': 'document_edit', 'args': 'object.id', 'famfam': 'page_edit', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]} document_preview = {'text': _(u'preview'), 'class': 'fancybox', 'view': 'document_preview', 'args': 'object.id', 'famfam': 'magnifier', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_download = {'text': _(u'download'), 'view': 'document_download', 'args': 'object.id', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} +document_multiple_download = {'text': _(u'download'), 'view': 'document_multiple_download', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} document_version_download = {'text': _(u'download'), 'view': 'document_version_download', 'args': 'object.pk', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} document_find_duplicates = {'text': _(u'find duplicates'), 'view': 'document_find_duplicates', 'args': 'object.id', 'famfam': 'page_white_copy', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_find_all_duplicates = {'text': _(u'find all duplicates'), 'view': 'document_find_all_duplicates', 'famfam': 'page_white_copy', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'description': _(u'Search all the documents\' checksums and return a list of the exact matches.')} @@ -130,7 +131,7 @@ register_links(['document_type_filename_create', 'document_type_filename_list', # Register document links register_links(Document, [document_edit, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations, document_create_siblings]) -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'], [document_multiple_clear_transformations, document_multiple_delete]) +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'], [document_multiple_clear_transformations, document_multiple_delete, document_multiple_download]) # Document Version links register_links(DocumentVersion, [document_version_revert, document_version_download]) diff --git a/apps/documents/urls.py b/apps/documents/urls.py index 8818543380..046d274dd8 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -29,6 +29,7 @@ urlpatterns = patterns('documents.views', url(r'^(?P\d+)/display/thumbnail/base64/$', 'get_document_image', {'size': THUMBNAIL_SIZE, 'base64_version': True}, 'document_thumbnail_base64'), url(r'^(?P\d+)/download/$', 'document_download', (), 'document_download'), + url(r'^multiple/download/$', 'document_multiple_download', (), 'document_multiple_download'), url(r'^(?P\d+)/create/siblings/$', 'document_create_siblings', (), 'document_create_siblings'), url(r'^(?P\d+)/find_duplicates/$', 'document_find_duplicates', (), 'document_find_duplicates'), url(r'^(?P\d+)/clear_transformations/$', 'document_clear_transformations', (), 'document_clear_transformations'), diff --git a/apps/documents/views.py b/apps/documents/views.py index 14ec65e855..a5deae4f53 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -13,6 +13,7 @@ from django.views.generic.list_detail import object_list from django.core.urlresolvers import reverse from django.utils.http import urlencode from django.core.exceptions import PermissionDenied +from django.conf import settings import sendfile from common.utils import pretty_size, parse_range, urlquote, \ @@ -31,6 +32,7 @@ from permissions.models import Permission from document_indexing.api import update_indexes, delete_indexes from history.api import create_history from acls.models import AccessEntry +from common.compressed_files import CompressedFile from .conf.settings import (PREVIEW_SIZE, STORAGE_BACKEND, ZOOM_PERCENT_STEP, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL, ROTATION_STEP, PRINT_SIZE, @@ -317,31 +319,72 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F return sendfile.sendfile(request, document.get_image(size=size, page=page, zoom=zoom, rotation=rotation, version=version), mimetype=DEFAULT_FILE_FORMAT_MIMETYPE) -def document_download(request, document_id=None, document_version_pk=None): - if document_version_pk: +def document_download(request, document_id=None, document_id_list=None, document_version_pk=None): + document_version = None + documents = [] + + if document_id: + documents = [get_object_or_404(Document, pk=document_id)] + post_action_redirect = reverse('document_list') + elif document_id_list: + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + elif document_version_pk: document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) - else: - document_version = get_object_or_404(Document, pk=document_id).latest_version try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_DOWNLOAD, request.user, document_version.document) - - try: - # Test permissions and trigger exception - fd = document_version.open() - fd.close() - return serve_file( - request, - document_version.file, - save_as=u'"%s"' % document_version.filename, - content_type=document_version.mimetype if document_version.mimetype else 'application/octet-stream' - ) - except Exception, e: - messages.error(request, e) - return HttpResponseRedirect(request.META['HTTP_REFERER']) + documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DOWNLOAD, request.user, documents, exception_on_empty=True) + if len(documents) == 1: + document_version = documents[0].latest_version + + if document_version: + try: + # Test permissions and trigger exception + fd = document_version.open() + fd.close() + return serve_file( + request, + document_version.file, + save_as=u'"%s"' % document_version.filename, + content_type=document_version.mimetype if document_version.mimetype else 'application/octet-stream' + ) + except Exception, e: + if settings.DEBUG: + raise + else: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) + else: + try: + compressed_file = CompressedFile() + for document in documents: + descriptor = document.open() + compressed_file.add_file(descriptor, arcname=document.filename) + descriptor.close() + + compressed_file.close() + + return serve_file( + request, + compressed_file.as_file('document_bundle.zip'), + save_as=u'"document_bundle.zip"', + content_type='application/zip' + ) + # TODO: DO a redirection afterwards + except Exception, e: + if settings.DEBUG: + raise + else: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) + + +def document_multiple_download(request): + return document_download( + request, document_id_list=request.GET.get('id_list', []) + ) def document_page_transformation_list(request, document_page_id): document_page = get_object_or_404(DocumentPage, pk=document_page_id) From eb267cae1084df2c82eb6409e777846a4118c41b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:18:42 -0400 Subject: [PATCH 188/484] Add a Singleton Model class and an AnonymousUserSingleton model to support adding permissions and access to anonymous users --- apps/common/models.py | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/apps/common/models.py b/apps/common/models.py index 71a8362390..1e174119bb 100644 --- a/apps/common/models.py +++ b/apps/common/models.py @@ -1,3 +1,43 @@ from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import AnonymousUser -# Create your models here. +SINGLETON_LOCK_ID = 1 + + +class SingletonManager(models.Manager): + def get(self, **kwargs): + instance, created = self.model.objects.get_or_create(lock_id=SINGLETON_LOCK_ID, **kwargs) + return instance + + +class Singleton(models.Model): + lock_id = models.CharField(max_length=1, default=SINGLETON_LOCK_ID, editable=False, verbose_name=_(u'lock field'), unique=True) + + objects = SingletonManager() + + def save(self, *args, **kwargs): + self.id = 1 + super(Singleton, self).save(*args, **kwargs) + + def delete(self): + pass + + class Meta: + abstract = True + + +class AnonymousUserSingletonManager(SingletonManager): + def passthru_check(self, user): + if isinstance(user, AnonymousUser): + return self.model.objects.get() + else: + return user + + +class AnonymousUserSingleton(Singleton): + objects = AnonymousUserSingletonManager() + + class Meta: + verbose_name = _(u'anonymous user') + verbose_name_plural = _(u'anonymous user') From a020b011dcbf61cd1679761b78d4d4cf509bf2e5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:20:39 -0400 Subject: [PATCH 189/484] Expose main app properties as project properties --- __init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/__init__.py b/__init__.py index e69de29bb2..a373a640b0 100644 --- a/__init__.py +++ b/__init__.py @@ -0,0 +1,2 @@ +from main import (__version__, __author__, __copyright__, __credits__, + __license__, __maintainer__, __email__, __status__) From 28000ccfec34585f526bbd0791420187d226bed0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:21:22 -0400 Subject: [PATCH 190/484] Add proper permission checking to the ACL setup view links --- apps/acls/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 5ca2e83361..eae1816727 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -15,11 +15,11 @@ acl_detail = {'text': _(u'details'), 'view': 'acl_detail', 'args': ['access_obje acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} -acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png'}#, 'permissions': [ACLS_EDIT_ACL]} -acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package'}#, 'permissions': [ACLS_EDIT_ACL]} -acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock'}#, 'permissions': [ACLS_VIEW_ACL]} -acls_class_acl_detail = {'text': _(u'edit'), 'view': 'acls_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -acl_class_new_holder_for = {'text': _(u'New holder'), 'view': 'acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user'}#, 'permissions': [ACLS_VIEW_ACL]} +acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png', 'permissions': [ACLS_CLASS_VIEW_ACL]} +acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package', 'permissions': [ACLS_CLASS_VIEW_ACL]} +acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock', 'permissions': [ACLS_CLASS_VIEW_ACL]} +acl_class_acl_detail = {'text': _(u'edit'), 'view': 'acls_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'lock', 'permissions': [ACLS_CLASS_VIEW_ACL]} +acl_class_new_holder_for = {'text': _(u'New holder'), 'view': 'acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user', 'permissions': [ACLS_CLASS_EDIT_ACL]} acl_class_grant = {'text': _(u'grant'), 'view': 'acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_CLASS_EDIT_ACL]} acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_CLASS_EDIT_ACL]} @@ -27,9 +27,9 @@ register_links(AccessHolder, [acl_detail]) register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) register_setup(acl_setup_valid_classes) -register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acls_class_acl_detail'], [acl_class_list], menu_name='sidebar') +register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acl_class_acl_detail'], [acl_class_list], menu_name='sidebar') -register_links(ClassAccessHolder, [acls_class_acl_detail]) +register_links(ClassAccessHolder, [acl_class_acl_detail]) register_links(AccessObjectClass, [acl_class_acl_list]) register_links(AccessObjectClass, [acl_class_new_holder_for]) From d0acea071415a8fc8b82ab3cb22aaa51b6944f55 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:22:03 -0400 Subject: [PATCH 191/484] Add anonymous user support to the object encapsulator class --- apps/acls/classes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/acls/classes.py b/apps/acls/classes.py index 1b6820c9e6..bcca9a6971 100644 --- a/apps/acls/classes.py +++ b/apps/acls/classes.py @@ -2,9 +2,12 @@ import logging import sys import types +from django.db import models from django.contrib.contenttypes.models import ContentType from django.db.models.base import ModelBase +from common.models import AnonymousUserSingleton + logger = logging.getLogger(__name__) _cache = {} @@ -27,6 +30,7 @@ class EncapsulatedObject(object): @classmethod def encapsulate(cls, source_object=None, app_label=None, model=None, pk=None): if source_object: + source_object = AnonymousUserSingleton.objects.passthru_check(source_object) content_type = ContentType.objects.get_for_model(source_object) elif app_label and model: try: From b9f7939e3ee40c38e999e933b5b06a3c10793b0d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:22:55 -0400 Subject: [PATCH 192/484] Add the anonymous user singleton to the list of avaible holder for an acl --- apps/acls/forms.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 8adfaef90e..13777cf98e 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -6,6 +6,7 @@ from django.contrib.auth.models import User, Group from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate, get_object_name +from common.models import AnonymousUserSingleton from .classes import AccessHolder @@ -39,5 +40,7 @@ class HolderSelectionForm(forms.Form): if roles: non_holder_list.append((_(u'Roles'), _as_choice_list(list(roles)))) + non_holder_list.append((_(u'Special'), _as_choice_list([AnonymousUserSingleton.get()]))) + super(HolderSelectionForm, self).__init__(*args, **kwargs) self.fields['holder_gid'].choices = non_holder_list From 595e901b64ac78970248168aa700b2bbcf34aff1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:24:04 -0400 Subject: [PATCH 193/484] Add anonymous user support to the acl model manager methods --- apps/acls/managers.py | 7 ++++++- apps/acls/models.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 0b22db3cbd..a2cb9ff17f 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -9,6 +9,8 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied +from common.models import AnonymousUserSingleton + from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder logger = logging.getLogger(__name__) @@ -65,6 +67,8 @@ class AccessEntryManager(models.Manager): if actor.is_superuser or actor.is_staff: return True + actor = AnonymousUserSingleton.objects.passthru_check(actor) + try: access_entry = self.model.objects.get( permission=permission.get_stored_permission(), @@ -97,7 +101,8 @@ class AccessEntryManager(models.Manager): def get_allowed_class_objects(self, permission, actor, cls, related=None): logger.debug('related: %s' % related) - + + actor = AnonymousUserSingleton.objects.passthru_check(actor) actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) if related: diff --git a/apps/acls/models.py b/apps/acls/models.py index b175601949..7aa847a88d 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -19,7 +19,7 @@ from .managers import AccessEntryManager, DefaultAccessEntryManager logger = logging.getLogger(__name__) - + class AccessEntry(models.Model): ''' Model that hold the permission, object, actor relationship From 33513d34a582d0c53ca66ef2985f3376fb03c0f8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:25:54 -0400 Subject: [PATCH 194/484] Remove remarked code --- apps/acls/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index 25445a9bbc..f0332fe33e 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -50,8 +50,6 @@ def acl_list_for(request, obj, extra_context=None): context = { 'object_list': AccessEntry.objects.get_holders_for(obj), 'title': _(u'access control lists for: %s' % obj), - #'multi_select_as_buttons': True, - #'hide_links': True, 'extra_columns': [ {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, From df5f50f5d47b4f80324a1e03c61181214a8de0e8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:28:26 -0400 Subject: [PATCH 195/484] Cleanup auto admin user creation using receiver decorator --- apps/common/__init__.py | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index 4212752ca8..b0557cce5c 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -6,6 +6,8 @@ from django.utils.translation import ugettext_lazy as _ from django.contrib.auth import models as auth_models from django.contrib.auth.management import create_superuser from django.db.models import signals +from django.dispatch import receiver +from django.db.models.signals import post_syncdb from navigation.api import register_links, register_top_menu @@ -31,34 +33,37 @@ register_links(['about_view', 'changelog_view', 'license_view'], [about_view, ch register_top_menu('about', link={'text': _(u'about'), 'view': 'about_view', 'famfam': 'information'}, position=-1) -if common_settings.AUTO_CREATE_ADMIN: - # From https://github.com/lambdalisue/django-qwert/blob/master/qwert/autoscript/__init__.py - # From http://stackoverflow.com/questions/1466827/ -- - # - # Prevent interactive question about wanting a superuser created. (This code - # has to go in this otherwise empty "models" module so that it gets processed by - # the "syncdb" command during database creation.) - # - # Create our own test user automatically. +#if common_settings.AUTO_CREATE_ADMIN: +# # From https://github.com/lambdalisue/django-qwert/blob/master/qwert/autoscript/__init__.py +# # From http://stackoverflow.com/questions/1466827/ -- +# # +# # Prevent interactive question about wanting a superuser created. (This code +# # has to go in this otherwise empty "models" module so that it gets processed by +# # the "syncdb" command during database creation.) +# # +# # Create our own admin super user automatically. - def create_testuser(app, created_models, verbosity, **kwargs): +@receiver(post_syncdb, dispatch_uid='create_superuser', sender=auth_models) +#def create_superuser(app, created_models, verbosity, **kwargs): +def create_superuser(sender, **kwargs): + if common_settings.AUTO_CREATE_ADMIN: USERNAME = common_settings.AUTO_ADMIN_USERNAME PASSWORD = common_settings.AUTO_ADMIN_PASSWORD try: auth_models.User.objects.get(username=USERNAME) except auth_models.User.DoesNotExist: print '*' * 80 - print 'Creating test user -- login: %s, password: %s' % (USERNAME, PASSWORD) + print 'Creating super admin user -- login: %s, password: %s' % (USERNAME, PASSWORD) print '*' * 80 assert auth_models.User.objects.create_superuser(USERNAME, 'x@x.com', PASSWORD) else: - print 'Test user already exists. -- login: %s, password: %s' % (USERNAME, PASSWORD) - signals.post_syncdb.disconnect( - create_superuser, - sender=auth_models, - dispatch_uid='django.contrib.auth.management.create_superuser') - signals.post_syncdb.connect(create_testuser, - sender=auth_models, dispatch_uid='common.models.create_testuser') + print 'Super admin user already exists. -- login: %s, password: %s' % (USERNAME, PASSWORD) +#signals.post_syncdb.disconnect( +# create_superuser, +# sender=auth_models, +# dispatch_uid='django.contrib.auth.management.create_superuser') +#signals.post_syncdb.connect(create_testuser, +# sender=auth_models, dispatch_uid='common.models.create_testuser') if (validate_path(common_settings.TEMPORARY_DIRECTORY) == False) or (not common_settings.TEMPORARY_DIRECTORY): setattr(common_settings, 'TEMPORARY_DIRECTORY', tempfile.mkdtemp()) From fa94288317ca7911ffdd32180ab8cf38bae44c1f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:29:03 -0400 Subject: [PATCH 196/484] Only add the sentry and admin add and icons if they corresponding apps have been installed --- apps/main/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index b3c1b6a1e8..842c5d11ab 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ +from django.conf import settings from navigation.api import register_top_menu from navigation.api import register_links @@ -55,8 +56,12 @@ def get_version(): __version__ = get_version() -register_setup(admin_site) +if 'django.contrib.admin' in settings.INSTALLED_APPS: + register_setup(admin_site) + register_tool(maintenance_menu) register_tool(statistics) register_tool(diagnostics) -register_tool(sentry) + +if 'sentry' in settings.INSTALLED_APPS: + register_tool(sentry) From 51b63e86de651a7bb50f808ce5ee2679cf37665b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:29:42 -0400 Subject: [PATCH 197/484] Add corresponding permission check to the source app view links --- apps/sources/__init__.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 9fc8b93965..62027a4734 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -23,21 +23,21 @@ from .permissions import (PERMISSION_SOURCES_SETUP_VIEW, 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]} +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_NEW_VERSION]} From 367d197cc0db03f060d56351b659007a6aa08e92 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:30:35 -0400 Subject: [PATCH 198/484] Add 'get_for_user' method to the RecentDocument model --- apps/documents/managers.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/documents/managers.py b/apps/documents/managers.py index 8c07b5ec54..189535a67d 100644 --- a/apps/documents/managers.py +++ b/apps/documents/managers.py @@ -4,6 +4,7 @@ from ast import literal_eval from datetime import datetime from django.db import models +from django.contrib.auth.models import AnonymousUser from .conf.settings import RECENT_COUNT @@ -16,6 +17,12 @@ class RecentDocumentManager(models.Manager): to_delete = self.model.objects.filter(user=user)[RECENT_COUNT:] for recent_to_delete in to_delete: recent_to_delete.delete() + + def get_for_user(self, user): + if not user.is_anonymous(): + return [recent_document.document for recent_document in self.model.objects.filter(user=user)] + else: + return [] class DocumentPageTransformationManager(models.Manager): From 4931d9bf4968e8e6cec49c29931a9598da21a1ce Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:30:58 -0400 Subject: [PATCH 199/484] Update recent document list view to user the 'get_for_user' RecentDocument manager method --- apps/documents/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index a5deae4f53..2ccecd62bf 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -827,7 +827,7 @@ def document_page_navigation_last(request, document_page_id): def document_list_recent(request): return document_list( request, - object_list=[recent_document.document for recent_document in RecentDocument.objects.filter(user=request.user)], + object_list=RecentDocument.objects.get_for_user(request.user), title=_(u'recent documents'), extra_context={ 'recent_count': RECENT_COUNT From c7ee18af8571a399b5327763058b43348e16be45 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:33:09 -0400 Subject: [PATCH 200/484] Add anonymous user support to the 'get_object_name' function --- apps/common/utils.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/common/utils.py b/apps/common/utils.py index da13756918..dd916980d6 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -1,4 +1,4 @@ - # -*- coding: utf-8 -*- + # -*- coding: utf-8 -*- import os import re import types @@ -13,6 +13,7 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User +from django.contrib.auth.models import AnonymousUser def urlquote(link=None, get=None): @@ -333,9 +334,15 @@ def get_object_name(obj, display_object_type=True): label = unicode(obj) if isinstance(obj, User): label = obj.get_full_name() if obj.get_full_name() else obj + elif isinstance(obj, AnonymousUser): + label = _(u'Anonymous user') if display_object_type: - verbose_name = unicode(getattr(obj._meta, u'verbose_name', ct_label)) + try: + verbose_name = unicode(obj._meta.verbose_name) + except AttributeError: + verbose_name = ct_label + return u'%s: %s' % (verbose_name, label) else: return u'%s' % (label) From 85875be8592f68e3e682e8ae4c4fa6fe43e285d6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:33:31 -0400 Subject: [PATCH 201/484] Add further auto admin creation cleanups --- apps/common/__init__.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index b0557cce5c..9dcd406a4f 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -33,19 +33,19 @@ register_links(['about_view', 'changelog_view', 'license_view'], [about_view, ch register_top_menu('about', link={'text': _(u'about'), 'view': 'about_view', 'famfam': 'information'}, position=-1) -#if common_settings.AUTO_CREATE_ADMIN: -# # From https://github.com/lambdalisue/django-qwert/blob/master/qwert/autoscript/__init__.py -# # From http://stackoverflow.com/questions/1466827/ -- -# # -# # Prevent interactive question about wanting a superuser created. (This code -# # has to go in this otherwise empty "models" module so that it gets processed by -# # the "syncdb" command during database creation.) -# # -# # Create our own admin super user automatically. - @receiver(post_syncdb, dispatch_uid='create_superuser', sender=auth_models) -#def create_superuser(app, created_models, verbosity, **kwargs): def create_superuser(sender, **kwargs): + """ + From https://github.com/lambdalisue/django-qwert/blob/master/qwert/autoscript/__init__.py + From http://stackoverflow.com/questions/1466827/ -- + + Prevent interactive question about wanting a superuser created. (This code + has to go in this otherwise empty "models" module so that it gets processed by + the "syncdb" command during database creation.) + + Create our own admin super user automatically. + """ + if common_settings.AUTO_CREATE_ADMIN: USERNAME = common_settings.AUTO_ADMIN_USERNAME PASSWORD = common_settings.AUTO_ADMIN_PASSWORD @@ -58,12 +58,6 @@ def create_superuser(sender, **kwargs): assert auth_models.User.objects.create_superuser(USERNAME, 'x@x.com', PASSWORD) else: print 'Super admin user already exists. -- login: %s, password: %s' % (USERNAME, PASSWORD) -#signals.post_syncdb.disconnect( -# create_superuser, -# sender=auth_models, -# dispatch_uid='django.contrib.auth.management.create_superuser') -#signals.post_syncdb.connect(create_testuser, -# sender=auth_models, dispatch_uid='common.models.create_testuser') if (validate_path(common_settings.TEMPORARY_DIRECTORY) == False) or (not common_settings.TEMPORARY_DIRECTORY): setattr(common_settings, 'TEMPORARY_DIRECTORY', tempfile.mkdtemp()) From cbc94e484f02c1844d7935d76de38c848338c1a7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:36:07 -0400 Subject: [PATCH 202/484] Add anonymous user support to the Permission manager models --- apps/permissions/managers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/permissions/managers.py b/apps/permissions/managers.py index a6d5cc4722..38a94ceee4 100644 --- a/apps/permissions/managers.py +++ b/apps/permissions/managers.py @@ -8,11 +8,16 @@ 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)] From 0c02ac7d40bdedd87c5082345388875906a03769 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 7 Jan 2012 23:36:41 -0400 Subject: [PATCH 203/484] Add anonymous user support to the dynamic search app's Savedsearch model manager method --- apps/dynamic_search/managers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/dynamic_search/managers.py b/apps/dynamic_search/managers.py index 5df299ac2c..e825bc7350 100644 --- a/apps/dynamic_search/managers.py +++ b/apps/dynamic_search/managers.py @@ -2,7 +2,8 @@ import urlparse from django.db import models from django.utils.http import urlencode - +from django.contrib.auth.models import AnonymousUser + from dynamic_search.conf.settings import RECENT_COUNT @@ -21,7 +22,7 @@ class RecentSearchManager(models.Manager): # Cleanup query string and only store the q parameter parsed_query = {'q': parsed_query['q']} - if parsed_query: + if parsed_query and not isinstance(user, AnonymousUser): # If the URL query has at least one variable with a value new_recent, created = self.model.objects.get_or_create(user=user, query=urlencode(parsed_query), defaults={'hits': hits}) new_recent.hits = hits From be1658505c4d8c829f2338f278739a94926dee89 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:40:02 -0400 Subject: [PATCH 204/484] Use a context variable (web_theme_view_type) to determine the web theme view mode instead of using the user login status --- apps/web_theme/templates/web_theme_base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web_theme/templates/web_theme_base.html b/apps/web_theme/templates/web_theme_base.html index 56aa5294cb..d60b8368df 100644 --- a/apps/web_theme/templates/web_theme_base.html +++ b/apps/web_theme/templates/web_theme_base.html @@ -69,7 +69,7 @@
    - {% if user.is_anonymous %} + {% if web_theme_view_type == 'plain' %}
    {% block content_plain %}{% endblock %}
    From 9d73c10b7b6ac83d9f779e6b9fc7b9cc7323a2ee Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:41:07 -0400 Subject: [PATCH 205/484] Invert authentication test logic from is_anonymous to not is_authenticated From: http://gdub.wordpress.com/2006/09/23/is_authenticated-vs-is_anonymous/ --- apps/web_theme/templates/web_theme_login.html | 83 ++++++++++--------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/apps/web_theme/templates/web_theme_login.html b/apps/web_theme/templates/web_theme_login.html index ca98f0c7e9..302e371226 100644 --- a/apps/web_theme/templates/web_theme_login.html +++ b/apps/web_theme/templates/web_theme_login.html @@ -3,51 +3,52 @@ {% load theme_tags %} {% block web_theme_head %} - {% if not user.is_anonymous %} + {% if user.is_authenticated %} {% get_login_redirect_url %} {% endif %} {% endblock %} {% block html_title %}{% trans "Login" %}{% endblock %} -{% if not user.is_anonymous %} - {% block web_theme_content %} - {% get_login_redirect_url %} -
    -

    {% trans "You are already logged in" %}

    -
    -

    - {% trans "Redirecting you to the website entry point in 5 seconds." %} -

    -

    - {% blocktrans %}Or click here if redirection doesn't work.{% endblocktrans %} -

    -
    -
    - {% endblock %} -{% else %} - {% block content_plain %} -
    -

    {% block project_name %}{% endblock %}

    -
    -

    {% trans "Login" %}

    - - {% get_web_theme_setting "VERBOSE_LOGIN" as verbose_login %} - {% if verbose_login %} - {% include "verbose_login.html" %} - {% endif %} - {% endblock %} -{% endif %} + {% endblock %} + {% else %} + {% block content_plain %} +
    +

    {% block project_name %}{% endblock %}

    +
    +

    {% trans "Login" %}

    + +
    + {% get_web_theme_setting "VERBOSE_LOGIN" as verbose_login %} + {% if verbose_login %} + {% include "verbose_login.html" %} + {% endif %} + {% endblock %} + {% endif %} From 467be05baaec7c4c731e0d7ac3b91f578b7928ef Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:42:01 -0400 Subject: [PATCH 206/484] Select the proper web theme display mode based on the user authentication status --- apps/common/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/common/views.py b/apps/common/views.py index c88a204362..c7969ad5c3 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -193,8 +193,13 @@ def login_view(request): if LOGIN_METHOD == 'email': kwargs['authentication_form'] = EmailAuthenticationForm + + if not request.user.is_authenticated(): + context = {'web_theme_view_type': 'plain'} + else: + context = {} - return login(request, **kwargs) + return login(request, extra_context=context, **kwargs) def changelog_view(request): From c2fcbfe2991b777987a5e546812f3fbbb9f49d6a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:54:15 -0400 Subject: [PATCH 207/484] Add COMMON_ALLOW_ANONYMOUS_ACCESS configuration option to allow access to non authenticated users --- apps/common/conf/settings.py | 9 ++++++ .../middleware/login_required_middleware.py | 25 +++++++++------ docs/changelog.rst | 2 ++ docs/settings.rst | 32 ++++++++++++++++--- 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/apps/common/conf/settings.py b/apps/common/conf/settings.py index 14640aeb2e..3372111a51 100644 --- a/apps/common/conf/settings.py +++ b/apps/common/conf/settings.py @@ -64,3 +64,12 @@ register_setting( default=u'username', description=_(u'Controls the mechanism used to authenticated user. Options are: username, email'), ) + +register_setting( + namespace=u'common', + module=u'common.conf.settings', + name=u'ALLOW_ANONYMOUS_ACCESS', + global_name=u'COMMON_ALLOW_ANONYMOUS_ACCESS', + default=False, + description=_(u'Allows non authenticated users access to all views'), +) diff --git a/apps/common/middleware/login_required_middleware.py b/apps/common/middleware/login_required_middleware.py index 91af7dc92f..94331d32aa 100644 --- a/apps/common/middleware/login_required_middleware.py +++ b/apps/common/middleware/login_required_middleware.py @@ -1,8 +1,12 @@ +from __future__ import absolute_import + import re from django.http import HttpResponseRedirect from django.conf import settings +from ..conf.settings import ALLOW_ANONYMOUS_ACCESS + EXEMPT_URLS = [re.compile(settings.LOGIN_URL.lstrip('/'))] if hasattr(settings, 'LOGIN_EXEMPT_URLS'): EXEMPT_URLS += [re.compile(expr) for expr in settings.LOGIN_EXEMPT_URLS] @@ -20,13 +24,14 @@ class LoginRequiredMiddleware: """ def process_request(self, request): - assert hasattr(request, 'user'), "The Login Required middleware\ - requires authentication middleware to be installed. Edit your\ - MIDDLEWARE_CLASSES setting to insert\ - 'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\ - work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\ - 'django.core.context_processors.auth'." - if not request.user.is_authenticated(): - path = request.path_info.lstrip('/') - if not any(m.match(path) for m in EXEMPT_URLS): - return HttpResponseRedirect(settings.LOGIN_URL) + if not ALLOW_ANONYMOUS_ACCESS: + assert hasattr(request, 'user'), "The Login Required middleware\ + requires authentication middleware to be installed. Edit your\ + MIDDLEWARE_CLASSES setting to insert\ + 'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\ + work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\ + 'django.core.context_processors.auth'." + if not request.user.is_authenticated(): + path = request.path_info.lstrip('/') + if not any(m.match(path) for m in EXEMPT_URLS): + return HttpResponseRedirect(settings.LOGIN_URL) diff --git a/docs/changelog.rst b/docs/changelog.rst index d06b77d2d2..89feffda1a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,7 @@ Version 0.12 ------------ +* Added new configuration option COMMON_ALLOW_ANONYMOUS_ACCESS to allow + non authenticated access. * Statistics fixes * Italian translation by SeeOpen.IT (www.seeopen.it, info@seeopen.it) * Removed the 'db_index' argument from Text fields definition and diff --git a/docs/settings.rst b/docs/settings.rst index 323bf84405..8d9b0237be 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -188,7 +188,7 @@ Job processor Default: ``None`` - Specified which job processing library to use, option are: None and celery. + Specifies which job processing library to use, option are: None and celery. Document indexing @@ -230,12 +230,17 @@ OCR .. data:: OCR_TESSERACT_PATH Default: ``/bin/tesseract`` + + File path to the ``tesseract`` executable, used to perform OCR on document + page's images. .. data:: OCR_TESSERACT_LANGUAGE Default: ``eng`` - + + Language code passed to the ``tesseract`` executable. + .. data:: OCR_REPLICATION_DELAY @@ -256,7 +261,8 @@ OCR Default: ``False`` - Automatically queue newly created documents for OCR. + Automatically queue newly created documents or newly uploaded versions + of existing documents for OCR. .. data:: OCR_QUEUE_PROCESSING_INTERVAL @@ -277,7 +283,8 @@ OCR Default: ``/usr/bin/unpaper`` - File path to unpaper program. + File path to the ``unpaper`` executable, used to clean up images before + doing OCR. Metadata @@ -318,24 +325,39 @@ Common .. data:: 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 .. data:: COMMON_AUTO_ADMIN_USERNAME Default: ``admin`` + Username of the automatically created superuser + .. data:: COMMON_AUTO_ADMIN_PASSWORD Default: ``admin`` - + + Default password of the automatically created superuser + .. data:: COMMON_LOGIN_METHOD Default: ``username`` Controls the mechanism used to authenticated user. Options are: ``username``, ``email`` + + +.. data:: COMMON_ALLOW_ANONYMOUS_ACCESS + + Default: ``False`` + Allow non authenticated users, access to all views + Search ------ From ad5dfdd148981c4b6bba872269365ca82c8a1804 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:55:13 -0400 Subject: [PATCH 208/484] Removed remarked lines --- settings.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/settings.py b/settings.py index 9a64a7ce74..1944232ed5 100644 --- a/settings.py +++ b/settings.py @@ -149,12 +149,12 @@ INSTALLED_APPS = ( 'sentry.client.celery', 'storage', 'folders', - 'taggit', - 'tags', 'document_comments', 'user_management', 'metadata', 'documents', + 'taggit', + 'tags', 'linking', 'mptt', 'document_indexing', @@ -176,10 +176,8 @@ INSTALLED_APPS = ( 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 = ( From f2a263adb710253a650ea55a92c721f7c215ea94 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:55:54 -0400 Subject: [PATCH 209/484] Move tag model column registration to the tags app --- apps/documents/__init__.py | 4 ---- apps/tags/__init__.py | 11 +++++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index aa8ec09269..45fd4c5ad7 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -9,7 +9,6 @@ from navigation.api import (register_links, register_top_menu, register_model_list_columns, register_multi_item_links, register_sidebar_template) from main.api import register_diagnostic, register_maintenance_links -from tags.widgets import get_tags_inline_widget_simple from history.api import register_history_type from history.permissions import PERMISSION_HISTORY_VIEW from metadata.api import get_metadata_string @@ -168,9 +167,6 @@ register_model_list_columns(Document, [ {'name':_(u'thumbnail'), 'attribute': encapsulate(lambda x: document_thumbnail(x)) }, - {'name':_(u'tags'), 'attribute': - encapsulate(lambda x: get_tags_inline_widget_simple(x)) - }, {'name':_(u'metadata'), 'attribute': encapsulate(lambda x: get_metadata_string(x)) }, diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 357b4b878c..8cfeacf58b 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -12,14 +12,15 @@ from acls.permissions import ACLS_VIEW_ACL from taggit.models import Tag from taggit.managers import TaggableManager +from .widgets import get_tags_inline_widget_simple from .widgets import tag_color_block 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', 'permission': [PERMISSION_TAG_CREATE]} -tag_attach = {'text': _(u'attach tag'), 'view': 'tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permission': [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, PERMISSION_TAG_ATTACH], 'children_view_regex': ['tag']} @@ -45,6 +46,12 @@ register_model_list_columns(Tag, [ } ]) +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, 'tag_list', 'tag_create'], [tag_list, tag_create], menu_name='secondary_menu') From 7fd83ddf0b286ecc0b8881701b3695188d8808dd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:57:02 -0400 Subject: [PATCH 210/484] Fix import format --- apps/permissions/templatetags/permission_tags.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/permissions/templatetags/permission_tags.py b/apps/permissions/templatetags/permission_tags.py index 18e161bdd7..0d0974145b 100644 --- a/apps/permissions/templatetags/permission_tags.py +++ b/apps/permissions/templatetags/permission_tags.py @@ -1,6 +1,5 @@ from django.core.exceptions import PermissionDenied -from django.template import TemplateSyntaxError, Library, \ - Node, Variable +from django.template import TemplateSyntaxError, Library, Node, Variable from permissions.models import Permission From c3175c7ea40cdbc7778d2b7b2a67884a152fc53e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:57:54 -0400 Subject: [PATCH 211/484] Add anonymous user support to the permission app --- apps/permissions/managers.py | 1 - apps/permissions/models.py | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/permissions/managers.py b/apps/permissions/managers.py index 38a94ceee4..2284f55e01 100644 --- a/apps/permissions/managers.py +++ b/apps/permissions/managers.py @@ -17,7 +17,6 @@ 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)] diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 744703f1c3..2ec16fe68f 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -10,6 +10,8 @@ from django.contrib.contenttypes import generic from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied +from common.models import AnonymousUserSingleton + from .managers import (RoleMemberManager, StoredPermissionManager) logger = logging.getLogger(__name__) @@ -44,6 +46,8 @@ class PermissionManager(object): if permission.requester_has_this(requester): return True + logger.debug('no permission') + raise PermissionDenied(ugettext(u'Insufficient permissions.')) @classmethod @@ -105,8 +109,7 @@ class Permission(object): return stored_permission def requester_has_this(self, requester): - stored_permission = self.get_stored_permission( - ) + stored_permission = self.get_stored_permission() return stored_permission.requester_has_this(requester) def save(self, *args, **kwargs): @@ -139,6 +142,8 @@ class StoredPermission(models.Model): return [holder.holder_object for holder in self.permissionholder_set.all()] def requester_has_this(self, requester): + requester = AnonymousUserSingleton.objects.passthru_check(requester) + logger.debug('requester: %s' % requester) if isinstance(requester, User): if requester.is_superuser or requester.is_staff: return True @@ -159,12 +164,17 @@ class StoredPermission(models.Model): for membership in list(set(roles) | set(groups)): if self.requester_has_this(membership): return True + + logger.debug('Fallthru') + return False def grant_to(self, requester): + requester = AnonymousUserSingleton.objects.passthru_check(requester) permission_holder, created = PermissionHolder.objects.get_or_create(permission=self, holder_type=ContentType.objects.get_for_model(requester), holder_id=requester.pk) return created def revoke_from(self, holder): + requester = AnonymousUserSingleton.objects.passthru_check(requester) try: permission_holder = PermissionHolder.objects.get(permission=self, holder_type=ContentType.objects.get_for_model(holder), holder_id=holder.pk) permission_holder.delete() @@ -199,6 +209,7 @@ class Role(models.Model): verbose_name_plural = _(u'roles') 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), From 45031022b6dcd637e4c5d46b966e39b1043d333d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:58:22 -0400 Subject: [PATCH 212/484] Update COMMON_ALLOW_ANONYMOUS_ACCESS description wording --- apps/common/conf/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/conf/settings.py b/apps/common/conf/settings.py index 3372111a51..e1ec67ada3 100644 --- a/apps/common/conf/settings.py +++ b/apps/common/conf/settings.py @@ -71,5 +71,5 @@ register_setting( name=u'ALLOW_ANONYMOUS_ACCESS', global_name=u'COMMON_ALLOW_ANONYMOUS_ACCESS', default=False, - description=_(u'Allows non authenticated users access to all views'), + description=_(u'Allow non authenticated users, access to all views'), ) From 3ef44b3d324c556f55d8511a6bebb53e5b3cf79c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:58:42 -0400 Subject: [PATCH 213/484] Update logout action to not redirect on logout --- apps/main/templates/base.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index c1fcedd0cb..ab7c60ca26 100644 --- a/apps/main/templates/base.html +++ b/apps/main/templates/base.html @@ -181,7 +181,7 @@ {% block web_theme_user_navigation %}
  • {% trans "User" %}: - {% if user.is_anonymous %} + {% if not user.is_authenticated %} {% trans "Anonymous" %} {% else %} {{ user.get_full_name|default:user }} @@ -202,7 +202,7 @@
  • {% endif %} {% get_setting "LOGIN_URL" as login_url %} -
  • {% if user.is_anonymous %}{% trans "Login" %}{% else %}{% trans "Logout" %}{% endif %}
  • +
  • {% if not user.is_authenticated %}{% trans "Login" %}{% else %}{% trans "Logout" %}{% endif %}
  • {% endblock %} {% block web_theme_main_navigation %} From 51a6abaf117081ed52aad19203d1c1159bc241b6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 04:59:16 -0400 Subject: [PATCH 214/484] Add context variable setting helper template tag --- apps/common/templatetags/set_var.py | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 apps/common/templatetags/set_var.py diff --git a/apps/common/templatetags/set_var.py b/apps/common/templatetags/set_var.py new file mode 100644 index 0000000000..c818a7188c --- /dev/null +++ b/apps/common/templatetags/set_var.py @@ -0,0 +1,30 @@ +from django import template + +register = template.Library() + +class SetVarNode(template.Node): + def __init__(self, var_name, var_value): + self.var_name = var_name + self.var_value = var_value + + def render(self, context): + try: + value = template.Variable(self.var_value).resolve(context) + except template.VariableDoesNotExist: + value = "" + #context[self.var_name] = value + # Make it global across all blocks + context.dicts[0][self.var_name] = value + + return u"" + +def set_var(parser, token): + """ + {% set = %} + """ + parts = token.split_contents() + if len(parts) < 4: + raise template.TemplateSyntaxError("'set' tag must be of the form: {% set = %}") + return SetVarNode(parts[1], parts[3]) + +register.tag('set', set_var) From 4db37003d97487af36e1e246dd2644b912e0b4fb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 06:48:01 -0400 Subject: [PATCH 215/484] Call the proper method when adding anonymous user singleton to the new holder list --- apps/acls/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 13777cf98e..7f651f7f1b 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -40,7 +40,7 @@ class HolderSelectionForm(forms.Form): if roles: non_holder_list.append((_(u'Roles'), _as_choice_list(list(roles)))) - non_holder_list.append((_(u'Special'), _as_choice_list([AnonymousUserSingleton.get()]))) + non_holder_list.append((_(u'Special'), _as_choice_list([AnonymousUserSingleton.objects.get()]))) super(HolderSelectionForm, self).__init__(*args, **kwargs) self.fields['holder_gid'].choices = non_holder_list From fac43006e3be44806425f9efa6c5b06f57df92a0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 06:48:45 -0400 Subject: [PATCH 216/484] Add translable return text to the anonymous user singleton __unicode__ method --- apps/common/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/common/models.py b/apps/common/models.py index 1e174119bb..cb9a98d91c 100644 --- a/apps/common/models.py +++ b/apps/common/models.py @@ -1,5 +1,6 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext from django.contrib.auth.models import AnonymousUser SINGLETON_LOCK_ID = 1 @@ -37,6 +38,9 @@ class AnonymousUserSingletonManager(SingletonManager): class AnonymousUserSingleton(Singleton): objects = AnonymousUserSingletonManager() + + def __unicode__(self): + return ugettext('Anonymous user') class Meta: verbose_name = _(u'anonymous user') From 14dbeb42666b2cc4a67b8a6730ffbfc8a80ef3db Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 06:49:26 -0400 Subject: [PATCH 217/484] Remove AnonymousUser class checking --- apps/common/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/common/utils.py b/apps/common/utils.py index dd916980d6..e472a00d3b 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import + import os import re import types @@ -13,7 +15,6 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User -from django.contrib.auth.models import AnonymousUser def urlquote(link=None, get=None): @@ -331,11 +332,10 @@ def generate_choices_w_labels(choices, display_object_type=True): def get_object_name(obj, display_object_type=True): ct_label = ContentType.objects.get_for_model(obj).name - label = unicode(obj) if isinstance(obj, User): label = obj.get_full_name() if obj.get_full_name() else obj - elif isinstance(obj, AnonymousUser): - label = _(u'Anonymous user') + else: + label = unicode(obj) if display_object_type: try: From 9e43b1bd7d9696af4d6da92bb072a7598b245aea Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 06:49:50 -0400 Subject: [PATCH 218/484] Remove FOLDER VIEW permission from the folder list view link This view is filtered by ACL --- apps/folders/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 0a89298148..df51dbc4c0 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -15,7 +15,7 @@ from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) -folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user', 'permissions': [PERMISSION_FOLDER_VIEW]} +folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user'} folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_CREATE]} folder_edit = {'text': _('edit'), 'view': 'folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit', 'permissions': [PERMISSION_FOLDER_EDIT]} folder_delete = {'text': _('delete'), 'view': 'folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_DELETE]} From 191386038c9165c862c902e0b075be4938ef0986 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 06:50:35 -0400 Subject: [PATCH 219/484] Don't update recent documents for anonymous users --- apps/documents/managers.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/documents/managers.py b/apps/documents/managers.py index 189535a67d..b564d44885 100644 --- a/apps/documents/managers.py +++ b/apps/documents/managers.py @@ -11,15 +11,16 @@ from .conf.settings import RECENT_COUNT class RecentDocumentManager(models.Manager): def add_document_for_user(self, user, document): - self.model.objects.filter(user=user, document=document).delete() - new_recent = self.model(user=user, document=document, datetime_accessed=datetime.now()) - new_recent.save() - to_delete = self.model.objects.filter(user=user)[RECENT_COUNT:] - for recent_to_delete in to_delete: - recent_to_delete.delete() + if user.is_authenticated(): + self.model.objects.filter(user=user, document=document).delete() + new_recent = self.model(user=user, document=document, datetime_accessed=datetime.now()) + new_recent.save() + to_delete = self.model.objects.filter(user=user)[RECENT_COUNT:] + for recent_to_delete in to_delete: + recent_to_delete.delete() def get_for_user(self, user): - if not user.is_anonymous(): + if user.is_authenticated(): return [recent_document.document for recent_document in self.model.objects.filter(user=user)] else: return [] From 7ea9033c02ff4f49fe6c898d50fa78edd5e9d376 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 06:51:32 -0400 Subject: [PATCH 220/484] Change the default return value of the acl tag to False if there is no navigation object available * This fixes the creation views links for the anonymous users --- apps/acls/templatetags/acl_tags.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/acls/templatetags/acl_tags.py b/apps/acls/templatetags/acl_tags.py index f76b29e424..20e96dbb2f 100644 --- a/apps/acls/templatetags/acl_tags.py +++ b/apps/acls/templatetags/acl_tags.py @@ -30,8 +30,8 @@ class CheckAccessNode(Node): obj = Variable(self.obj).resolve(context) logger.debug('obj: %s' % obj) except VariableDoesNotExist: - context[u'access'] = True - logger.debug('no obj, access True') + context[u'access'] = False + logger.debug('no obj, access False') return u'' if not permission_list: From abd408812fd9086cf862125fd8fcbfff404ac69d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 07:35:40 -0400 Subject: [PATCH 221/484] Restrict statistics access to superusers and staff only --- apps/main/__init__.py | 2 +- apps/main/views.py | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 842c5d11ab..8a502f30f9 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -31,7 +31,7 @@ def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser maintenance_menu = {'text': _(u'maintenance'), 'view': 'maintenance_menu', 'famfam': 'wrench', 'icon': 'wrench.png'} -statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png'} +statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png', 'condition': is_superuser} diagnostics = {'text': _(u'diagnostics'), 'view': 'diagnostics', 'famfam': 'pill', 'icon': 'pill.png'} sentry = {'text': _(u'sentry'), 'view': 'sentry', 'famfam': 'bug', 'icon': 'bug.png', 'condition': is_superuser} admin_site = {'text': _(u'admin site'), 'view': 'admin:index', 'famfam': 'keyboard', 'icon': 'keyboard.png', 'condition': is_superuser} diff --git a/apps/main/views.py b/apps/main/views.py index 316b4b6e6d..12aabda9e5 100644 --- a/apps/main/views.py +++ b/apps/main/views.py @@ -46,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): From 1039b808318f4848f7a40cce1da5104e851eb486 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 8 Jan 2012 07:36:07 -0400 Subject: [PATCH 222/484] Remove commented code --- .../generic_list_horizontal_subtemplate.html | 88 ------------------- 1 file changed, 88 deletions(-) diff --git a/apps/common/templates/generic_list_horizontal_subtemplate.html b/apps/common/templates/generic_list_horizontal_subtemplate.html index 5edd4f47fe..8b62536db7 100644 --- a/apps/common/templates/generic_list_horizontal_subtemplate.html +++ b/apps/common/templates/generic_list_horizontal_subtemplate.html @@ -59,95 +59,7 @@
    {% endif %} -{% comment %} - - - {% if not hide_header %} - - {% if multi_select or multi_select_as_buttons %} - - {% endif %} - {% if not hide_object %} - - {% endif %} - - {% for column in extra_columns_preffixed %} - - {% endfor %} - - {% for column in object_list.0|get_model_list_columns %} - - {% endfor %} - - {% for column in extra_columns %} - - {% endfor %} - - {% if not hide_links %} - - {% endif %} - - {% endif %} - {% for object in object_list %} - - {% if multi_select or multi_select_as_buttons %} - - {% endif %} - {% if not hide_object %} - {% if main_object %} - {% with object|object_property:main_object as object %} - - {% endwith %} - {% else %} - - {% endif %} - {% endif %} - {% for column in extra_columns_preffixed %} - {% if column.keep_together %} - - {% else %} - - {% endif %} - {% endfor %} - {% if not hide_columns %} - {% for column in object|get_model_list_columns %} - - {% endfor %} - {% endif %} - {% for column in extra_columns %} - {% if column.keep_together %} - - {% else %} - - {% endif %} - {% endfor %} - {% if not hide_links %} - {% if list_object_variable_name %} - {% copy_variable object as list_object_variable_name %} - {% copy_variable list_object_variable_name as "navigation_object_name" %} - {% endif %} - - {% endif %} - - {% empty %} - - {% endfor %} - -
    {% trans "Identifier" %}{{ column.name|capfirst }}{{ column.name|capfirst }}{{ column.name|capfirst }} 
    {% if not hide_link %}{{ object }}{% else %}{{ object }}{% endif %}{% if not hide_link %}{{ object }}{% else %}{{ object }}{% endif %} - {{ object|object_property:column.attribute|make_non_breakable }} - {{ object|object_property:column.attribute }}{{ object|object_property:column.attribute }} - {{ object|object_property:column.attribute|make_non_breakable }} - {{ object|object_property:column.attribute }} - {% if navigation_object_links %} - {% with navigation_object_links as overrided_object_links %} - {% object_navigation_template %} - {% endwith %} - {% else %} - {% object_navigation_template %} - {% endif %} -
    {% blocktrans with title|striptags as stripped_title %}There are no {{ stripped_title }}{% endblocktrans %}
    -{% endcomment %} {% endif %} + {% get_object_navigation_links "sidebar" as object_navigation_links %} + {% if object_navigation_links %} +
    +

    {% trans "Other available actions" %}

    + +
    + {% endif %} {% endfor %} {% else %} {% get_object_navigation_links as object_navigation_links %} From 351784a2104fc98248422eb92e678f14abe52860 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 06:41:58 -0400 Subject: [PATCH 241/484] Add generic 'new holder' link --- apps/acls/__init__.py | 6 +++++- apps/acls/urls.py | 1 + apps/acls/views.py | 47 ++++++++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index c6dd477306..64becbdef5 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -5,7 +5,8 @@ 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 .classes import AccessHolder, AccessObjectClass, ClassAccessHolder +from .classes import (AccessHolder, AccessObjectClass, ClassAccessHolder, + AccessObject) from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) @@ -14,6 +15,7 @@ acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissio acl_detail = {'text': _(u'details'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'key_go', 'permissions': [ACLS_VIEW_ACL]} acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} +acl_holder_new = {'text': _(u'New holder'), 'view': 'acl_holder_new', 'args': 'access_object.gid', 'famfam': 'user', 'permissions': [ACLS_EDIT_ACL]} acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png', 'permissions': [ACLS_CLASS_VIEW_ACL]} acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package', 'permissions': [ACLS_CLASS_VIEW_ACL]} @@ -26,6 +28,8 @@ acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', ' register_links(AccessHolder, [acl_detail]) register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) +register_links([AccessObject], [acl_holder_new], menu_name='sidebar') + register_setup(acl_setup_valid_classes) register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acl_class_acl_detail'], [acl_class_list], menu_name='secondary_menu') diff --git a/apps/acls/urls.py b/apps/acls/urls.py index ff1e9dd4b3..a544274b5b 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -4,6 +4,7 @@ urlpatterns = patterns('acls.views', url(r'^new_holder_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_new_holder_for', (), 'acl_new_holder_for'), url(r'^list_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_list', (), 'acl_list'), url(r'^details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acl_detail', (), 'acl_detail'), + url(r'^holder/new/(?P[.\w]+)/$', 'acl_holder_new', (), 'acl_holder_new'), url(r'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), url(r'^multiple/revoke/$', 'acl_revoke', (), 'acl_multiple_revoke'), diff --git a/apps/acls/views.py b/apps/acls/views.py index 375ab37b6e..d0a71b79a7 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -55,7 +55,12 @@ def acl_list_for(request, obj, extra_context=None): {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, ], 'hide_object': True, - 'access_object': AccessObject.encapsulate(obj) + 'access_object': AccessObject.encapsulate(obj), + 'object': obj, + 'navigation_object_list': [ + {'object': 'object'}, + {'object': 'access_object'} + ], } if extra_context: @@ -78,12 +83,10 @@ def acl_detail(request, access_object_gid, holder_object_gid): except ObjectDoesNotExist: raise Http404 - navigation_object = request.GET.get('navigation_object') - logger.debug('navigation_object: %s' % navigation_object) - return acl_detail_for(request, holder.source_object, access_object.source_object, navigation_object) + return acl_detail_for(request, holder.source_object, access_object.source_object) -def acl_detail_for(request, actor, obj, navigation_object=None): +def acl_detail_for(request, actor, obj): try: Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) except PermissionDenied: @@ -123,15 +126,13 @@ def acl_detail_for(request, actor, obj, navigation_object=None): 'permission_pk': lambda x: x.pk, 'holder_gid': lambda x: AccessHolder(actor).gid, 'object_gid': lambda x: AccessObject(obj).gid, - } + }, + 'access_object': AccessObject.encapsulate(obj), + 'navigation_object_list': [ + {'object': 'object'}, + {'object': 'access_object'} + ], } - - if navigation_object: - context.update( - { - navigation_object: obj - } - ) return render_to_response( 'generic_detail.html', @@ -359,13 +360,28 @@ def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None) 'title': _(u'add new holder for: %s') % obj, 'submit_label': _(u'Select'), 'submit_icon_famfam': 'tick', + 'object': obj, + 'access_object': AccessObject.encapsulate(obj), + 'navigation_object_list': [ + {'object': 'object'}, + {'object': 'access_object'}, + ], } - + if extra_context: context.update(extra_context) return render_to_response('generic_form.html', context, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) + + +def acl_holder_new(request, access_object_gid): + try: + access_object = AccessObject.get(gid=access_object_gid) + except ObjectDoesNotExist: + raise Http404 + + return acl_new_holder_for(request, access_object.source_object)#, extra_context={'access_object': access_object}) # Setup views @@ -435,7 +451,6 @@ def acl_class_acl_detail(request, access_object_class_gid, holder_object_gid): 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_access(x, actor.source_object, access_object_class.source_object))) }, ], - #'hide_link': True, 'hide_object': True, } }, From c330c422b728836622c2f340c7ce7c9c22fbab55 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 06:42:35 -0400 Subject: [PATCH 242/484] Remove app specific ACL new holder links, urls and views --- apps/document_acls/__init__.py | 3 --- apps/document_acls/urls.py | 1 - apps/document_acls/views.py | 13 +----------- apps/folders/__init__.py | 3 --- apps/folders/urls.py | 1 - apps/folders/views.py | 16 +-------------- apps/linking/__init__.py | 13 +++++------- apps/linking/urls.py | 1 - apps/linking/views.py | 36 ++++++++++------------------------ apps/tags/__init__.py | 2 -- apps/tags/urls.py | 1 - apps/tags/views.py | 12 ------------ 12 files changed, 17 insertions(+), 85 deletions(-) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index ff6d1f32bb..a904759f4d 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -7,12 +7,9 @@ from acls import ACLS_VIEW_ACL, ACLS_EDIT_ACL from acls.api import class_permissions acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -document_new_holder = {'text': _(u'New holder'), 'view': 'document_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} register_links(Document, [acl_list], menu_name='form_header') -register_links(['document_acl_list', 'document_new_holder'], [document_new_holder], menu_name='sidebar') - class_permissions(Document, [ ACLS_VIEW_ACL, ACLS_EDIT_ACL diff --git a/apps/document_acls/urls.py b/apps/document_acls/urls.py index e86dc9d4fc..50a6e79aa6 100644 --- a/apps/document_acls/urls.py +++ b/apps/document_acls/urls.py @@ -2,5 +2,4 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('document_acls.views', url(r'^list_for/document/(?P\d+)/$', 'document_acl_list', (), 'document_acl_list'), - url(r'^new_holder_for/document/(?P\d+)/$', 'document_new_holder', (), 'document_new_holder'), ) diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 505770fa99..4b20a038ee 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -2,7 +2,7 @@ from django.shortcuts import render_to_response, get_object_or_404 from django.utils.translation import ugettext_lazy as _ from documents.models import Document -from acls.views import acl_list_for, acl_new_holder_for +from acls.views import acl_list_for from acls.models import AccessEntry @@ -15,14 +15,3 @@ def document_acl_list(request, document_id): 'object': document, } ) - - -def document_new_holder(request, document_id): - document = get_object_or_404(Document, pk=document_id) - return acl_new_holder_for( - request, - document, - extra_context={ - 'object': document, - } - ) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index df51dbc4c0..8bbc3126b2 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -25,14 +25,11 @@ folder_add_document = {'text': _('add to a folder'), 'view': 'folder_add_documen document_folder_list = {'text': _(u'folders'), 'view': 'document_folder_list', 'args': 'object.pk', 'famfam': 'folder_user', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'children_view_regex': [r'folder']} folder_acl_list = {'text': _(u'ACLs'), 'view': 'folder_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -folder_new_holder = {'text': _(u'New holder'), 'view': 'folder_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} register_multi_item_links(['folder_view'], [folder_document_multiple_remove]) register_links(Folder, [folder_view, folder_edit, folder_delete, folder_acl_list]) -register_links(['folder_acl_list', 'folder_new_holder'], [folder_new_holder], menu_name='sidebar') - register_links([Folder, 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='secondary_menu') register_top_menu(name='folders', link={'text': _('folders'), 'famfam': 'folder_user', 'view': 'folder_list'}, children_views=['folder_list', 'folder_create', 'folder_edit', 'folder_delete', 'folder_view', 'folder_document_multiple_remove']) diff --git a/apps/folders/urls.py b/apps/folders/urls.py index 46ad85b478..0e0cf0d5ad 100644 --- a/apps/folders/urls.py +++ b/apps/folders/urls.py @@ -13,5 +13,4 @@ urlpatterns = patterns('folders.views', url(r'^document/(?P\d+)/folder/list/$', 'document_folder_list', (), 'document_folder_list'), url(r'^(?P\d+)/acl/list/$', 'folder_acl_list', (), 'folder_acl_list'), - url(r'^(?P\d+)/acl/holder/new/$', 'folder_new_holder', (), 'folder_new_holder'), ) diff --git a/apps/folders/views.py b/apps/folders/views.py index d4eeadbaed..de1dcc4ca4 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -17,7 +17,7 @@ from documents.views import document_list from permissions import Permission from common.utils import encapsulate from acls.models import AccessEntry -from acls.views import acl_list_for, acl_new_holder_for +from acls.views import acl_list_for from .models import Folder, FolderDocument from .forms import FolderForm, FolderListForm @@ -291,17 +291,3 @@ def folder_acl_list(request, folder_pk): 'object': folder, } ) - - -def folder_new_holder(request, folder_pk): - folder = get_object_or_404(Folder, pk=folder_pk) - return acl_new_holder_for( - request, - folder, - extra_context={ - 'folder': folder, - 'submit_label': _(u'Select'), - 'submit_icon_famfam': 'tick', - 'object': folder, - } - ) diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index cb1c98cbff..0d827f3e48 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -20,18 +20,15 @@ smart_link_instances_for_document = {'text': _(u'smart links'), 'view': 'smart_l smart_link_setup = {'text': _(u'smart links'), 'view': 'smart_link_list', 'icon': 'link.png', 'permissions': [PERMISSION_SMART_LINK_CREATE]} smart_link_list = {'text': _(u'smart links list'), 'view': 'smart_link_list', 'famfam': 'link', 'permissions': [PERMISSION_SMART_LINK_CREATE]} smart_link_create = {'text': _(u'create new smart link'), 'view': 'smart_link_create', 'famfam': 'link_add', 'permissions': [PERMISSION_SMART_LINK_CREATE]} -smart_link_edit = {'text': _(u'edit'), 'view': 'smart_link_edit', 'args': 'smart_link.pk', 'famfam': 'link_edit', 'permissions': [PERMISSION_SMART_LINK_EDIT]} -smart_link_delete = {'text': _(u'delete'), 'view': 'smart_link_delete', 'args': 'smart_link.pk', 'famfam': 'link_delete', 'permissions': [PERMISSION_SMART_LINK_DELETE]} +smart_link_edit = {'text': _(u'edit'), 'view': 'smart_link_edit', 'args': 'object.pk', 'famfam': 'link_edit', 'permissions': [PERMISSION_SMART_LINK_EDIT]} +smart_link_delete = {'text': _(u'delete'), 'view': 'smart_link_delete', 'args': 'object.pk', 'famfam': 'link_delete', 'permissions': [PERMISSION_SMART_LINK_DELETE]} -smart_link_condition_list = {'text': _(u'conditions'), 'view': 'smart_link_condition_list', 'args': 'smart_link.pk', 'famfam': 'cog', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_CREATE]} -smart_link_condition_create = {'text': _(u'create condition'), 'view': 'smart_link_condition_create', 'args': 'smart_link.pk', 'famfam': 'cog_add', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} +smart_link_condition_list = {'text': _(u'conditions'), 'view': 'smart_link_condition_list', 'args': 'object.pk', 'famfam': 'cog', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_CREATE]} +smart_link_condition_create = {'text': _(u'create condition'), 'view': 'smart_link_condition_create', 'args': 'object.pk', 'famfam': 'cog_add', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} smart_link_condition_edit = {'text': _(u'edit'), 'view': 'smart_link_condition_edit', 'args': 'condition.pk', 'famfam': 'cog_edit', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} smart_link_condition_delete = {'text': _(u'delete'), 'view': 'smart_link_condition_delete', 'args': 'condition.pk', 'famfam': 'cog_delete', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} -smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'smart_link_acl_list', 'args': 'smart_link.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -smart_link_new_holder = {'text': _(u'New holder'), 'view': 'smart_link_new_holder', 'args': 'smart_link.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} - -register_links(['smart_link_acl_list', 'smart_link_new_holder'], [smart_link_new_holder], menu_name='sidebar') +smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'smart_link_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} register_links(Document, [smart_link_instances_for_document], menu_name='form_header') diff --git a/apps/linking/urls.py b/apps/linking/urls.py index e13bc00441..cf47c7ca7e 100644 --- a/apps/linking/urls.py +++ b/apps/linking/urls.py @@ -16,5 +16,4 @@ urlpatterns = patterns('linking.views', url(r'^setup/smart_link/condition/(?P\d+)/delete/$', 'smart_link_condition_delete', (), 'smart_link_condition_delete'), url(r'^(?P\d+)/acl/list/$', 'smart_link_acl_list', (), 'smart_link_acl_list'), - url(r'^(?P\d+)/acl/holder/new/$', 'smart_link_new_holder', (), 'smart_link_new_holder'), ) diff --git a/apps/linking/views.py b/apps/linking/views.py index 5f72d8f393..58a1c8451c 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -15,7 +15,7 @@ from documents.models import Document from documents.views import document_list from documents.permissions import PERMISSION_DOCUMENT_VIEW from permissions.models import Permission -from acls.views import acl_new_holder_for, acl_list_for, acl_detail_for +from acls.views import acl_list_for from acls.models import AccessEntry, PermissionDenied from .models import SmartLink, SmartLinkCondition @@ -176,8 +176,8 @@ def smart_link_edit(request, smart_link_pk): form = SmartLinkForm(instance=smart_link) return render_to_response('generic_form.html', { - 'navigation_object_name': 'smart_link', - 'smart_link': smart_link, + #'navigation_object_name': 'smart_link', + 'object': smart_link, 'form': form, 'title': _(u'Edit smart link: %s') % smart_link }, context_instance=RequestContext(request)) @@ -207,8 +207,7 @@ def smart_link_delete(request, smart_link_pk): return render_to_response('generic_confirm.html', { 'delete_view': True, - 'navigation_object_name': 'smart_link', - 'smart_link': smart_link, + 'object': smart_link, 'title': _(u'Are you sure you wish to delete smart link: %s?') % smart_link, 'next': next, 'previous': previous, @@ -231,8 +230,7 @@ def smart_link_condition_list(request, smart_link_pk): {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, ], 'hide_link': True, - 'smart_link': smart_link, - 'navigation_object_name': 'smart_link', + 'object': smart_link, 'list_object_variable_name': 'condition', }, context_instance=RequestContext(request)) @@ -259,8 +257,7 @@ def smart_link_condition_create(request, smart_link_pk): return render_to_response('generic_form.html', { 'form': form, 'title': _(u'Add new conditions to smart link: "%s"') % smart_link, - 'navigation_object_name': 'smart_link', - 'smart_link': smart_link, + 'object': smart_link, }, context_instance=RequestContext(request)) @@ -292,9 +289,9 @@ def smart_link_condition_edit(request, smart_link_condition_pk): 'next': next, 'previous': previous, 'condition': smart_link_condition, - 'smart_link': smart_link_condition.smart_link, + 'object': smart_link_condition.smart_link, 'navigation_object_list': [ - {'object': 'smart_link', 'name': _(u'smart link')}, + {'object': 'object', 'name': _(u'smart link')}, {'object': 'condition', 'name': _(u'condition')} ], @@ -326,9 +323,9 @@ def smart_link_condition_delete(request, smart_link_condition_pk): return render_to_response('generic_confirm.html', { 'delete_view': True, 'condition': smart_link_condition, - 'smart_link': smart_link_condition.smart_link, + 'object': smart_link_condition.smart_link, 'navigation_object_list': [ - {'object': 'smart_link', 'name': _(u'smart link')}, + {'object': 'object', 'name': _(u'smart link')}, {'object': 'condition', 'name': _(u'condition')} ], 'title': _(u'Are you sure you wish to delete smart link condition: "%s"?') % smart_link_condition, @@ -350,16 +347,3 @@ def smart_link_acl_list(request, smart_link_pk): 'smart_link': smart_link, } ) - - -def smart_link_new_holder(request, smart_link_pk): - smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) - return acl_new_holder_for( - request, - smart_link, - extra_context={ - 'smart_link': smart_link, - 'object': smart_link, - }, - navigation_object=u'smart_link', - ) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 79a04dbd03..a00f69bf45 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -29,7 +29,6 @@ tag_edit = {'text': _(u'edit'), 'view': 'tag_edit', 'args': 'object.id', 'famfam 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]} -tag_new_holder = {'text': _(u'New holder'), 'view': 'tag_new_holder', 'args': 'object.pk', 'famfam': 'user', 'permissions': [ACLS_VIEW_ACL]} register_model_list_columns(Tag, [ { @@ -56,7 +55,6 @@ 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, '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_path_regex=[r'^tags/[^d]'])#TODO: change to children view regex or list -register_links(['tag_acl_list', 'tag_new_holder'], [tag_new_holder], menu_name='sidebar') register_links(Document, [tag_document_list], menu_name='form_header') register_links(['document_tags', 'tag_remove', 'tag_multiple_remove', 'tag_attach'], [tag_attach], menu_name='sidebar') diff --git a/apps/tags/urls.py b/apps/tags/urls.py index 403d4c258d..fff26800a8 100644 --- a/apps/tags/urls.py +++ b/apps/tags/urls.py @@ -14,5 +14,4 @@ urlpatterns = patterns('tags.views', url(r'^document/(?P\d+)/list/$', 'document_tags', (), 'document_tags'), url(r'^(?P\d+)/acl/list/$', 'tag_acl_list', (), 'tag_acl_list'), - url(r'^(?P\d+)/acl/holder/new/$', 'tag_new_holder', (), 'tag_new_holder'), ) diff --git a/apps/tags/views.py b/apps/tags/views.py index 8083f8d696..50e8929c10 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -301,15 +301,3 @@ def tag_acl_list(request, tag_pk): 'object': tag, } ) - - -def tag_new_holder(request, tag_pk): - tag = get_object_or_404(Tag, pk=tag_pk) - return acl_new_holder_for( - request, - tag, - extra_context={ - #'tag': tag, - 'object': tag, - } - ) From 9fae7269a6ef1c80f297b1d69aaf01715f0d7d39 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 08:11:59 -0400 Subject: [PATCH 243/484] Move Role class processing from the views to the model as methods --- apps/permissions/models.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index 2ec16fe68f..a518bff358 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -208,13 +208,6 @@ class Role(models.Model): verbose_name = _(u'role') verbose_name_plural = _(u'roles') - 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) - def __unicode__(self): return self.label @@ -222,6 +215,25 @@ 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')) From 4da328612dcbd4e9b20083162071cf9dab7f9176 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 08:12:50 -0400 Subject: [PATCH 244/484] Add option group support to the assign_remove view --- apps/common/views.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/common/views.py b/apps/common/views.py index c7969ad5c3..4d0030b0be 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -66,7 +66,7 @@ def get_obj_from_content_type_string(string): return ct.get_object_for_this_type(pk=pk) -def assign_remove(request, left_list, right_list, add_method, remove_method, left_list_title, right_list_title, decode_content_type=False, extra_context=None): +def assign_remove(request, left_list, right_list, add_method, remove_method, left_list_title, right_list_title, decode_content_type=False, extra_context=None, grouped=False): left_list_name = u'left_list' right_list_name = u'right_list' @@ -77,7 +77,14 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef choices=left_list()) if unselected_list.is_valid(): for selection in unselected_list.cleaned_data['selection']: - label = dict(left_list())[selection] + if grouped: + flat_list = [] + for group in left_list(): + flat_list.extend(group[1]) + else: + flat_list = left_list() + + label = dict(flat_list)[selection] if decode_content_type: selection_obj = get_obj_from_content_type_string(selection) else: @@ -96,7 +103,14 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef choices=right_list()) if selected_list.is_valid(): for selection in selected_list.cleaned_data['selection']: - label = dict(right_list())[selection] + if grouped: + flat_list = [] + for group in right_list(): + flat_list.extend(group[1]) + else: + flat_list = right_list() + + label = dict(flat_list)[selection] if decode_content_type: selection = get_obj_from_content_type_string(selection) try: From 3b3b29cb99dedcb48be284a125ccfff0401a63b0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 08:13:42 -0400 Subject: [PATCH 245/484] Update the role member add and removal views to use option groups and Role class methods --- apps/permissions/views.py | 67 ++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/apps/permissions/views.py b/apps/permissions/views.py index d1fa7c7d04..40c5b62691 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -16,8 +16,9 @@ from django.contrib.auth.models import User, Group 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 acls.classes import EncapsulatedObject from .models import Role, Permission, PermissionHolder, RoleMember from .forms import RoleForm, RoleForm_view @@ -244,35 +245,62 @@ def permission_revoke(request): return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) +class Member(EncapsulatedObject): + source_object_name = u'member_object' -def get_role_members(role): +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])] + + users = role.members(filter_dict={'member_type': user_ct}) + groups = role.members(filter_dict={'member_type': group_ct}) + + if separate: + return users, groups + else: + members = [] + + if users: + members.append((_(u'Users'), _as_choice_list(list(users)))) + + if groups: + members.append((_(u'Groups'), _as_choice_list(list(groups)))) + + return members def get_non_role_members(role): #non members = all users - members - staff - super users + member_users, member_groups = 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) + + 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)))) + + 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): @@ -281,8 +309,10 @@ def role_members(request, 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, @@ -290,5 +320,6 @@ def role_members(request, role_id): extra_context={ 'object': role, 'object_name': _(u'role'), - } + }, + grouped=True, ) From fe9db003d2785c569449d9dc674c2219c978a929 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 08:32:49 -0400 Subject: [PATCH 246/484] Improve navigation feedback when granting or revoking a role permission --- apps/permissions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/permissions/__init__.py b/apps/permissions/__init__.py index 6eb0d68be5..12c5be29aa 100644 --- a/apps/permissions/__init__.py +++ b/apps/permissions/__init__.py @@ -25,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='secondary_menu') +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'] From 8216953beddc94e9973a175da923c642ce855b80 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 08:33:20 -0400 Subject: [PATCH 247/484] Add anonymous user content type support to RoleMembers class --- apps/permissions/models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index a518bff358..b21cdbf7ae 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -239,7 +239,12 @@ 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') From 665ec099a97d0e35dffaeb825aa1d0b5f4697b67 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 08:33:44 -0400 Subject: [PATCH 248/484] Add anonymous user support to the role member add and remove views --- apps/permissions/views.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/permissions/views.py b/apps/permissions/views.py index 40c5b62691..a7e2df41fb 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -245,6 +245,9 @@ def permission_revoke(request): return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) +from common.models import AnonymousUserSingleton + + class Member(EncapsulatedObject): source_object_name = u'member_object' @@ -255,12 +258,14 @@ def _as_choice_list(items): def get_role_members(role, separate=False): user_ct = ContentType.objects.get(model='user') group_ct = ContentType.objects.get(model='group') + 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 + return users, groups, anonymous else: members = [] @@ -269,19 +274,23 @@ def get_role_members(role, separate=False): 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 = get_role_members(role, separate=True) + 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.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: @@ -289,6 +298,11 @@ def get_non_role_members(role): 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 From 11a023feed49cc1bc9e7d4e614bb7ba178266c24 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 09:07:25 -0400 Subject: [PATCH 249/484] Add Barry Rowlingson to the contributors file --- docs/contributors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributors.rst b/docs/contributors.rst index a89656ffb3..df1edfa199 100644 --- a/docs/contributors.rst +++ b/docs/contributors.rst @@ -35,6 +35,7 @@ Suggestions ----------- * Cezar Jenkins (https://twitter.com/#!/emperorcezar) * Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) +* Barry Rowlingson (http://geospaced.blogspot.com) Translations ------------ From 94e8bf2e74933a6a11b81145de59c2f4b7e450e1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 09:07:46 -0400 Subject: [PATCH 250/484] Update changelog --- docs/changelog.rst | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 89feffda1a..1e80f40926 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,10 +2,37 @@ Version 0.12 ------------ * Added new configuration option COMMON_ALLOW_ANONYMOUS_ACCESS to allow non authenticated access. -* Statistics fixes +* Navigation improvements. +* Statistics fixes. +* ACL support for documents, folders, tags and smart links. +* Anonymous user support for the permissions system. +* 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 + option groups +* Fixed get_image_cache_name regression in the OCR app * Italian translation by SeeOpen.IT (www.seeopen.it, info@seeopen.it) * Removed the 'db_index' argument from Text fields definition and migrations as it was causing error messages for MySQL users. +* 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. Version 0.11.1 -------------- From b34caacf131e12349859708ad5f13594f74af71f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 09:07:59 -0400 Subject: [PATCH 251/484] Update installation instructions to add --migrate parameter to syncdb step --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 98e96a283b..09d44f2f0a 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -39,7 +39,7 @@ If using the ``MySQL`` database manager, use the following commands:: 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:: From f3fe4edc74a8bbadb11f270b056b77b68b7a45c8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 9 Jan 2012 09:08:56 -0400 Subject: [PATCH 252/484] Add --migrate to another instance of syncdb command --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 09d44f2f0a..cba4e5e9f7 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -100,7 +100,7 @@ To install **Mayan EDMS** on Webfaction_, follow these steps: #. 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):: - $ ./manage.py syncdb + $ ./manage.py syncdb --migrate #. Collect the static files of the apps:: From 4b3a446d4ad8c57827358cef2c6469f9bda5f7a6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 17 Jan 2012 15:15:43 -0400 Subject: [PATCH 253/484] Improve metadata app navigation feedback --- apps/metadata/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index c2d97b87d9..099b908216 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -26,12 +26,12 @@ metadata_multiple_add = {'text': _(u'add metadata'), 'view': 'metadata_multiple_ 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]} 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]} 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]} @@ -43,10 +43,10 @@ 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]) From 5d8a4584aafdfefdeff900ddac525f7b0c19a790 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 17 Jan 2012 15:15:57 -0400 Subject: [PATCH 254/484] Add db migration instruction for 0.11.1 -> 0.12 --- docs/changelog.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 1e80f40926..572225bb14 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,24 @@ Version 0.12 ------------ +* Upgrade commands: + + * ./manage.py syncdb + * ./manage.py migrate permissions 0001 --fake + * ./manage.py migrate permissions + """ +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: yes + """ + * ./manage.py migrate documents + + * Added new configuration option COMMON_ALLOW_ANONYMOUS_ACCESS to allow non authenticated access. * Navigation improvements. From 93fc581ba09bd5c829dabf0c249d42a46adcbda6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 17 Jan 2012 16:33:51 -0400 Subject: [PATCH 255/484] Remove unused imports, file zf.write argument --- apps/common/compressed_files.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/common/compressed_files.py b/apps/common/compressed_files.py index 6737bbc9ed..cd3a57b40c 100644 --- a/apps/common/compressed_files.py +++ b/apps/common/compressed_files.py @@ -1,4 +1,4 @@ -import os, tempfile, zipfile +import zipfile try: import zlib @@ -54,7 +54,7 @@ class CompressedFile(object): file_input.seek(0) except AttributeError: # If not, keep it - self.zf.write(filename, arcname=arcname, compress_type=COMPRESSION) + self.zf.write(file_input, arcname=arcname, compress_type=COMPRESSION) else: self.zf.writestr(arcname, file_input.read()) From 1a285d56dc7e67b9671da0309a1cd8374f5c8a30 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 17 Jan 2012 16:40:30 -0400 Subject: [PATCH 256/484] PEP8 cleanups, remove unused imports --- apps/common/__init__.py | 1 - apps/common/widgets.py | 3 ++- apps/django_gpg/__init__.py | 5 +---- apps/django_gpg/api.py | 3 --- apps/django_gpg/forms.py | 3 --- apps/django_gpg/views.py | 4 +--- apps/document_signatures/__init__.py | 2 +- apps/document_signatures/managers.py | 12 ++++++------ apps/document_signatures/models.py | 2 +- apps/document_signatures/views.py | 2 +- apps/folders/models.py | 2 +- apps/folders/views.py | 3 +-- 12 files changed, 15 insertions(+), 27 deletions(-) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index 9dcd406a4f..928a5d36b7 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -5,7 +5,6 @@ import tempfile from django.utils.translation import ugettext_lazy as _ from django.contrib.auth import models as auth_models from django.contrib.auth.management import create_superuser -from django.db.models import signals from django.dispatch import receiver from django.db.models.signals import post_syncdb diff --git a/apps/common/widgets.py b/apps/common/widgets.py index bfedfaa776..9ec76a40a6 100644 --- a/apps/common/widgets.py +++ b/apps/common/widgets.py @@ -120,7 +120,8 @@ class ScrollableCheckboxSelectMultiple(forms.widgets.CheckboxSelectMultiple): exceds the height of the div ''' def render(self, name, value, attrs=None, choices=()): - if value is None: value = [] + if value is None: + value = [] has_id = attrs and 'id' in attrs final_attrs = self.build_attrs(attrs, name=name) output = [u'
      '] diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index 558dae9371..6448d825da 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -2,10 +2,7 @@ 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, - register_sidebar_template) -from main.api import register_diagnostic, register_maintenance_links +from navigation.api import register_links from project_setup.api import register_setup from hkp import Key as KeyServerKey diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 329ffe612e..5aea19746f 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -1,8 +1,5 @@ from __future__ import absolute_import -import types - -from pickle import dumps import logging import tempfile import os diff --git a/apps/django_gpg/forms.py b/apps/django_gpg/forms.py index 619035fd5d..9a9514fdb3 100644 --- a/apps/django_gpg/forms.py +++ b/apps/django_gpg/forms.py @@ -1,9 +1,6 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext -from django.core.urlresolvers import reverse -from django.utils.safestring import mark_safe -from django.conf import settings class KeySearchForm(forms.Form): diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index 60d400b018..ab49bbcfa9 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -1,6 +1,5 @@ from __future__ import absolute_import -from datetime import datetime import logging from django.utils.translation import ugettext_lazy as _ @@ -14,8 +13,7 @@ from django.conf import settings from django.template.defaultfilters import force_escape from permissions.models import Permission -from common.utils import pretty_size, parse_range, urlquote, \ - return_diff, encapsulate +from common.utils import (urlquote, encapsulate) from .api import Key, SIGNATURE_STATES from .runtime import gpg diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index cd9a120cc3..2311a2f1b2 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -72,7 +72,7 @@ def document_post_save_hook(instance): if not instance.pk: document_signature, created = DocumentVersionSignature.objects.get_or_create( document_version=instance.latest_version, - ) + ) #DocumentVersionSignature.objects.update_signed_state(instance.document) #@receiver(post_save, dispatch_uid='check_document_signature_state', sender=DocumentVersion) diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index 915fba4644..ff4ed05e9c 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -13,12 +13,12 @@ class DocumentVersionSignatureManager(models.Manager): document_signature, created = self.model.objects.get_or_create( document_version=document.latest_version, ) - + return document_signature - + def add_detached_signature(self, document, detached_signature): document_signature = self.get_document_signature(document) - + if document_signature.has_embedded_signature: raise Exception('document already has an embedded signature') else: @@ -27,13 +27,13 @@ class DocumentVersionSignatureManager(models.Manager): document_signature.delete_detached_signature() document_signature.signature_file = None document_signature.save() - + document_signature.signature_file = detached_signature document_signature.save() def has_detached_signature(self, document): document_signature = self.get_document_signature(document) - + if document_signature.signature_file: return True else: @@ -48,7 +48,7 @@ class DocumentVersionSignatureManager(models.Manager): def detached_signature(self, document): document_signature = self.get_document_signature(document) - + return document_signature.signature_file.storage.open(document_signature.signature_file.path) def verify_signature(self, document): diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 2c15523574..4b71af2f71 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -28,7 +28,7 @@ class DocumentVersionSignature(models.Model): def save(self, *args, **kwargs): if not self.pk: - self.has_embedded_signature = gpg.has_embedded_signature(self.document_version.open(raw=True)) + self.has_embedded_signature = gpg.has_embedded_signature(self.document_version.open(raw=True)) super(DocumentVersionSignature, self).save(*args, **kwargs) class Meta: diff --git a/apps/document_signatures/views.py b/apps/document_signatures/views.py index fc33c87a2a..024f59ffb4 100644 --- a/apps/document_signatures/views.py +++ b/apps/document_signatures/views.py @@ -117,7 +117,7 @@ def document_signature_download(request, document_pk): try: Permission.objects.check_permissions(request.user, [PERMISSION_SIGNATURE_DOWNLOAD]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_SIGNATURE_DOWNLOAD, request.user, document) + AccessEntry.objects.check_access(PERMISSION_SIGNATURE_DOWNLOAD, request.user, document) try: if DocumentVersionSignature.objects.has_detached_signature(document): diff --git a/apps/folders/models.py b/apps/folders/models.py index 20c2eda7a7..c032780241 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -23,7 +23,7 @@ class Folder(models.Model): @models.permalink def get_absolute_url(self): return ('folder_view', [self.pk]) - + @property def documents(self): return [folder_document.document for folder_document in self.folderdocument_set.all()] diff --git a/apps/folders/views.py b/apps/folders/views.py index de1dcc4ca4..b604f00d8b 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -7,7 +7,6 @@ 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.views.generic.list_detail import object_list from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied @@ -19,7 +18,7 @@ from common.utils import encapsulate from acls.models import AccessEntry from acls.views import acl_list_for -from .models import Folder, FolderDocument +from .models import Folder from .forms import FolderForm, FolderListForm from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_DELETE, From 8a5d0425b648e119610e260d4ef254a17c31d4a6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 13:52:19 -0400 Subject: [PATCH 257/484] PEP8 cleanups, style cleanups, unused imports --- apps/acls/classes.py | 7 +- apps/acls/forms.py | 13 +-- apps/acls/models.py | 10 +-- apps/acls/widgets.py | 6 +- apps/common/compressed_files.py | 18 ++-- apps/common/forms.py | 18 ++-- apps/common/models.py | 4 +- apps/common/templatetags/set_var.py | 12 +-- apps/common/utils.py | 14 +-- apps/common/views.py | 38 ++++---- apps/common/widgets.py | 22 ++--- apps/common/wizard.py | 18 ++-- apps/django_gpg/api.py | 6 +- apps/django_gpg/views.py | 6 +- apps/document_acls/__init__.py | 3 +- apps/document_acls/views.py | 19 ++-- apps/document_comments/__init__.py | 3 +- apps/document_comments/views.py | 4 +- apps/document_indexing/filesystem.py | 2 +- apps/document_indexing/os_specifics.py | 8 +- apps/document_indexing/views.py | 2 +- apps/document_signatures/__init__.py | 2 +- apps/document_signatures/managers.py | 2 +- apps/documents/__init__.py | 8 +- apps/documents/forms.py | 24 ++--- apps/documents/managers.py | 3 +- apps/documents/models.py | 116 ++++++++++++------------- apps/documents/tests.py | 32 ++++--- apps/documents/urls.py | 2 +- apps/documents/views.py | 100 ++++++++++----------- apps/documents/widgets.py | 17 ++-- apps/linking/views.py | 2 +- apps/lock_manager/managers.py | 1 - apps/lock_manager/models.py | 2 +- apps/navigation/api.py | 4 +- apps/navigation/widgets.py | 13 ++- apps/sources/__init__.py | 10 +-- apps/sources/forms.py | 4 +- apps/sources/managers.py | 2 +- apps/sources/models.py | 38 ++++---- apps/sources/utils.py | 20 ++--- apps/sources/views.py | 11 +-- 42 files changed, 311 insertions(+), 335 deletions(-) diff --git a/apps/acls/classes.py b/apps/acls/classes.py index 016a4ca797..91141e46b6 100644 --- a/apps/acls/classes.py +++ b/apps/acls/classes.py @@ -4,10 +4,10 @@ import logging import sys import types -from django.db import models from django.contrib.contenttypes.models import ContentType from django.db.models.base import ModelBase from django.template.defaultfilters import capfirst +from django.core.exceptions import ObjectDoesNotExist from common.models import AnonymousUserSingleton @@ -31,7 +31,7 @@ class EncapsulatedObject(object): if hasattr(value, 'contribute_to_class'): value.contribute_to_class(cls, name) else: - setattr(cls, name, value) + setattr(cls, name, value) @classmethod def set_source_object_name(cls, new_name): @@ -39,8 +39,7 @@ class EncapsulatedObject(object): #@classmethod #def encapsulate_list(cls, source_object=None, app_label=None, model=None, pk=None): - - + @classmethod def encapsulate(cls, source_object): source_object = AnonymousUserSingleton.objects.passthru_check(source_object) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 7f651f7f1b..e5a55a006c 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -4,8 +4,8 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group -from permissions.models import Permission, Role -from common.utils import generate_choices_w_labels, encapsulate, get_object_name +from permissions.models import Role +from common.utils import get_object_name from common.models import AnonymousUserSingleton from .classes import AccessHolder @@ -14,11 +14,12 @@ from .classes import AccessHolder def _as_choice_list(holders): return sorted([(AccessHolder.encapsulate(holder).gid, get_object_name(holder, display_object_type=False)) for holder in holders], key=lambda x: x[1]) + class HolderSelectionForm(forms.Form): holder_gid = forms.ChoiceField( label=_(u'New holder') ) - + def __init__(self, *args, **kwargs): current_holders = kwargs.pop('current_holders', []) if current_holders: @@ -29,14 +30,14 @@ class HolderSelectionForm(forms.Form): users = set(User.objects.filter(is_active=True)) - set(staff_users) - set(super_users) - set(current_holders) roles = set(Role.objects.all()) - set(current_holders) groups = set(Group.objects.all()) - set(current_holders) - + non_holder_list = [] if users: non_holder_list.append((_(u'Users'), _as_choice_list(list(users)))) - + if groups: non_holder_list.append((_(u'Groups'), _as_choice_list(list(groups)))) - + if roles: non_holder_list.append((_(u'Roles'), _as_choice_list(list(roles)))) diff --git a/apps/acls/models.py b/apps/acls/models.py index 865e44e567..55df6a253e 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -8,9 +8,7 @@ from django.utils.translation import ugettext from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic from django.core.exceptions import PermissionDenied -from django.core.urlresolvers import reverse from django.core.exceptions import ObjectDoesNotExist -from django.shortcuts import get_object_or_404 from permissions.models import StoredPermission @@ -22,9 +20,9 @@ logger = logging.getLogger(__name__) class AccessEntry(models.Model): - ''' + """ Model that hold the permission, object, actor relationship - ''' + """ permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) holder_type = models.ForeignKey( @@ -59,10 +57,10 @@ class AccessEntry(models.Model): class DefaultAccessEntry(models.Model): - ''' + """ Model that holds the permission, class, actor relationship, that will be added upon the creation of an instance of said class - ''' + """ @classmethod def get_classes(cls): return [AccessObjectClass.encapsulate(cls) for cls in get_classes()] diff --git a/apps/acls/widgets.py b/apps/acls/widgets.py index 3c13fce54b..521a60d40b 100644 --- a/apps/acls/widgets.py +++ b/apps/acls/widgets.py @@ -2,10 +2,6 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe -from django import forms -from django.forms.util import flatatt -from django.utils.html import conditional_escape -from django.utils.encoding import force_unicode from django.contrib.contenttypes.models import ContentType from django.db.models.base import ModelBase from django.template.defaultfilters import capfirst @@ -28,5 +24,5 @@ def object_w_content_type_icon(obj): label = obj.get_full_name() else: label = unicode(obj) - + return mark_safe('%s%s' % (content_type_icon(content_type), capfirst(label))) diff --git a/apps/common/compressed_files.py b/apps/common/compressed_files.py index cd3a57b40c..2350f1ace1 100644 --- a/apps/common/compressed_files.py +++ b/apps/common/compressed_files.py @@ -24,11 +24,11 @@ class CompressedFile(object): self._open(file_input) else: self._create() - + def _create(self): self.descriptor = StringIO() self.zf = zipfile.ZipFile(self.descriptor, mode='w') - + def _open(self, file_input): try: # Is it a file like object? @@ -37,7 +37,7 @@ class CompressedFile(object): # If not, try open it. self.descriptor = open(file_input, 'r+b') else: - self.descriptor = file_input + self.descriptor = file_input try: test = zipfile.ZipFile(self.descriptor, mode='r') @@ -54,23 +54,23 @@ class CompressedFile(object): file_input.seek(0) except AttributeError: # If not, keep it - self.zf.write(file_input, arcname=arcname, compress_type=COMPRESSION) + self.zf.write(file_input, arcname=arcname, compress_type=COMPRESSION) else: self.zf.writestr(arcname, file_input.read()) def contents(self): return [filename for filename in self.zf.namelist() if not filename.endswith('/')] - + def get_content(self, filename): return self.zf.read(filename) - + def write(self, filename=None): - # fix for Linux zip files read in Windows - for file in self.zf.filelist: + # fix for Linux zip files read in Windows + for file in self.zf.filelist: file.create_system = 0 self.descriptor.seek(0) - + if filename: descriptor = open(filename, 'w') descriptor.write(self.descriptor.read()) diff --git a/apps/common/forms.py b/apps/common/forms.py index 91aff0b67e..11d91d0c2c 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -92,10 +92,10 @@ class FilterForm(forms.Form): class ChoiceForm(forms.Form): - ''' + """ Form to be used in side by side templates used to add or remove items from a many to many field - ''' + """ def __init__(self, *args, **kwargs): choices = kwargs.pop('choices', []) label = kwargs.pop('label', _(u'Selection')) @@ -108,28 +108,28 @@ class ChoiceForm(forms.Form): class UserForm_view(DetailForm): - ''' + """ Form used to display an user's public details - ''' + """ class Meta: model = User fields = ('username', 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser', 'last_login', 'date_joined', 'groups') class UserForm(forms.ModelForm): - ''' + """ Form used to edit an user's mininal fields by the user himself - ''' + """ class Meta: model = User fields = ('first_name', 'last_name') class EmailAuthenticationForm(AuthenticationForm): - ''' + """ Override the default authentication form to use email address authentication - ''' + """ email = forms.CharField(label=_(u'Email'), max_length=75, widget=EmailInput() ) @@ -153,7 +153,7 @@ EmailAuthenticationForm.base_fields.keyOrder = ['email', 'password'] class FileDisplayForm(forms.Form): text = forms.CharField( - label='',#_(u'Text'), + label='', # _(u'Text'), widget=forms.widgets.Textarea( attrs={'cols': 40, 'rows': 20, 'readonly': 'readonly'} ) diff --git a/apps/common/models.py b/apps/common/models.py index cb9a98d91c..effe8196ed 100644 --- a/apps/common/models.py +++ b/apps/common/models.py @@ -34,14 +34,14 @@ class AnonymousUserSingletonManager(SingletonManager): return self.model.objects.get() else: return user - + class AnonymousUserSingleton(Singleton): objects = AnonymousUserSingletonManager() def __unicode__(self): return ugettext('Anonymous user') - + class Meta: verbose_name = _(u'anonymous user') verbose_name_plural = _(u'anonymous user') diff --git a/apps/common/templatetags/set_var.py b/apps/common/templatetags/set_var.py index c818a7188c..3d1f8c0084 100644 --- a/apps/common/templatetags/set_var.py +++ b/apps/common/templatetags/set_var.py @@ -1,12 +1,13 @@ from django import template - + register = template.Library() - + + class SetVarNode(template.Node): def __init__(self, var_name, var_value): self.var_name = var_name self.var_value = var_value - + def render(self, context): try: value = template.Variable(self.var_value).resolve(context) @@ -17,7 +18,8 @@ class SetVarNode(template.Node): context.dicts[0][self.var_name] = value return u"" - + + def set_var(parser, token): """ {% set = %} @@ -26,5 +28,5 @@ def set_var(parser, token): if len(parts) < 4: raise template.TemplateSyntaxError("'set' tag must be of the form: {% set = %}") return SetVarNode(parts[1], parts[3]) - + register.tag('set', set_var) diff --git a/apps/common/utils.py b/apps/common/utils.py index e472a00d3b..3905be558c 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -1,4 +1,4 @@ - # -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from __future__ import absolute_import import os @@ -18,7 +18,7 @@ from django.contrib.auth.models import User def urlquote(link=None, get=None): - u''' + u""" This method does both: urlquote() and urlencode() urlqoute(): Quote special characters in 'link' @@ -33,7 +33,7 @@ def urlquote(link=None, get=None): urlquote('/mypath/', {'key': 'value'}) --> '/mypath/?key=value' urlquote('/mypath/', {'key': ['value1', 'value2']}) --> '/mypath/?key=value1&key=value2' urlquote({'key': ['value1', 'value2']}) --> 'key=value1&key=value2' - ''' + """ if get is None: get = [] @@ -112,9 +112,9 @@ def pretty_size_10(size): # http://www.johncardinal.com/tmgutil/capitalizenames.htm def proper_name(name): - ''' + """ Does the work of capitalizing a name (can be a full name). - ''' + """ mc = re.compile(r'^Mc(\w)(?=\w)', re.I) mac = re.compile(r'^Mac(\w)(?=\w)', re.I) suffixes = [ @@ -330,7 +330,7 @@ def generate_choices_w_labels(choices, display_object_type=True): return sorted(results, key=lambda x: x[1]) -def get_object_name(obj, display_object_type=True): +def get_object_name(obj, display_object_type=True): ct_label = ContentType.objects.get_for_model(obj).name if isinstance(obj, User): label = obj.get_full_name() if obj.get_full_name() else obj @@ -342,7 +342,7 @@ def get_object_name(obj, display_object_type=True): verbose_name = unicode(obj._meta.verbose_name) except AttributeError: verbose_name = ct_label - + return u'%s: %s' % (verbose_name, label) else: return u'%s' % (label) diff --git a/apps/common/views.py b/apps/common/views.py index 4d0030b0be..46aa782bad 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -18,19 +18,19 @@ from .conf.settings import LOGIN_METHOD def password_change_done(request): - ''' + """ View called when the new user password has been accepted - ''' + """ messages.success(request, _(u'Your password has been successfully changed.')) return redirect('home') def multi_object_action_view(request): - ''' + """ Proxy view called first when using a multi object action, which then redirects to the appropiate specialized view - ''' + """ next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) @@ -83,7 +83,7 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef flat_list.extend(group[1]) else: flat_list = left_list() - + label = dict(flat_list)[selection] if decode_content_type: selection_obj = get_obj_from_content_type_string(selection) @@ -109,7 +109,7 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef flat_list.extend(group[1]) else: flat_list = right_list() - + label = dict(flat_list)[selection] if decode_content_type: selection = get_obj_from_content_type_string(selection) @@ -159,9 +159,9 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef def current_user_details(request): - ''' + """ Display the current user's details - ''' + """ form = UserForm_view(instance=request.user) return render_to_response( @@ -174,9 +174,9 @@ def current_user_details(request): def current_user_edit(request): - ''' + """ Allow an user to edit his own details - ''' + """ next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('current_user_details')))) @@ -199,15 +199,15 @@ def current_user_edit(request): def login_view(request): - ''' - Control how the use is to be authenticated, options are 'email' and + """ + Control how the use is to be authenticated, options are 'email' and 'username' - ''' + """ kwargs = {'template_name': 'login.html'} - + if LOGIN_METHOD == 'email': kwargs['authentication_form'] = EmailAuthenticationForm - + if not request.user.is_authenticated(): context = {'web_theme_view_type': 'plain'} else: @@ -217,9 +217,9 @@ def login_view(request): def changelog_view(request): - ''' + """ Display the included Changelog.txt file from the about menu - ''' + """ form = ChangelogForm() return render_to_response( 'generic_detail.html', { @@ -230,9 +230,9 @@ def changelog_view(request): def license_view(request): - ''' + """ Display the included LICENSE file from the about menu - ''' + """ form = LicenseForm() return render_to_response( 'generic_detail.html', { diff --git a/apps/common/widgets.py b/apps/common/widgets.py index 9ec76a40a6..c2f7906c56 100644 --- a/apps/common/widgets.py +++ b/apps/common/widgets.py @@ -10,10 +10,10 @@ from django.utils.encoding import force_unicode class PlainWidget(forms.widgets.Widget): - ''' + """ Class to define a form widget that effectively nulls the htmls of a widget and reduces the output to only it's value - ''' + """ def render(self, name, value, attrs=None): return mark_safe(u'%s' % value) @@ -74,11 +74,11 @@ def two_state_template(state, famfam_ok_icon=u'tick', famfam_fail_icon=u'cross') class TextAreaDiv(forms.widgets.Widget): - ''' + """ Class to define a form widget that simulates the behavior of a Textarea widget but using a div tag instead - ''' - + """ + def __init__(self, attrs=None): # The 'rows' and 'cols' attributes are required for HTML correctness. default_attrs = {'class': 'text_area_div'} @@ -98,10 +98,10 @@ class TextAreaDiv(forms.widgets.Widget): # From: http://www.peterbe.com/plog/emailinput-html5-django class EmailInput(forms.widgets.Input): - ''' - Class for a login form widget that accepts only well formated + """ + Class for a login form widget that accepts only well formated email address - ''' + """ input_type = 'email' def render(self, name, value, attrs=None): @@ -114,11 +114,11 @@ class EmailInput(forms.widgets.Input): class ScrollableCheckboxSelectMultiple(forms.widgets.CheckboxSelectMultiple): - ''' + """ Class for a form widget composed of a selection of checkboxes wrapped in a div tag with automatic overflow to add scrollbars when the list exceds the height of the div - ''' + """ def render(self, name, value, attrs=None, choices=()): if value is None: value = [] @@ -142,5 +142,5 @@ class ScrollableCheckboxSelectMultiple(forms.widgets.CheckboxSelectMultiple): option_label = conditional_escape(force_unicode(option_label)) output.append(u'
    • %s %s
    • ' % (label_for, rendered_cb, option_label)) output.append(u'
    ') - + return mark_safe(u'
    %s
    ' % u'\n'.join(output)) diff --git a/apps/common/wizard.py b/apps/common/wizard.py index 914dcd062a..5454277135 100644 --- a/apps/common/wizard.py +++ b/apps/common/wizard.py @@ -1,4 +1,4 @@ -'''Common abstract classes for forms.''' +"""Common abstract classes for forms.""" try: import cPickle as pickle except ImportError: @@ -15,13 +15,13 @@ __all__ = ('security_hash', 'BoundFormWizard') def security_hash_new(form, exclude=None, *args): - ''' + """ Calculates a security hash for the given Form/FormSet instance. This creates a list of the form field names/values in a deterministic order, pickles the result with the SECRET_KEY setting, then takes an md5 hash of that. - ''' + """ data = [] if exclude is None: @@ -52,20 +52,20 @@ def security_hash_new(form, exclude=None, *args): class BoundFormWizard(FormWizard): - ''' + """ Render prev_fields as a list of bound form fields in the template context rather than raw html. - ''' - + """ + def security_hash(self, request, form): - ''' + """ Calculates the security hash for the given HttpRequest and Form/FormSet instances. Subclasses may want to take into account request-specific information, such as the IP address. - ''' - + """ + return security_hash_new(form) def render(self, form, request, step, context=None): diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 5aea19746f..f4aad2fa63 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -4,9 +4,7 @@ import logging import tempfile import os -from django.core.files.base import File from django.utils.translation import ugettext_lazy as _ -from django.utils.http import urlquote_plus from hkp import KeyServer import gnupg @@ -70,7 +68,7 @@ SIGNATURE_STATES = { 'text': _(u'Document is signed with a valid signature.'), 'icon': 'document_signature.png' }, -} +} class Key(object): @@ -107,7 +105,7 @@ class Key(object): keys = gpg.gpg.list_keys(secret=secret) key = next((key for key in keys if key['keyid'] == key_id), None) if not key: - if search_keyservers and secret==False: + if search_keyservers and secret == False: try: gpg.receive_key(key_id) return Key(gpg, key_id) diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index ab49bbcfa9..af3c52ef7c 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -4,13 +4,9 @@ import logging from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response, get_object_or_404 +from django.shortcuts import render_to_response from django.template import RequestContext from django.contrib import messages -from django.core.urlresolvers import reverse -from django.utils.safestring import mark_safe -from django.conf import settings -from django.template.defaultfilters import force_escape from permissions.models import Permission from common.utils import (urlquote, encapsulate) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index a904759f4d..376b048843 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -1,8 +1,7 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import Document -from navigation.api import register_links, register_multi_item_links -from project_setup.api import register_setup +from navigation.api import register_links from acls import ACLS_VIEW_ACL, ACLS_EDIT_ACL from acls.api import class_permissions diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 4b20a038ee..5938fec434 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -1,17 +1,16 @@ -from django.shortcuts import render_to_response, get_object_or_404 +from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext_lazy as _ from documents.models import Document from acls.views import acl_list_for -from acls.models import AccessEntry def document_acl_list(request, document_id): - document = get_object_or_404(Document, pk=document_id) - return acl_list_for( - request, - document, - extra_context={ - 'object': document, - } - ) + document = get_object_or_404(Document, pk=document_id) + return acl_list_for( + request, + document, + extra_context={ + 'object': document, + } + ) diff --git a/apps/document_comments/__init__.py b/apps/document_comments/__init__.py index 6758a06811..2356f36885 100644 --- a/apps/document_comments/__init__.py +++ b/apps/document_comments/__init__.py @@ -6,7 +6,6 @@ from django.contrib.comments.models import Comment from django.contrib.contenttypes import generic from navigation.api import register_links, register_model_list_columns -from permissions.models import PermissionNamespace, Permission from common.utils import encapsulate from acls.api import class_permissions from documents.models import Document @@ -16,7 +15,7 @@ if 'django.contrib.comments' not in settings.INSTALLED_APPS: from .permissions import (PERMISSION_COMMENT_CREATE, PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_VIEW) - + comment_delete = {'text': _('delete'), 'view': 'comment_delete', 'args': 'object.pk', 'famfam': 'comment_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_multiple_delete = {'text': _('delete'), 'view': 'comment_multiple_delete', 'args': 'object.pk', 'famfam': 'comments_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} comment_add = {'text': _('add comment'), 'view': 'comment_add', 'args': 'object.pk', 'famfam': 'comment_add', 'permissions': [PERMISSION_COMMENT_CREATE]} diff --git a/apps/document_comments/views.py b/apps/document_comments/views.py index cb9cc0a92e..7c089b3cda 100644 --- a/apps/document_comments/views.py +++ b/apps/document_comments/views.py @@ -31,7 +31,7 @@ def comment_delete(request, comment_id=None, comment_id_list=None): Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_DELETE]) except PermissionDenied: comments = AccessEntry.objects.filter_objects_by_access(PERMISSION_COMMENT_DELETE, request.user, comments, related='content_object') - + if not comments: messages.error(request, _(u'Must provide at least one comment.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) @@ -81,7 +81,7 @@ def comment_add(request, document_id): Permission.objects.check_permissions(request.user, [PERMISSION_COMMENT_CREATE]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_COMMENT_CREATE, request.user, document) - + post_action_redirect = None next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py index 4b24a9d4d6..7c732007cc 100644 --- a/apps/document_indexing/filesystem.py +++ b/apps/document_indexing/filesystem.py @@ -40,7 +40,7 @@ def fs_create_document_link(index_instance, document, suffix=0): if FILESERVING_ENABLE: filename = assemble_suffixed_filename(document.file.name, suffix) filepath = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance), filename]) - + try: os.symlink(document.file.path, filepath) except OSError, exc: diff --git a/apps/document_indexing/os_specifics.py b/apps/document_indexing/os_specifics.py index 97bdc426e4..d57eae409c 100644 --- a/apps/document_indexing/os_specifics.py +++ b/apps/document_indexing/os_specifics.py @@ -6,16 +6,16 @@ from .conf.settings import SUFFIX_SEPARATOR def assemble_suffixed_filename(filename, suffix=0): - ''' + """ Split document filename, to attach suffix to the name part then re attacht the extension - ''' - + """ + if suffix: name, extension = filename.split(os.split(os.extsep)) return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension]) else: - return file_filename + return filename def assemble_path_from_list(directory_list): diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 0505ad5cac..8d405fc3d5 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -59,7 +59,7 @@ def index_instance_list(request, index_id=None): }, { 'name': _(u'items'), - 'attribute': encapsulate(lambda x: x.documents.count() if x.index.link_documents else x.get_children().count() ) + 'attribute': encapsulate(lambda x: x.documents.count() if x.index.link_documents else x.get_children().count()) } ], 'title': title, diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index 2311a2f1b2..ac4eb1413e 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -72,7 +72,7 @@ def document_post_save_hook(instance): if not instance.pk: document_signature, created = DocumentVersionSignature.objects.get_or_create( document_version=instance.latest_version, - ) + ) #DocumentVersionSignature.objects.update_signed_state(instance.document) #@receiver(post_save, dispatch_uid='check_document_signature_state', sender=DocumentVersion) diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index ff4ed05e9c..f1c7bd39dc 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -43,7 +43,7 @@ class DocumentVersionSignatureManager(models.Manager): logger.debug('document: %s' % document) document_signature = self.get_document_signature(document) - + return document_signature.has_embedded_signature def detached_signature(self, document): diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 1d052cfa24..f7f1e4a043 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -34,6 +34,8 @@ from .conf import settings as document_settings from .widgets import document_thumbnail # Document page links expressions + + def is_first_page(context): return context['page'].page_number <= 1 @@ -179,7 +181,7 @@ register_top_menu( r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents' ], #children_view_regex=[r'upload'], - children_views=['document_folder_list', 'folder_add_document', 'document_index_list', 'upload_version',], + children_views=['document_folder_list', 'folder_add_document', 'document_index_list', 'upload_version', ], position=1 ) @@ -197,7 +199,7 @@ if (validate_path(document_settings.CACHE_PATH) == False) or (not document_setti register_setup(document_type_setup) class_permissions(Document, [ - PERMISSION_DOCUMENT_PROPERTIES_EDIT, + PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_DELETE, @@ -205,5 +207,5 @@ class_permissions(Document, [ PERMISSION_DOCUMENT_TRANSFORM, PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_VERSION_REVERT, - PERMISSION_HISTORY_VIEW + PERMISSION_HISTORY_VIEW ]) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 88cfa46395..398e9f59ae 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -5,13 +5,11 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.core.urlresolvers import reverse from django.utils.safestring import mark_safe -from django.conf import settings from common.forms import DetailForm from common.literals import PAGE_SIZE_CHOICES, PAGE_ORIENTATION_CHOICES -from common.conf.settings import DEFAULT_PAPER_SIZE -from common.conf.settings import DEFAULT_PAGE_ORIENTATION -from common.widgets import TextAreaDiv +from common.conf.settings import DEFAULT_PAPER_SIZE, DEFAULT_PAGE_ORIENTATION +from common.widgets import TextAreaDiv from .models import (Document, DocumentType, DocumentPage, DocumentPageTransformation, DocumentTypeFilename, @@ -19,6 +17,7 @@ from .models import (Document, DocumentType, from .widgets import document_html_widget from .literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES) + # Document page forms class DocumentPageTransformationForm(forms.ModelForm): class Meta: @@ -105,7 +104,7 @@ class DocumentPagesCarouselWidget(forms.widgets.Widget): output.append(u'
    ') for page in value.pages.all(): - + output.append(u'
    ') output.append(u'
    %(page_string)s %(page)s
    ' % {'page_string': ugettext(u'Page'), 'page': page.page_number}) output.append( @@ -180,24 +179,24 @@ class DocumentForm(forms.ModelForm): if instance: self.version_fields(instance) - + def version_fields(self, document): self.fields['version_update'] = forms.ChoiceField( label=_(u'Version update'), choices=DocumentVersion.get_version_update_choices(document.latest_version) ) - + self.fields['release_level'] = forms.ChoiceField( label=_(u'Release level'), choices=RELEASE_LEVEL_CHOICES, initial=RELEASE_LEVEL_FINAL, ) - + self.fields['serial'] = forms.IntegerField( label=_(u'Release level serial'), initial=0, widget=forms.widgets.TextInput( - attrs = {'style': 'width: auto;'} + attrs={'style': 'width: auto;'} ), ) @@ -210,7 +209,7 @@ class DocumentForm(forms.ModelForm): new_filename = forms.CharField( label=_('New document filename'), required=False ) - + def clean(self): cleaned_data = self.cleaned_data cleaned_data['new_version_data'] = { @@ -221,7 +220,8 @@ class DocumentForm(forms.ModelForm): } # Always return the full collection of cleaned data. - return cleaned_data + return cleaned_data + class DocumentForm_edit(DocumentForm): """ @@ -230,7 +230,7 @@ class DocumentForm_edit(DocumentForm): class Meta: model = Document exclude = ('file', 'document_type', 'tags') - + def __init__(self, *args, **kwargs): super(DocumentForm_edit, self).__init__(*args, **kwargs) self.fields.pop('serial') diff --git a/apps/documents/managers.py b/apps/documents/managers.py index b564d44885..83555b9568 100644 --- a/apps/documents/managers.py +++ b/apps/documents/managers.py @@ -4,7 +4,6 @@ from ast import literal_eval from datetime import datetime from django.db import models -from django.contrib.auth.models import AnonymousUser from .conf.settings import RECENT_COUNT @@ -18,7 +17,7 @@ class RecentDocumentManager(models.Manager): to_delete = self.model.objects.filter(user=user)[RECENT_COUNT:] for recent_to_delete in to_delete: recent_to_delete.delete() - + def get_for_user(self, user): if user.is_authenticated(): return [recent_document.document for recent_document in self.model.objects.filter(user=user)] diff --git a/apps/documents/models.py b/apps/documents/models.py index 963a5e056f..135e2e3825 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -11,8 +11,8 @@ import logging try: from cStringIO import StringIO except ImportError: - from StringIO import StringIO - + from StringIO import StringIO + from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext @@ -30,7 +30,7 @@ from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_PAGE_NUMBER) from .conf.settings import (CHECKSUM_FUNCTION, UUID_FUNCTION, - STORAGE_BACKEND, PREVIEW_SIZE, DISPLAY_SIZE, CACHE_PATH, + STORAGE_BACKEND, DISPLAY_SIZE, CACHE_PATH, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL) from .managers import (RecentDocumentManager, DocumentPageTransformationManager) @@ -70,9 +70,9 @@ class DocumentType(models.Model): class Document(models.Model): - ''' + """ Defines a single document with it's fields and properties - ''' + """ uuid = models.CharField(max_length=48, blank=True, editable=False) document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'), null=True, blank=True) description = models.TextField(blank=True, null=True, verbose_name=_(u'description')) @@ -133,7 +133,7 @@ class Document(models.Model): zoom = ZOOM_MAX_LEVEL rotation = rotation % 360 - + try: file_path = self.get_valid_image(size=size, page=page, zoom=zoom, rotation=rotation, version=version) except UnknownFileFormat: @@ -142,7 +142,7 @@ class Document(models.Model): file_path = get_error_icon_file_path() except: file_path = get_error_icon_file_path() - + if as_base64: image = open(file_path, 'r') out = StringIO() @@ -159,16 +159,16 @@ class Document(models.Model): def add_as_recent_document_for_user(self, user): RecentDocument.objects.add_document_for_user(user, self) - + def delete(self, *args, **kwargs): for version in self.versions.all(): version.delete() return super(Document, self).delete(*args, **kwargs) - + @property def size(self): return self.latest_version.size - + def new_version(self, file, comment=None, version_update=None, release_level=None, serial=None): logger.debug('creating new document version') if version_update: @@ -177,12 +177,12 @@ class Document(models.Model): new_version = DocumentVersion( document=self, file=file, - major = new_version_dict.get('major'), - minor = new_version_dict.get('minor'), - micro = new_version_dict.get('micro'), - release_level = release_level, - serial = serial, - comment = comment, + major=new_version_dict.get('major'), + minor=new_version_dict.get('minor'), + micro=new_version_dict.get('micro'), + release_level=release_level, + serial=serial, + comment=comment, ) new_version.save() else: @@ -198,20 +198,20 @@ class Document(models.Model): # Proxy methods def open(self, *args, **kwargs): - ''' + """ Return a file descriptor to a document's file irrespective of the storage backend - ''' + """ return self.latest_version.open(*args, **kwargs) - + def save_to_file(self, *args, **kwargs): return self.latest_version.save_to_file(*args, **kwargs) def exists(self): - ''' - Returns a boolean value that indicates if the document's + """ + Returns a boolean value that indicates if the document's latest version file exists in storage - ''' + """ return self.latest_version.exists() # Compatibility methods @@ -226,7 +226,7 @@ class Document(models.Model): @property def file_mime_encoding(self): return self.latest_version.encoding - + @property def file_filename(self): return self.latest_version.filename @@ -275,12 +275,12 @@ class Document(models.Model): class DocumentVersion(models.Model): - ''' + """ Model that describes a document version and its properties - ''' + """ _pre_open_hooks = {} _post_save_hooks = {} - + @staticmethod def get_version_update_choices(document_version): return ( @@ -288,7 +288,7 @@ class DocumentVersion(models.Model): (VERSION_UPDATE_MINOR, _(u'Minor %(major)i.%(minor)i, (some updates)') % document_version.get_new_version_dict(VERSION_UPDATE_MINOR)), (VERSION_UPDATE_MICRO, _(u'Micro %(major)i.%(minor)i.%(micro)i, (fixes)') % document_version.get_new_version_dict(VERSION_UPDATE_MICRO)) ) - + @classmethod def register_pre_open_hook(cls, order, func): cls._pre_open_hooks[order] = func @@ -296,7 +296,7 @@ class DocumentVersion(models.Model): @classmethod def register_post_save_hook(cls, order, func): cls._post_save_hooks[order] = func - + document = models.ForeignKey(Document, verbose_name=_(u'document'), editable=False) major = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1, editable=False) minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0, editable=False) @@ -305,7 +305,7 @@ class DocumentVersion(models.Model): serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0, editable=False) timestamp = models.DateTimeField(verbose_name=_(u'timestamp'), editable=False) comment = models.TextField(blank=True, verbose_name=_(u'comment')) - + # File related fields file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) mimetype = models.CharField(max_length=64, default='', editable=False) @@ -342,11 +342,11 @@ class DocumentVersion(models.Model): 'minor': self.minor, 'micro': self.micro + 1, } - + def get_formated_version(self): - ''' + """ Return the formatted version information - ''' + """ vers = [u'%i.%i' % (self.major, self.minor), ] if self.micro: @@ -360,10 +360,10 @@ class DocumentVersion(models.Model): return self.documentpage_set def save(self, *args, **kwargs): - ''' + """ Overloaded save method that updates the document version's checksum, mimetype, page count and transformation when created - ''' + """ new_document = not self.pk if not self.pk: self.timestamp = datetime.datetime.now() @@ -371,9 +371,9 @@ class DocumentVersion(models.Model): #Only do this for new documents transformations = kwargs.pop('transformations', None) super(DocumentVersion, self).save(*args, **kwargs) - + for key in sorted(DocumentVersion._post_save_hooks): - DocumentVersion._post_save_hooks[key](self) + DocumentVersion._post_save_hooks[key](self) if new_document: #Only do this for new documents @@ -385,10 +385,10 @@ class DocumentVersion(models.Model): self.apply_default_transformations(transformations) def update_checksum(self, save=True): - ''' + """ Open a document version's file and update the checksum field using the user provided checksum function - ''' + """ if self.exists(): source = self.open() self.checksum = unicode(CHECKSUM_FUNCTION(source.read())) @@ -444,17 +444,17 @@ class DocumentVersion(models.Model): page_transformation.save() def revert(self): - ''' + """ Delete the subsequent versions after this one - ''' + """ for version in self.document.versions.filter(timestamp__gt=self.timestamp): version.delete() def update_mimetype(self, save=True): - ''' + """ Read a document verions's file and determine the mimetype by calling the get_mimetype wrapper - ''' + """ if self.exists(): try: self.mimetype, self.encoding = get_mimetype(self.open(), self.filename) @@ -466,35 +466,35 @@ class DocumentVersion(models.Model): self.save() def delete(self, *args, **kwargs): - self.file.storage.delete(self.file.path) + self.file.storage.delete(self.file.path) return super(DocumentVersion, self).delete(*args, **kwargs) def exists(self): - ''' + """ Returns a boolean value that indicates if the document's file exists in storage - ''' + """ return self.file.storage.exists(self.file.path) - + def open(self, raw=False): - ''' + """ Return a file descriptor to a document version's file irrespective of the storage backend - ''' + """ if raw: return self.file.storage.open(self.file.path) else: result = self.file.storage.open(self.file.path) for key in sorted(DocumentVersion._pre_open_hooks): result = DocumentVersion._pre_open_hooks[key](result, self) - + return result def save_to_file(self, filepath, buffer_size=1024 * 1024): - ''' + """ Save a copy of the document from the document storage backend to the local filesystem - ''' + """ input_descriptor = self.open() output_descriptor = open(filepath, 'wb') while True: @@ -507,7 +507,7 @@ class DocumentVersion(models.Model): output_descriptor.close() input_descriptor.close() return filepath - + @property def size(self): if self.exists(): @@ -517,10 +517,10 @@ class DocumentVersion(models.Model): class DocumentTypeFilename(models.Model): - ''' + """ List of filenames available to a specific document type for the quick rename functionality - ''' + """ document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type')) filename = models.CharField(max_length=128, verbose_name=_(u'filename'), db_index=True) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) @@ -535,12 +535,12 @@ class DocumentTypeFilename(models.Model): class DocumentPage(models.Model): - ''' + """ Model that describes a document version page including it's content - ''' + """ # New parent field document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version')) - + # Unchanged fields content = models.TextField(blank=True, null=True, verbose_name=_(u'content')) page_label = models.CharField(max_length=32, blank=True, null=True, verbose_name=_(u'page label')) @@ -568,7 +568,7 @@ class DocumentPage(models.Model): @property def siblings(self): return DocumentPage.objects.filter(document_version=self.document_version) - + # Compatibility methods @property def document(self): diff --git a/apps/documents/tests.py b/apps/documents/tests.py index 8f03074fa6..f8c7164cdb 100644 --- a/apps/documents/tests.py +++ b/apps/documents/tests.py @@ -3,7 +3,6 @@ from __future__ import absolute_import import os from django.utils import unittest -from django.test.client import Client from django.conf import settings from django.core.files.base import File @@ -19,45 +18,45 @@ class DocumentTestCase(unittest.TestCase): self.document_type.save() self.document = Document( - document_type = self.document_type, - description = 'description', + document_type=self.document_type, + description='description', ) self.document.save() #return File(file(self.filepath, 'rb'), name=self.filename) file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf')) new_version = self.document.new_version(file=File(file_object, name='mayan_11_1.pdf')) - file_object.close() + file_object.close() def runTest(self): self.failUnlessEqual(self.document_type.name, 'test doc type') self.failUnlessEqual(self.document.exists(), True) self.failUnlessEqual(self.document.size, 272213) - + self.failUnlessEqual(self.document.file_mimetype, 'application/pdf') self.failUnlessEqual(self.document.file_mime_encoding, 'binary') self.failUnlessEqual(self.document.file_filename, 'mayan_11_1.pdf') self.failUnlessEqual(self.document.checksum, 'c637ffab6b8bb026ed3784afdb07663fddc60099853fae2be93890852a69ecf3') self.failUnlessEqual(self.document.page_count, 47) - + self.failUnlessEqual(self.document.latest_version.get_formated_version(), '1.0') self.failUnlessEqual(self.document.has_detached_signature(), False) - + file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf.gpg')) new_version_data = { 'comment': 'test comment 1', 'version_update': VERSION_UPDATE_MAJOR, 'release_level': RELEASE_LEVEL_FINAL, 'serial': 0, - } - + } + new_version = self.document.new_version(file=File(file_object, name='mayan_11_1.pdf.gpg'), **new_version_data) file_object.close() self.failUnlessEqual(self.document.latest_version.get_formated_version(), '2.0') self.failUnlessEqual(self.document.has_detached_signature(), False) - + self.failUnlessEqual(self.document.verify_signature().status, SIGNATURE_STATE_VALID) new_version_data = { @@ -65,23 +64,22 @@ class DocumentTestCase(unittest.TestCase): 'version_update': VERSION_UPDATE_MAJOR, 'release_level': RELEASE_LEVEL_FINAL, 'serial': 0, - } + } file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf')) new_version = self.document.new_version(file=File(file_object), **new_version_data) file_object.close() self.failUnlessEqual(self.document.latest_version.get_formated_version(), '3.0') - + #GPGVerificationError self.failUnlessEqual(self.document.verify_signature(), None) - + file_object = open(os.path.join(settings.PROJECT_ROOT, 'contrib', 'mayan_11_1.pdf.sig'), 'rb') new_version = self.document.add_detached_signature(File(file_object)) file_object.close() - + self.failUnlessEqual(self.document.has_detached_signature(), True) - self.failUnlessEqual(self.document.verify_signature().status, SIGNATURE_STATE_VALID) - - + self.failUnlessEqual(self.document.verify_signature().status, SIGNATURE_STATE_VALID) + def tearDown(self): self.document.delete() diff --git a/apps/documents/urls.py b/apps/documents/urls.py index 046d274dd8..0303438fdd 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -33,7 +33,7 @@ urlpatterns = patterns('documents.views', url(r'^(?P\d+)/create/siblings/$', 'document_create_siblings', (), 'document_create_siblings'), url(r'^(?P\d+)/find_duplicates/$', 'document_find_duplicates', (), 'document_find_duplicates'), url(r'^(?P\d+)/clear_transformations/$', 'document_clear_transformations', (), 'document_clear_transformations'), - + url(r'^(?P\d+)/version/all/$', 'document_version_list', (), 'document_version_list'), url(r'^document/version/(?P\d+)/download/$', 'document_download', (), 'document_version_download'), url(r'^document/version/(?P\d+)/revert/$', 'document_version_revert', (), 'document_version_revert'), diff --git a/apps/documents/views.py b/apps/documents/views.py index 2ccecd62bf..c33554edc1 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -48,10 +48,10 @@ from .literals import (HISTORY_DOCUMENT_CREATED, HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED) from .forms import (DocumentTypeSelectForm, DocumentForm_edit, DocumentPropertiesForm, - DocumentPreviewForm, DocumentPageForm, - DocumentPageTransformationForm, DocumentContentForm, - DocumentPageForm_edit, DocumentPageForm_text, PrintForm, - DocumentTypeForm, DocumentTypeFilenameForm, + DocumentPreviewForm, DocumentPageForm, + DocumentPageTransformationForm, DocumentContentForm, + DocumentPageForm_edit, DocumentPageForm_text, PrintForm, + DocumentTypeForm, DocumentTypeFilenameForm, DocumentTypeFilenameForm_create) from .wizards import DocumentCreateWizard from .models import (Document, DocumentType, DocumentPage, @@ -68,12 +68,12 @@ def document_list(request, object_list=None, title=None, extra_context=None): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: # If user doesn't have global permission, get a list of document - # for which he/she does hace access use it to filter the + # for which he/she does hace access use it to filter the # provided object_list final_object_list = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_VIEW, request.user, pre_object_list) else: final_object_list = pre_object_list - + context = { 'object_list': final_object_list, 'title': title if title else _(u'documents'), @@ -190,7 +190,7 @@ def document_delete(request, document_id=None, document_id_list=None): documents = [get_object_or_404(Document, pk=document_id)] post_action_redirect = reverse('document_list') elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] else: messages.error(request, _(u'Must provide at least one document.')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) @@ -296,12 +296,12 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) page = int(request.GET.get('page', DEFAULT_PAGE_NUMBER)) zoom = int(request.GET.get('zoom', DEFAULT_ZOOM_LEVEL)) - + version = int(request.GET.get('version', document.latest_version.pk)) if zoom < ZOOM_MIN_LEVEL: @@ -317,12 +317,12 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F else: # TODO: fix hardcoded MIMETYPE return sendfile.sendfile(request, document.get_image(size=size, page=page, zoom=zoom, rotation=rotation, version=version), mimetype=DEFAULT_FILE_FORMAT_MIMETYPE) - + def document_download(request, document_id=None, document_id_list=None, document_version_pk=None): document_version = None documents = [] - + if document_id: documents = [get_object_or_404(Document, pk=document_id)] post_action_redirect = reverse('document_list') @@ -338,7 +338,7 @@ def document_download(request, document_id=None, document_id_list=None, document if len(documents) == 1: document_version = documents[0].latest_version - + if document_version: try: # Test permissions and trigger exception @@ -363,9 +363,9 @@ def document_download(request, document_id=None, document_id_list=None, document descriptor = document.open() compressed_file.add_file(descriptor, arcname=document.filename) descriptor.close() - + compressed_file.close() - + return serve_file( request, compressed_file.as_file('document_bundle.zip'), @@ -386,14 +386,14 @@ def document_multiple_download(request): request, document_id_list=request.GET.get('id_list', []) ) + def document_page_transformation_list(request, document_page_id): document_page = get_object_or_404(DocumentPage, pk=document_page_id) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page.document) - + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page.document) return object_list( request, @@ -418,11 +418,11 @@ def document_page_transformation_list(request, document_page_id): def document_page_transformation_create(request, document_page_id): document_page = get_object_or_404(DocumentPage, pk=document_page_id) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page.document) if request.method == 'POST': form = DocumentPageTransformationForm(request.POST, initial={'document_page': document_page}) @@ -450,7 +450,7 @@ def document_page_transformation_edit(request, document_page_transformation_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page_transformation.document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page_transformation.document_page.document) if request.method == 'POST': form = DocumentPageTransformationForm(request.POST, instance=document_page_transformation) @@ -482,7 +482,7 @@ def document_page_transformation_delete(request, document_page_transformation_id try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TRANSFORM]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page_transformation.document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_TRANSFORM, request.user, document_page_transformation.document_page.document) redirect_view = reverse('document_page_transformation_list', args=[document_page_transformation.document_page_id]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_view))) @@ -516,7 +516,7 @@ def document_find_duplicates(request, document_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) extra_context = { 'title': _(u'duplicates of: %s') % document, @@ -565,8 +565,8 @@ def document_find_all_duplicates(request): def document_update_page_count(request): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) - + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) + office_converter = OfficeConverter() qs = DocumentVersion.objects.exclude(filename__iendswith='dxf').filter(mimetype__in=office_converter.mimetypes()) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) @@ -580,7 +580,7 @@ def document_update_page_count(request): processed += 1 if old_page_count != document_version.pages.count(): updated += 1 - + messages.success(request, _(u'Page count update complete. Documents processed: %(total)d, documents with changed page count: %(change)d') % { 'total': processed, 'change': updated @@ -673,12 +673,12 @@ def document_missing_list(request): def document_page_view(request, document_page_id): - document_page = get_object_or_404(DocumentPage, pk=document_page_id) + document_page = get_object_or_404(DocumentPage, pk=document_page_id) try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) zoom = int(request.GET.get('zoom', DEFAULT_ZOOM_LEVEL)) rotation = int(request.GET.get('rotation', DEFAULT_ROTATION)) @@ -717,7 +717,7 @@ def document_page_text(request, document_page_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) document_page_form = DocumentPageForm_text(instance=document_page) @@ -733,11 +733,11 @@ def document_page_text(request, document_page_id): def document_page_edit(request, document_page_id): document_page = get_object_or_404(DocumentPage, pk=document_page_id) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_EDIT]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_EDIT, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_EDIT, request.user, document_page.document) if request.method == 'POST': form = DocumentPageForm_edit(request.POST, instance=document_page) @@ -766,8 +766,8 @@ def document_page_navigation_next(request, document_page_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) - + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) if document_page.page_number >= document_page.siblings.count(): @@ -784,7 +784,7 @@ def document_page_navigation_previous(request, document_page_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) @@ -803,7 +803,7 @@ def document_page_navigation_first(request, document_page_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) @@ -812,12 +812,12 @@ def document_page_navigation_first(request, document_page_id): def document_page_navigation_last(request, document_page_id): document_page = get_object_or_404(DocumentPage, pk=document_page_id) - document_page = get_object_or_404(document_page.siblings, page_number=document_page.siblings.count()) + document_page = get_object_or_404(document_page.siblings, page_number=document_page.siblings.count()) try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) @@ -841,7 +841,7 @@ def transform_page(request, document_page_id, zoom_function=None, rotation_funct try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document_page.document) view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) @@ -900,11 +900,11 @@ def document_page_rotate_left(request, document_page_id): def document_print(request, document_id): document = get_object_or_404(Document, pk=document_id) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) RecentDocument.objects.add_document_for_user(request.user, document) @@ -964,7 +964,7 @@ def document_hard_copy(request, document_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) RecentDocument.objects.add_document_for_user(request.user, document) @@ -1056,7 +1056,7 @@ def document_type_edit(request, document_type_id): #'object': document_type, 'object_name': _(u'document type'), 'navigation_object_name': 'document_type', - 'document_type': document_type, + 'document_type': document_type, 'next': next }, context_instance=RequestContext(request)) @@ -1253,8 +1253,8 @@ def document_type_filename_create(request, document_type_id): 'document_type': document_type, }, context_instance=RequestContext(request)) - - + + def document_clear_image_cache(request): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_TOOLS]) @@ -1266,23 +1266,23 @@ def document_clear_image_cache(request): messages.success(request, _(u'Document image cache cleared successfully')) except Exception, msg: messages.error(request, _(u'Error clearing document image cache; %s') % msg) - + return HttpResponseRedirect(previous) return render_to_response('generic_confirm.html', { 'previous': previous, 'title': _(u'Are you sure you wish to clear the document image cache?'), 'form_icon': u'camera_delete.png', - }, context_instance=RequestContext(request)) + }, context_instance=RequestContext(request)) def document_version_list(request, document_pk): document = get_object_or_404(Document, pk=document_pk) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VIEW, request.user, document) RecentDocument.objects.add_document_for_user(request.user, document) @@ -1330,7 +1330,7 @@ def document_version_revert(request, document_version_pk): try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VERSION_REVERT]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERSION_REVERT, request.user, document_version.document) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_VERSION_REVERT, request.user, document_version.document) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) @@ -1340,7 +1340,7 @@ def document_version_revert(request, document_version_pk): messages.success(request, _(u'Document version reverted successfully')) except Exception, msg: messages.error(request, _(u'Error reverting document version; %s') % msg) - + return HttpResponseRedirect(previous) return render_to_response('generic_confirm.html', { @@ -1349,4 +1349,4 @@ def document_version_revert(request, document_version_pk): 'title': _(u'Are you sure you wish to revert to this version?'), 'message': _(u'All later version after this one will be deleted too.'), 'form_icon': u'page_refresh.png', - }, context_instance=RequestContext(request)) + }, context_instance=RequestContext(request)) diff --git a/apps/documents/widgets.py b/apps/documents/widgets.py index 0bd9ce473e..bdc963ed94 100644 --- a/apps/documents/widgets.py +++ b/apps/documents/widgets.py @@ -6,12 +6,9 @@ from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse from django.utils.http import urlencode -from converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, \ - DEFAULT_PAGE_NUMBER -from converter.exceptions import UnknownFileFormat, UnkownConvertError +from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, + DEFAULT_PAGE_NUMBER) from mimetype.api import get_error_icon_url - -from .conf.settings import DISPLAY_SIZE def document_thumbnail(document): @@ -24,7 +21,7 @@ def document_link(document): def document_html_widget(document, view='document_thumbnail', click_view=None, page=DEFAULT_PAGE_NUMBER, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION, gallery_name=None, fancybox_class='fancybox', version=None): result = [] - + alt_text = _(u'document page image') if not version: @@ -41,13 +38,13 @@ def document_html_widget(document, view='document_thumbnail', click_view=None, p gallery_template = u'rel="%s"' % gallery_name else: gallery_template = u'' - + query_string = urlencode(query_dict) preview_view = u'%s?%s' % (reverse(view, args=[document.pk]), query_string) - + plain_template = [] plain_template.append(u'%s' % (preview_view, alt_text)) - + result.append(u'
    ' % (document.pk, page if page else 1)) if click_view: @@ -55,7 +52,7 @@ def document_html_widget(document, view='document_thumbnail', click_view=None, p result.append(u'%s' % (preview_view, settings.STATIC_URL, alt_text)) result.append(u'' % (preview_view, alt_text)) - if click_view: + if click_view: result.append(u'') result.append(u'
    ') diff --git a/apps/linking/views.py b/apps/linking/views.py index 58a1c8451c..0e8a89ccec 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -9,7 +9,7 @@ from django.shortcuts import get_object_or_404, render_to_response from django.core.urlresolvers import reverse from django.template import RequestContext -from common.utils import generate_choices_w_labels, encapsulate +from common.utils import encapsulate from common.widgets import two_state_template from documents.models import Document from documents.views import document_list diff --git a/apps/lock_manager/managers.py b/apps/lock_manager/managers.py index f5613110f4..603a36c575 100644 --- a/apps/lock_manager/managers.py +++ b/apps/lock_manager/managers.py @@ -3,7 +3,6 @@ from __future__ import absolute_import import logging import datetime -from django.db.utils import DatabaseError from django.db.utils import IntegrityError from django.db import transaction from django.db import models diff --git a/apps/lock_manager/models.py b/apps/lock_manager/models.py index 25188380c7..a70af8230c 100644 --- a/apps/lock_manager/models.py +++ b/apps/lock_manager/models.py @@ -21,7 +21,7 @@ class Lock(models.Model): def save(self, *args, **kwargs): self.creation_datetime = datetime.datetime.now() - if not self.timeout and not kwarget.get('timeout'): + if not self.timeout and not kwargs.get('timeout'): self.timeout = DEFAULT_LOCK_TIMEOUT super(Lock, self).save(*args, **kwargs) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 8939370cb9..a0ccc9f32e 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): """ diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index 78c6923e43..f587fc6ebb 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -8,13 +8,11 @@ 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 -from django.template import (TemplateSyntaxError, Library, - VariableDoesNotExist, Node, Variable) - +from django.template import RequestContext, Variable + from permissions.models import Permission -from .templatetags.navigation_tags import resolve_links, _get_object_navigation_links +from .templatetags.navigation_tags import resolve_links from .utils import resolve_to_name @@ -27,7 +25,8 @@ def button_navigation_widget(request, link): return u'' else: return render_widget(request, link) - + + def render_widget(request, link): context = RequestContext(request) @@ -37,7 +36,7 @@ def render_widget(request, link): 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] diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 62027a4734..707b09ef67 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -2,15 +2,11 @@ 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.models import Permission, PermissionNamespace +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.permissions import (PERMISSION_DOCUMENT_CREATE, - PERMISSION_DOCUMENT_NEW_VERSION) -from acls.api import class_permissions +from documents.permissions import PERMISSION_DOCUMENT_NEW_VERSION from .staging import StagingFile from .models import (WebForm, StagingFolder, SourceTransformation, diff --git a/apps/sources/forms.py b/apps/sources/forms.py index 259f900062..714343530b 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -39,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): @@ -63,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/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/models.py b/apps/sources/models.py index 8bf86d7a0c..52e828a4fe 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -9,7 +9,7 @@ from django.contrib.contenttypes import generic from django.core.exceptions import ValidationError 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 @@ -33,7 +33,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)) @@ -44,10 +44,10 @@ 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) @@ -66,15 +66,15 @@ class BaseModel(models.Model): self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user) else: self.upload_single_file(file_object, filename, use_file_name, document_type, metadata_dict_list, user, document, new_version_data) - + file_object.close() - + 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): 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) @@ -93,7 +93,7 @@ class BaseModel(models.Model): if not new_version_data: new_version_data = {} - + new_version = document.new_version(file=file_object, **new_version_data) if filename: new_version.filename = filename @@ -103,7 +103,7 @@ class BaseModel(models.Model): new_version.apply_default_transformations(transformations) #TODO: new HISTORY for version updates - + class Meta: ordering = ('title',) abstract = True @@ -120,12 +120,12 @@ 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_height = models.IntegerField(blank=True, null=True, verbose_name=_(u'preview height'), help_text=_(u'Height value to be passed to the converter backend.')) @@ -173,16 +173,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()) @@ -191,11 +191,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: @@ -203,11 +203,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.') 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 1f98826d2c..4ab34935a4 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -26,7 +26,7 @@ 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.staging import create_staging_file_class from sources.forms import (StagingDocumentForm, WebFormForm, WatchFolderSetupForm) from sources.forms import WebFormSetupForm, StagingFolderSetupForm @@ -47,7 +47,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, @@ -55,19 +55,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, @@ -75,6 +75,7 @@ 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): subtemplates_list = [] From f9a3c4611b9cf83b9a79cb612a8b47aeceff1896 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 13:53:02 -0400 Subject: [PATCH 258/484] PEP8 cleanups, remove OCR_CACHE_URI --- apps/ocr/__init__.py | 9 ++++----- apps/ocr/conf/settings.py | 1 - apps/ocr/exceptions.py | 12 ++++++------ apps/ocr/parsers/__init__.py | 9 ++++----- apps/ocr/tasks.py | 6 ++---- docs/changelog.rst | 1 + docs/settings.rst | 8 -------- 7 files changed, 17 insertions(+), 29 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 78f3f297c2..c2f2358039 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -1,15 +1,14 @@ from __future__ import absolute_import import logging - + from django.db import transaction from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.db.models.signals import post_save from django.dispatch import receiver -from navigation.api import register_links, register_top_menu, register_multi_item_links -from permissions.models import Permission, PermissionNamespace +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 @@ -18,7 +17,7 @@ from acls.api import class_permissions from scheduler.api import register_interval_job from .conf.settings import (AUTOMATIC_OCR, QUEUE_PROCESSING_INTERVAL) -from .models import DocumentQueue, QueueTransformation, QueueDocument +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, @@ -85,7 +84,7 @@ def document_post_save(sender, instance, **kwargs): # 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() 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 0b6f4a129a..32ec4c4c07 100644 --- a/apps/ocr/exceptions.py +++ b/apps/ocr/exceptions.py @@ -1,21 +1,21 @@ class AlreadyQueued(Exception): - ''' + """ Raised when a trying to queue document already in the queue - ''' + """ pass class TesseractError(Exception): - ''' + """ Raised by tesseract - ''' + """ pass class UnpaperError(Exception): - ''' + """ Raised by unpaper - ''' + """ pass 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/tasks.py b/apps/ocr/tasks.py index 14c0ce5152..f042c51460 100644 --- a/apps/ocr/tasks.py +++ b/apps/ocr/tasks.py @@ -2,8 +2,6 @@ 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 @@ -17,7 +15,7 @@ from .literals import (QUEUEDOCUMENT_STATE_PENDING, QUEUEDOCUMENT_STATE_ERROR) from .models import QueueDocument, DocumentQueue from .conf.settings import (NODE_CONCURRENT_EXECUTION, REPLICATION_DELAY, - CACHE_URI, QUEUE_PROCESSING_INTERVAL) + QUEUE_PROCESSING_INTERVAL) LOCK_EXPIRE = 60 * 10 # Lock expires in 10 minutes # TODO: Tie LOCK_EXPIRATION with hard task timeout @@ -100,7 +98,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/docs/changelog.rst b/docs/changelog.rst index 572225bb14..4a37902165 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,6 @@ Version 0.12 ------------ +* Removal of the OCR_CACHE_URI configuration option * Upgrade commands: * ./manage.py syncdb diff --git a/docs/settings.rst b/docs/settings.rst index 8d9b0237be..d27a0bb0ac 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -270,14 +270,6 @@ OCR 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 From ad5973446011cacf709e53b90107aa32e53fbe75 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 14:36:42 -0400 Subject: [PATCH 259/484] Fix document signatures app reverse migration --- .../migrations/0002_move_signatures_to_new_app.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py index 06cc84f703..e48ba547b2 100644 --- a/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py +++ b/apps/document_signatures/migrations/0002_move_signatures_to_new_app.py @@ -23,14 +23,10 @@ class Migration(DataMigration): def backwards(self, orm): for document_signature in orm.DocumentVersionSignature.objects.all(): - try: - document_version = orm['documents.DocumentVersion'].objects.get(document_version=document_version) - except orm['documents.DocumentVersion'].DoesNotExists: - pass - else: - document_version.signature_state=document_signature.signature_state - document_version.signature_file=document_signature.signature_file - document_version.save() + document_version = document_signature.document_version + document_version.signature_state=document_signature.signature_state + document_version.signature_file=document_signature.signature_file + document_version.save() models = { From 970cb74d35ba09b0bc44069c858a7740302cdeca Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 14:37:15 -0400 Subject: [PATCH 260/484] PEP8 cleanups --- apps/acls/__init__.py | 2 +- apps/acls/admin.py | 4 +- apps/acls/classes.py | 36 ++++++------ apps/acls/managers.py | 48 ++++++++-------- apps/acls/models.py | 4 +- apps/acls/templatetags/acl_tags.py | 4 +- apps/acls/urls.py | 4 +- apps/acls/views.py | 88 +++++++++++++++--------------- apps/common/tests.py | 1 - apps/converter/api.py | 17 +++--- apps/converter/exceptions.py | 16 +++--- apps/converter/literals.py | 8 +-- apps/converter/office_converter.py | 16 +++--- apps/converter/tests.py | 1 - apps/django_gpg/api.py | 28 +++++----- apps/django_gpg/models.py | 1 - apps/django_gpg/views.py | 36 ++++++------ apps/document_indexing/tests.py | 1 - apps/document_signatures/models.py | 4 +- apps/documents/admin.py | 4 +- apps/folders/forms.py | 2 +- apps/folders/models.py | 4 +- apps/folders/permissions.py | 2 +- apps/folders/tests.py | 1 - apps/folders/urls.py | 2 +- apps/folders/views.py | 15 +++-- apps/linking/__init__.py | 2 +- apps/linking/admin.py | 2 +- apps/linking/forms.py | 10 ++-- apps/linking/managers.py | 2 +- apps/linking/models.py | 2 +- apps/linking/permissions.py | 2 +- apps/linking/urls.py | 4 +- apps/linking/views.py | 70 ++++++++++++------------ apps/main/__init__.py | 4 +- apps/main/tests.py | 1 - apps/metadata/__init__.py | 2 +- apps/metadata/admin.py | 2 +- apps/metadata/api.py | 28 +++++----- apps/metadata/forms.py | 2 +- apps/metadata/models.py | 22 ++++---- apps/metadata/permissions.py | 2 +- apps/metadata/tests.py | 1 - apps/metadata/views.py | 36 ++++++------ apps/ocr/__init__.py | 2 +- apps/ocr/tasks.py | 2 +- apps/ocr/tests.py | 1 - apps/ocr/views.py | 6 +- apps/permissions/api.py | 1 - apps/permissions/models.py | 44 +++++++-------- apps/permissions/runtime.py | 1 - apps/permissions/tests.py | 1 - apps/permissions/urls.py | 2 +- apps/permissions/views.py | 42 +++++++------- apps/smart_settings/__init__.py | 1 + apps/smart_settings/tests.py | 1 - apps/sources/tests.py | 1 - apps/sources/views.py | 56 +++++++++---------- apps/tags/forms.py | 6 +- apps/tags/urls.py | 2 +- apps/tags/views.py | 22 ++++---- apps/tags/widgets.py | 10 ++-- 62 files changed, 365 insertions(+), 379 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 64becbdef5..33493dd232 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -7,7 +7,7 @@ from project_setup.api import register_setup from .classes import (AccessHolder, AccessObjectClass, ClassAccessHolder, AccessObject) -from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, +from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) diff --git a/apps/acls/admin.py b/apps/acls/admin.py index 6608e6799b..61c12d9498 100644 --- a/apps/acls/admin.py +++ b/apps/acls/admin.py @@ -1,8 +1,6 @@ from __future__ import absolute_import from django.contrib import admin -from django.contrib.contenttypes import generic -from django.contrib.contenttypes.models import ContentType from .models import AccessEntry @@ -21,5 +19,5 @@ class AccessEntryAdmin(admin.ModelAdmin): list_display = ('pk', 'holder_object', 'permission', 'content_object') list_display_links = ('pk',) model = AccessEntry - + admin.site.register(AccessEntry, AccessEntryAdmin) diff --git a/apps/acls/classes.py b/apps/acls/classes.py index 91141e46b6..f2b7c36ef2 100644 --- a/apps/acls/classes.py +++ b/apps/acls/classes.py @@ -12,13 +12,13 @@ from django.core.exceptions import ObjectDoesNotExist from common.models import AnonymousUserSingleton logger = logging.getLogger(__name__) - + _cache = {} class EncapsulatedObject(object): source_object_name = u'source_object' - + @classmethod def object_key(cls, app_label=None, model=None, pk=None): if pk: @@ -36,7 +36,7 @@ class EncapsulatedObject(object): @classmethod def set_source_object_name(cls, new_name): cls.source_object_name = new_name - + #@classmethod #def encapsulate_list(cls, source_object=None, app_label=None, model=None, pk=None): @@ -44,7 +44,7 @@ class EncapsulatedObject(object): def encapsulate(cls, source_object): source_object = AnonymousUserSingleton.objects.passthru_check(source_object) content_type = ContentType.objects.get_for_model(source_object) - + if hasattr(source_object, 'pk'): # Object object_key = cls.object_key(content_type.app_label, content_type.model, source_object.pk) @@ -67,9 +67,9 @@ class EncapsulatedObject(object): elif len(elements) == 2: app_label, model = elements[0], elements[1] pk = None - + object_key = cls.object_key(*elements) - + try: return _cache[object_key] except KeyError: @@ -90,9 +90,9 @@ class EncapsulatedObject(object): raise ObjectDoesNotExist("%s matching query does not exist." % source_object_model_class._meta.object_name) else: source_object = source_object_model_class - + return cls.encapsulate(source_object) - + def __init__(self, source_object): self.content_type = ContentType.objects.get_for_model(source_object) self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.name) @@ -101,15 +101,15 @@ class EncapsulatedObject(object): # Class self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.model) else: - # Object + # Object self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.model, source_object.pk) - + setattr(self, self.__class__.source_object_name, source_object) def __unicode__(self): if isinstance(self.source_object, ModelBase): return capfirst(unicode(self.source_object._meta.verbose_name_plural)) - + elif self.ct_fullname == 'auth.user': return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name()) else: @@ -117,19 +117,19 @@ class EncapsulatedObject(object): def __repr__(self): return self.__unicode__() - + @property def source_object(self): return getattr(self, self.__class__.source_object_name, None) - - + + class AccessHolder(EncapsulatedObject): source_object_name = u'holder_object' - - + + class AccessObject(EncapsulatedObject): - source_object_name = u'obj' - + source_object_name = u'obj' + class AccessObjectClass(EncapsulatedObject): source_object_name = u'cls' diff --git a/apps/acls/managers.py b/apps/acls/managers.py index a2cb9ff17f..dd69b7d061 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -8,8 +8,10 @@ from django.utils.translation import ugettext from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse from common.models import AnonymousUserSingleton +from permissions.models import Permission from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder @@ -22,14 +24,14 @@ class AccessEntryManager(models.Manager): return obj.source_object else: return obj - + def grant(self, permission, actor, obj): ''' Grant a permission (what), (to) an actor, (on) a specific object ''' obj = self.source_object(obj) actor = self.source_object(actor) - + access_entry, created = self.model.objects.get_or_create( permission=permission, holder_type=ContentType.objects.get_for_model(actor), @@ -42,7 +44,7 @@ class AccessEntryManager(models.Manager): def revoke(self, permission, actor, obj): ''' Revoke a permission (what), (from) an actor, (on) a specific object - ''' + ''' obj = self.source_object(obj) actor = self.source_object(actor) @@ -57,12 +59,12 @@ class AccessEntryManager(models.Manager): access_entry.delete() return True except self.model.DoesNotExist: - return False + return False def has_access(self, permission, actor, obj): obj = self.source_object(obj) actor = self.source_object(actor) - + if isinstance(actor, User): if actor.is_superuser or actor.is_staff: return True @@ -80,7 +82,7 @@ class AccessEntryManager(models.Manager): return True except self.model.DoesNotExist: return False - + def check_access(self, permission, actor, obj): obj = self.source_object(obj) actor = self.source_object(actor) @@ -89,7 +91,7 @@ class AccessEntryManager(models.Manager): return True else: raise PermissionDenied(ugettext(u'Insufficient access.')) - + def check_accesses(self, permission_list, actor, obj): obj = self.source_object(obj) actor = self.source_object(actor) @@ -101,7 +103,7 @@ class AccessEntryManager(models.Manager): def get_allowed_class_objects(self, permission, actor, cls, related=None): logger.debug('related: %s' % related) - + actor = AnonymousUserSingleton.objects.passthru_check(actor) actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) @@ -122,22 +124,22 @@ class AccessEntryManager(models.Manager): def get_new_holder_url(self, obj): content_type = ContentType.objects.get_for_model(obj) return reverse('acl_new_holder_for', args=[content_type.app_label, content_type.model, obj.pk]) - + def get_holders_for(self, obj): content_type = ContentType.objects.get_for_model(obj) holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): entry = AccessHolder.encapsulate(access_entry.holder_object) - + if entry not in holder_list: holder_list.append(entry) - + return holder_list def get_holder_permissions_for(self, obj, actor): logger.debug('obj: %s' % obj) logger.debug('actor: %s' % actor) - + if isinstance(actor, User): if actor.is_superuser or actor.is_staff: return Permission.objects.all() @@ -149,11 +151,11 @@ class AccessEntryManager(models.Manager): def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False, related=None): logger.debug('exception_on_empty: %s' % exception_on_empty) logger.debug('object_list: %s' % object_list) - + if isinstance(actor, User): if actor.is_superuser or actor.is_staff: return object_list - + try: if object_list.count() == 0: return object_list @@ -161,15 +163,15 @@ class AccessEntryManager(models.Manager): # object_list is not a queryset if len(object_list) == 0: return object_list - + try: # Try to process as a QuerySet qs = object_list.filter(pk__in=[obj.pk for obj in self.get_allowed_class_objects(permission, actor, object_list[0].__class__, related)]) logger.debug('qs: %s' % qs) - + if qs.count() == 0 and exception_on_empty == True: raise PermissionDenied - + return qs except AttributeError: # Fallback to a filtered list @@ -190,17 +192,17 @@ class DefaultAccessEntryManager(models.Manager): holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type): entry = ClassAccessHolder.encapsulate(access_entry.holder_object) - + if entry not in holder_list: holder_list.append(entry) - + return holder_list def has_access(self, permission, actor, cls): if isinstance(actor, User): if actor.is_superuser or actor.is_staff: return True - + try: access_entry = self.model.objects.get( permission=permission.get_stored_permission(), @@ -227,7 +229,7 @@ class DefaultAccessEntryManager(models.Manager): def revoke(self, permission, actor, cls): ''' Revoke a permission (what), (from) an actor, (on) a specific class - ''' + ''' try: access_entry = self.model.objects.get( permission=permission, @@ -238,13 +240,13 @@ class DefaultAccessEntryManager(models.Manager): access_entry.delete() return True except self.model.DoesNotExist: - return False + return False def get_holder_permissions_for(self, cls, actor): if isinstance(actor, User): if actor.is_superuser or actor.is_staff: return Permission.objects.all() - + actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=actor_type, holder_id=actor.pk)] diff --git a/apps/acls/models.py b/apps/acls/models.py index 55df6a253e..a255348760 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -18,7 +18,7 @@ from .api import get_classes logger = logging.getLogger(__name__) - + class AccessEntry(models.Model): """ Model that hold the permission, object, actor relationship @@ -64,7 +64,7 @@ class DefaultAccessEntry(models.Model): @classmethod def get_classes(cls): return [AccessObjectClass.encapsulate(cls) for cls in get_classes()] - + permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) holder_type = models.ForeignKey( diff --git a/apps/acls/templatetags/acl_tags.py b/apps/acls/templatetags/acl_tags.py index 20e96dbb2f..68ce30263d 100644 --- a/apps/acls/templatetags/acl_tags.py +++ b/apps/acls/templatetags/acl_tags.py @@ -3,7 +3,7 @@ import logging from django.core.exceptions import PermissionDenied from django.template import (TemplateSyntaxError, Library, Node, Variable, VariableDoesNotExist) - + from acls.models import AccessEntry @@ -33,7 +33,7 @@ class CheckAccessNode(Node): context[u'access'] = False logger.debug('no obj, access False') return u'' - + if not permission_list: # There is no permissions list to check against which means # this link is available for all diff --git a/apps/acls/urls.py b/apps/acls/urls.py index a544274b5b..ba9aa8be92 100644 --- a/apps/acls/urls.py +++ b/apps/acls/urls.py @@ -5,13 +5,13 @@ urlpatterns = patterns('acls.views', url(r'^list_for/(?P[-\w]+)/(?P[-\w]+)/(?P\d+)/$', 'acl_list', (), 'acl_list'), url(r'^details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acl_detail', (), 'acl_detail'), url(r'^holder/new/(?P[.\w]+)/$', 'acl_holder_new', (), 'acl_holder_new'), - + url(r'^multiple/grant/$', 'acl_grant', (), 'acl_multiple_grant'), url(r'^multiple/revoke/$', 'acl_revoke', (), 'acl_multiple_revoke'), url(r'^class/$', 'acl_setup_valid_classes', (), 'acl_setup_valid_classes'), url(r'^class/details/(?P[.\w]+)/holder/(?P[.\w]+)/$', 'acl_class_acl_detail', (), 'acl_class_acl_detail'), - url(r'^class/list_for/(?P[.\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), + url(r'^class/list_for/(?P[.\w]+)/$', 'acl_class_acl_list', (), 'acl_class_acl_list'), url(r'^class/holder/new/(?P[.\w]+)/$', 'acl_class_new_holder_for', (), 'acl_class_new_holder_for'), url(r'^class/multiple/grant/$', 'acl_class_multiple_grant', (), 'acl_class_multiple_grant'), diff --git a/apps/acls/views.py b/apps/acls/views.py index d0a71b79a7..694c4b1e68 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -22,7 +22,7 @@ from permissions.models import Permission, Role from common.utils import generate_choices_w_labels, encapsulate from common.widgets import two_state_template -from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, +from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) from .models import AccessEntry, DefaultAccessEntry from .classes import (AccessHolder, AccessObject, AccessObjectClass, @@ -36,8 +36,8 @@ logger = logging.getLogger(__name__) def _permission_titles(permission_list): return u', '.join([unicode(permission) for permission in permission_list]) - - + + def acl_list_for(request, obj, extra_context=None): try: Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) @@ -60,14 +60,14 @@ def acl_list_for(request, obj, extra_context=None): 'navigation_object_list': [ {'object': 'object'}, {'object': 'access_object'} - ], + ], } if extra_context: context.update(extra_context) return render_to_response('generic_list.html', context, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) def acl_list(request, app_label, model_name, object_id): @@ -90,10 +90,10 @@ def acl_detail_for(request, actor, obj): try: Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) except PermissionDenied: - AccessEntry.objects.check_accesses([ACLS_VIEW_ACL], actor, obj) + AccessEntry.objects.check_accesses([ACLS_VIEW_ACL], actor, obj) permission_list = get_class_permissions_for(obj) - + #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { @@ -139,7 +139,7 @@ def acl_detail_for(request, actor, obj): context, context_instance=RequestContext(request) ) - + def acl_grant(request): items_property_list = loads(request.GET.get('items_property_list', [])) @@ -152,13 +152,13 @@ def acl_grant(request): title_suffix = [] navigation_object = None navigation_object_count = 0 - + for item_properties in items_property_list: try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: - raise Http404 - + raise Http404 + try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) @@ -184,13 +184,13 @@ def acl_grant(request): items[requester][access_object].append(permission) navigation_object = access_object navigation_object_count += 1 - + for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' to %s') % requester) - + if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to grant the permission %(title_suffix)s?') else: @@ -225,7 +225,7 @@ def acl_grant(request): context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } - + logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: @@ -251,21 +251,21 @@ def acl_revoke(request): try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: - raise Http404 + raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) except ObjectDoesNotExist: raise Http404 - + try: Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) except PermissionDenied: try: AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, access_object) except PermissionDenied: - raise + raise else: items.setdefault(requester, {}) items[requester].setdefault(access_object, []) @@ -277,14 +277,14 @@ def acl_revoke(request): items[requester].setdefault(access_object, []) items[requester][access_object].append(permission) navigation_object = access_object - navigation_object_count += 1 - + navigation_object_count += 1 + for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' from %s') % requester) - + if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to revoke the permission %(title_suffix)s?') else: @@ -319,7 +319,7 @@ def acl_revoke(request): context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } - + logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: @@ -349,7 +349,7 @@ def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None) reverse('acl_detail', args=[access_object.gid, access_holder.gid]), urlencode(query_string) ) - ) + ) except ObjectDoesNotExist: raise Http404 else: @@ -365,12 +365,12 @@ def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None) 'navigation_object_list': [ {'object': 'object'}, {'object': 'access_object'}, - ], + ], } - + if extra_context: context.update(extra_context) - + return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) @@ -399,12 +399,12 @@ def acl_setup_valid_classes(request): } return render_to_response('generic_list.html', context, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) def acl_class_acl_list(request, access_object_class_gid): Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL]) - + access_object_class = AccessObjectClass.get(gid=access_object_class_gid) context = { 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), @@ -419,7 +419,7 @@ def acl_class_acl_list(request, access_object_class_gid): } return render_to_response('generic_list.html', context, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) def acl_class_acl_detail(request, access_object_class_gid, holder_object_gid): @@ -429,7 +429,7 @@ def acl_class_acl_detail(request, access_object_class_gid, holder_object_gid): access_object_class = AccessObjectClass.get(gid=access_object_class_gid) except ObjectDoesNotExist: raise Http404 - + #permission_list = list(access_object_class.get_class_permissions()) permission_list = get_class_permissions_for(access_object_class.content_type.model_class()) #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) @@ -464,9 +464,9 @@ def acl_class_acl_detail(request, access_object_class_gid, holder_object_gid): 'permission_pk': lambda x: x.pk, 'holder_gid': lambda x: actor.gid, 'access_object_class_gid': lambda x: access_object_class.gid, - }, + }, }, context_instance=RequestContext(request)) - + def acl_class_new_holder_for(request, access_object_class_gid): Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) @@ -489,11 +489,11 @@ def acl_class_new_holder_for(request, access_object_class_gid): 'title': _(u'add new holder for class: %s') % unicode(access_object_class), 'object': access_object_class, 'submit_label': _(u'Select'), - 'submit_icon_famfam': 'tick' + 'submit_icon_famfam': 'tick' } - + return render_to_response('generic_form.html', context, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) def acl_class_multiple_grant(request): @@ -513,25 +513,25 @@ def acl_class_multiple_grant(request): try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: - raise Http404 + raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object_class = AccessObjectClass.get(gid=item_properties['access_object_class_gid']) except ObjectDoesNotExist: raise Http404 - + items.setdefault(requester, {}) items[requester].setdefault(access_object_class, []) items[requester][access_object_class].append(permission) navigation_object = access_object_class navigation_object_count += 1 - + for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' to %s') % requester) - + if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to grant the permission %(title_suffix)s?') else: @@ -566,7 +566,7 @@ def acl_class_multiple_grant(request): context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } - + logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: @@ -593,25 +593,25 @@ def acl_class_multiple_revoke(request): try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: - raise Http404 + raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object_class = AccessObjectClass.get(gid=item_properties['access_object_class_gid']) except ObjectDoesNotExist: raise Http404 - + items.setdefault(requester, {}) items[requester].setdefault(access_object_class, []) items[requester][access_object_class].append(permission) navigation_object = access_object_class navigation_object_count += 1 - + for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' from %s') % requester) - + if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to revoke the permission %(title_suffix)s?') else: @@ -646,7 +646,7 @@ def acl_class_multiple_revoke(request): context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } - + logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: diff --git a/apps/common/tests.py b/apps/common/tests.py index 2247054b35..3b31148896 100644 --- a/apps/common/tests.py +++ b/apps/common/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/converter/api.py b/apps/converter/api.py index 8d1239afd2..7e22354b2d 100644 --- a/apps/converter/api.py +++ b/apps/converter/api.py @@ -19,7 +19,7 @@ from .exceptions import OfficeConversionError HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() - + def cache_cleanup(input_filepath, *args, **kwargs): try: os.remove(create_image_cache_filename(input_filepath, *args, **kwargs)) @@ -42,13 +42,13 @@ def convert(input_filepath, output_filepath=None, cleanup_files=False, mimetype= rotation = kwargs.get('rotation', DEFAULT_ROTATION) page = kwargs.get('page', DEFAULT_PAGE_NUMBER) transformations = kwargs.get('transformations', []) - + if transformations is None: transformations = [] if output_filepath is None: output_filepath = create_image_cache_filename(input_filepath, *args, **kwargs) - + if os.path.exists(output_filepath): return output_filepath @@ -79,7 +79,7 @@ def convert(input_filepath, output_filepath=None, cleanup_files=False, mimetype= 'transformation': TRANSFORMATION_ZOOM, 'arguments': {'percent': zoom} } - ) + ) if rotation != 0 and rotation != 360: transformations.append( @@ -87,7 +87,7 @@ def convert(input_filepath, output_filepath=None, cleanup_files=False, mimetype= 'transformation': TRANSFORMATION_ROTATE, 'arguments': {'degrees': rotation} } - ) + ) try: backend.convert_file(input_filepath=input_filepath, output_filepath=output_filepath, transformations=transformations, page=page, file_format=file_format, mimetype=mimetype) @@ -107,7 +107,7 @@ def get_page_count(input_filepath): except OfficeConversionError: raise UnknownFileFormat('office converter exception') - + return backend.get_page_count(input_filepath) ''' @@ -127,8 +127,7 @@ def get_available_transformations_choices(): result.append([transformation, transformation_template]) return result - - + + def get_format_list(): return [(format, FILE_FORMATS.get(format, u'')) for format in backend.get_format_list()] - diff --git a/apps/converter/exceptions.py b/apps/converter/exceptions.py index 74b13a7c56..1423d38002 100644 --- a/apps/converter/exceptions.py +++ b/apps/converter/exceptions.py @@ -1,29 +1,29 @@ class ConvertError(Exception): - ''' + """ Base exception for all coverter app exceptions - ''' + """ pass class UnknownFileFormat(ConvertError): - ''' + """ Raised when the converter backend can't understand a file - ''' + """ pass class IdentifyError(ConvertError): - ''' + """ Raised by the graphcismagick and imagemagics identify program - ''' + """ pass class UnkownConvertError(ConvertError): - ''' + """ Raised when an error is found but there is no disernible way to identify the kind of error - ''' + """ pass diff --git a/apps/converter/literals.py b/apps/converter/literals.py index 14df18106d..aa66218874 100644 --- a/apps/converter/literals.py +++ b/apps/converter/literals.py @@ -53,7 +53,7 @@ FILE_FORMATS = { '8BIN': _(u'Photoshop resource format'), '8BIMTEXT': _(u'Photoshop resource text format'), '8BIMWTEXT': _(u'Photoshop resource wide text format'), - + 'A': _(u'Raw alpha samples'), 'AI': _(u'Adobe Illustrator CS2'), 'APP1': _(u'Raw application information'), @@ -62,7 +62,7 @@ FILE_FORMATS = { 'ARW': _(u'Sony Alpha DSLR Raw Image Format'), 'AVI': _(u'Microsoft Audio/Visual Interleaved'), 'AVS': _(u'AVS X image'), - + 'B': _(u'Raw blue samples'), 'BGR': _(u'Raw blue, green, and red samples'), 'BGRA': _(u'Raw blue, green, red and alpha samples'), @@ -95,7 +95,7 @@ FILE_FORMATS = { 'DJVU': _(u'Déjà vu'), 'DNG': _(u'Adobe Digital Negative'), 'DOT': _(u'Graphviz'), - 'DPX': _(u'SMPTE 268M-2003 (DPX 2.0)'), + 'DPX': _(u'SMPTE 268M-2003 (DPX 2.0)'), 'EPDF': _(u'Encapsulated Portable Document Format'), 'EPI': _(u'Adobe Encapsulated PostScript Interchange format'), @@ -110,7 +110,7 @@ FILE_FORMATS = { 'ERF': _(u'Epson RAW Format'), 'EXIF': _(u'Exif digital camera binary data'), 'EXR': _(u'High Dynamic-range (HDR)'), - + 'FAX': _(u'Group 3 FAX (Not TIFF Group3 FAX)'), 'FLI': _(u'Autodesk FLI animations file'), 'FLC': _(u'Autodesk FLC animations file'), diff --git a/apps/converter/office_converter.py b/apps/converter/office_converter.py index 8df298ceed..07c7a28f62 100644 --- a/apps/converter/office_converter.py +++ b/apps/converter/office_converter.py @@ -13,14 +13,14 @@ from .exceptions import (OfficeConversionError, OfficeBackendError, UnknownFileFormat) CACHED_FILE_SUFFIX = u'_office_converter' - + CONVERTER_OFFICE_FILE_MIMETYPES = [ u'application/msword', u'application/mswrite', u'application/mspowerpoint', u'application/msexcel', u'application/vnd.ms-excel', - u'application/vnd.ms-powerpoint', + u'application/vnd.ms-powerpoint', u'application/vnd.oasis.opendocument.presentation', u'application/vnd.oasis.opendocument.text', u'application/vnd.openxmlformats-officedocument.wordprocessingml.document', @@ -43,7 +43,7 @@ class OfficeConverter(object): self.exists = False self.mimetype = None self.encoding = None - + def mimetypes(self): return CONVERTER_OFFICE_FILE_MIMETYPES @@ -51,7 +51,7 @@ class OfficeConverter(object): self.exists = False self.mimetype = None self.encoding = None - + self.input_filepath = input_filepath # Make sure file is of a known office format @@ -71,13 +71,13 @@ class OfficeConverter(object): except OfficeBackendError, msg: # convert exception so that at least the mime type icon is displayed raise UnknownFileFormat(msg) - + def __unicode__(self): return getattr(self, 'output_filepath', None) - + def __str__(self): return str(self.__unicode__()) - + class OfficeConverterBackendUnoconv(object): def __init__(self): @@ -91,7 +91,7 @@ class OfficeConverterBackendUnoconv(object): ''' self.input_filepath = input_filepath self.output_filepath = output_filepath - + command = [] command.append(self.unoconv_path) diff --git a/apps/converter/tests.py b/apps/converter/tests.py index 2247054b35..3b31148896 100644 --- a/apps/converter/tests.py +++ b/apps/converter/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index f4aad2fa63..7e188f8d4c 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -157,8 +157,8 @@ class GPG(object): # If not, try open it. return open(file_input, 'rb') else: - return file_input - + return file_input + def __init__(self, binary_path=None, home=None, keyring=None, keyservers=None): kwargs = {} if binary_path: @@ -198,9 +198,9 @@ class GPG(object): ''' Verify the signature of a file. ''' - + input_descriptor = GPG.get_descriptor(file_input) - + if detached_signature: # Save the original data and invert the argument order # Signature first, file second @@ -212,10 +212,10 @@ class GPG(object): verify = self.gpg.verify_file(detached_signature, data_filename=filename) else: verify = self.gpg.verify_file(input_descriptor) - + if close_descriptor: input_descriptor.close() - + if verify: return verify #elif getattr(verify, 'status', None) == 'no public key': @@ -240,7 +240,7 @@ class GPG(object): overrided if it already exists), if no destination file name is provided the signature is returned. ''' - + kwargs = {} kwargs['clearsign'] = clearsign @@ -287,12 +287,12 @@ class GPG(object): result = self.gpg.decrypt_file(input_descriptor) if close_descriptor: input_descriptor.close() - + if not result.status: raise GPGDecryptionError('Unable to decrypt file') return result - + def create_key(self, *args, **kwargs): if kwargs.get('passphrase') == u'': kwargs.pop('passphrase') @@ -319,7 +319,7 @@ class GPG(object): return Key.get(self, import_result.fingerprints[0], secret=False) raise KeyFetchingError - + def query(self, term): results = {} for keyserver in self.keyservers: @@ -331,14 +331,14 @@ class GPG(object): results[key.keyid] = key except: pass - + return results.values() - + def import_key(self, key_data): import_result = self.gpg.import_keys(key_data) logger.debug('import_result: %s' % import_result) - + if import_result: return Key.get(self, import_result.fingerprints[0], secret=False) - raise KeyImportError + raise KeyImportError diff --git a/apps/django_gpg/models.py b/apps/django_gpg/models.py index 8b13789179..e69de29bb2 100644 --- a/apps/django_gpg/models.py +++ b/apps/django_gpg/models.py @@ -1 +0,0 @@ - diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index af3c52ef7c..e3dcd4981e 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -10,7 +10,7 @@ from django.contrib import messages from permissions.models import Permission from common.utils import (urlquote, encapsulate) - + from .api import Key, SIGNATURE_STATES from .runtime import gpg from .exceptions import (GPGVerificationError, KeyFetchingError, @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) def key_receive(request, key_id): Permission.objects.check_permissions(request.user, [PERMISSION_KEY_RECEIVE]) - + post_action_redirect = None 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', '/'))) @@ -48,13 +48,13 @@ def key_receive(request, key_id): 'next': next, 'previous': previous, 'submit_method': 'GET', - + }, context_instance=RequestContext(request)) - + def key_list(request, secret=True): Permission.objects.check_permissions(request.user, [PERMISSION_KEY_VIEW]) - + if secret: object_list = Key.get_all(gpg, secret=True) title = _(u'private keys') @@ -81,7 +81,7 @@ def key_list(request, secret=True): def key_delete(request, fingerprint, key_type): Permission.objects.check_permissions(request.user, [PERMISSION_KEY_DELETE]) - + secret = key_type == 'sec' key = Key.get(gpg, fingerprint, secret=secret) @@ -110,7 +110,7 @@ def key_delete(request, fingerprint, key_type): def key_query(request): Permission.objects.check_permissions(request.user, [PERMISSION_KEYSERVER_QUERY]) - + subtemplates_list = [] term = request.GET.get('term') @@ -124,8 +124,8 @@ def key_query(request): 'submit_method': 'GET', }, } - ) - + ) + if term: results = gpg.query(term) subtemplates_list.append( @@ -147,36 +147,36 @@ def key_query(request): { 'name': _(u'creation date'), 'attribute': 'creation_date', - }, + }, { 'name': _(u'disabled'), 'attribute': 'disabled', - }, + }, { 'name': _(u'expiration date'), 'attribute': 'expiration_date', - }, + }, { 'name': _(u'expired'), 'attribute': 'expired', - }, + }, { 'name': _(u'length'), 'attribute': 'key_length', - }, + }, { 'name': _(u'revoked'), 'attribute': 'revoked', - }, - + }, + { 'name': _(u'Identifies'), 'attribute': encapsulate(lambda x: u', '.join([identity.uid for identity in x.identities])), }, - ] + ] }, } - ) + ) return render_to_response('generic_form.html', { 'subtemplates_list': subtemplates_list, diff --git a/apps/document_indexing/tests.py b/apps/document_indexing/tests.py index 2247054b35..3b31148896 100644 --- a/apps/document_indexing/tests.py +++ b/apps/document_indexing/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 4b71af2f71..7ae215f675 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -14,9 +14,9 @@ logger = logging.getLogger(__name__) class DocumentVersionSignature(models.Model): - ''' + """ Model that describes a document version signature properties - ''' + """ document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'), editable=False) signature_file = models.FileField(blank=True, null=True, upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'signature file'), editable=False) has_embedded_signature = models.BooleanField(default=False, verbose_name=_(u'has embedded signature'), editable=False) diff --git a/apps/documents/admin.py b/apps/documents/admin.py index 40ac5d0a2b..91ee0ac22c 100644 --- a/apps/documents/admin.py +++ b/apps/documents/admin.py @@ -25,8 +25,8 @@ class DocumentVersionInline(admin.StackedInline): #inlines = [ # DocumentPageInline, #] - - + + class DocumentTypeFilenameInline(admin.StackedInline): model = DocumentTypeFilename extra = 1 diff --git a/apps/folders/forms.py b/apps/folders/forms.py index a17c3a3d27..d76da47f3d 100644 --- a/apps/folders/forms.py +++ b/apps/folders/forms.py @@ -32,7 +32,7 @@ class FolderListForm(forms.Form): Permission.objects.check_permissions(user, [PERMISSION_FOLDER_VIEW]) except PermissionDenied: queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_VIEW, user, queryset) - + self.fields['folder'] = forms.ModelChoiceField( queryset=queryset, label=_(u'Folder')) diff --git a/apps/folders/models.py b/apps/folders/models.py index c032780241..e58db8ab91 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -27,11 +27,11 @@ class Folder(models.Model): @property def documents(self): return [folder_document.document for folder_document in self.folderdocument_set.all()] - + def remove_document(self, document): folder_document = self.folderdocument_set.get(document=document) folder_document.delete() - + def add_document(self, document): folder_document, created = FolderDocument.objects.get_or_create(folder=self, document=document) return created diff --git a/apps/folders/permissions.py b/apps/folders/permissions.py index 6077438f42..5538a70214 100644 --- a/apps/folders/permissions.py +++ b/apps/folders/permissions.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/apps/folders/tests.py b/apps/folders/tests.py index 2247054b35..3b31148896 100644 --- a/apps/folders/tests.py +++ b/apps/folders/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/folders/urls.py b/apps/folders/urls.py index 0e0cf0d5ad..9f35d24c69 100644 --- a/apps/folders/urls.py +++ b/apps/folders/urls.py @@ -11,6 +11,6 @@ urlpatterns = patterns('folders.views', url(r'^document/(?P\d+)/folder/add/$', 'folder_add_document', (), 'folder_add_document'), url(r'^document/(?P\d+)/folder/list/$', 'document_folder_list', (), 'document_folder_list'), - + url(r'^(?P\d+)/acl/list/$', 'folder_acl_list', (), 'folder_acl_list'), ) diff --git a/apps/folders/views.py b/apps/folders/views.py index b604f00d8b..0bd85d2790 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import import logging @@ -49,8 +49,8 @@ def folder_list(request, queryset=None, extra_context=None): queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_FOLDER_VIEW, request.user, queryset) context['object_list'] = queryset - - return render_to_response('generic_list.html', + + return render_to_response('generic_list.html', context, context_instance=RequestContext(request) ) @@ -58,7 +58,7 @@ def folder_list(request, queryset=None, extra_context=None): def folder_create(request): Permission.objects.check_permissions(request.user, [PERMISSION_FOLDER_CREATE]) - + if request.method == 'POST': form = FolderForm(request.POST) if form.is_valid(): @@ -157,9 +157,9 @@ def folder_view(request, folder_id): 'hide_links': True, 'multi_select_as_buttons': True, 'object': folder, - 'object_name': _(u'folder'), + 'object_name': _(u'folder'), } - + return document_list( request, object_list=folder.documents, @@ -193,14 +193,13 @@ def folder_add_document(request, document_id): else: form = FolderListForm(user=request.user) - return render_to_response('generic_form.html', { 'title': _(u'add document "%s" to a folder') % document, 'form': form, 'object': document, 'next': next, }, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) def document_folder_list(request, document_id): diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index 0d827f3e48..e45e80a496 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/apps/linking/admin.py b/apps/linking/admin.py index 84f13692f5..2116114693 100644 --- a/apps/linking/admin.py +++ b/apps/linking/admin.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.contrib import admin diff --git a/apps/linking/forms.py b/apps/linking/forms.py index 5cdb6be1f9..53c9639f53 100644 --- a/apps/linking/forms.py +++ b/apps/linking/forms.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ @@ -18,7 +18,7 @@ class SmartLinkForm(forms.ModelForm): class Meta: model = SmartLink - + class SmartLinkConditionForm(forms.ModelForm): class Meta: model = SmartLinkCondition @@ -56,7 +56,7 @@ class SmartLinkImageWidget(forms.widgets.Widget): output.append(u'%s' % (reverse('document_view_simple', args=[document.pk]), ugettext(u'Select'))) output.append(u'
    ') output.append(u'
    ') - + output.append(u'
    ') output.append( u'
    %s' % @@ -70,9 +70,9 @@ class SmartLinkInstanceForm(forms.Form): smart_link_instances = kwargs.pop('smart_link_instances', None) links = kwargs.pop('links', None) current_document = kwargs.pop('current_document', None) - + super(SmartLinkInstanceForm, self).__init__(*args, **kwargs) - + for smart_link_instance, data in smart_link_instances.items(): self.fields['preview-%s' % smart_link_instance] = forms.CharField( widget=SmartLinkImageWidget(), diff --git a/apps/linking/managers.py b/apps/linking/managers.py index bb6dcba1c5..4583b646ad 100644 --- a/apps/linking/managers.py +++ b/apps/linking/managers.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.db import models from django.db.models import Q diff --git a/apps/linking/models.py b/apps/linking/models.py index 2c75642c9e..0af9522e77 100644 --- a/apps/linking/models.py +++ b/apps/linking/models.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/apps/linking/permissions.py b/apps/linking/permissions.py index c9b889b084..f5e7cc30b7 100644 --- a/apps/linking/permissions.py +++ b/apps/linking/permissions.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/apps/linking/urls.py b/apps/linking/urls.py index cf47c7ca7e..7cb2749d6e 100644 --- a/apps/linking/urls.py +++ b/apps/linking/urls.py @@ -4,12 +4,12 @@ urlpatterns = patterns('linking.views', url(r'^action/$', 'smart_link_action', (), 'smart_link_action'), url(r'^document/(?P\d+)/smart_link/(?P\d+)/$', 'smart_link_instance_view', (), 'smart_link_instance_view'), url(r'^smart/for_document/(?P\d+)/$', 'smart_link_instances_for_document', (), 'smart_link_instances_for_document'), - + url(r'^setup/list/$', 'smart_link_list', (), 'smart_link_list'), url(r'^setup/create/$', 'smart_link_create', (), 'smart_link_create'), url(r'^setup/(?P\d+)/delete/$', 'smart_link_delete', (), 'smart_link_delete'), url(r'^setup/(?P\d+)/edit/$', 'smart_link_edit', (), 'smart_link_edit'), - + url(r'^setup/(?P\d+)/condition/list/$', 'smart_link_condition_list', (), 'smart_link_condition_list'), url(r'^setup/(?P\d+)/condition/create/$', 'smart_link_condition_create', (), 'smart_link_condition_create'), url(r'^setup/smart_link/condition/(?P\d+)/edit/$', 'smart_link_condition_edit', (), 'smart_link_condition_edit'), diff --git a/apps/linking/views.py b/apps/linking/views.py index 0e8a89ccec..07e1d42351 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) def smart_link_action(request): #Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) - + action = request.GET.get('action', None) if not action: @@ -45,12 +45,12 @@ def smart_link_action(request): def smart_link_instance_view(request, document_id, smart_link_pk): document = get_object_or_404(Document, pk=document_id) smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_SMART_LINK_VIEW, request.user, smart_link) - + object_list, errors = SmartLink.objects.get_smart_link_instances_for(document, smart_link) return document_list( @@ -86,7 +86,7 @@ def smart_link_instances_for_document(request, document_id): for key, value in smart_link_instances.items(): if key not in smart_link_instances_keys_filtered: smart_link_instances.pop(key) - + value['documents'] = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_VIEW, request.user, value['documents']) if smart_link_instances: @@ -116,30 +116,30 @@ def smart_link_instances_for_document(request, document_id): 'document': document, 'subtemplates_list': subtemplates_list, }, context_instance=RequestContext(request)) - - + + def smart_link_list(request): qs = SmartLink.objects.all() - + try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW]) except PermissionDenied: qs = AccessEntry.objects.filter_objects_by_access(PERMISSION_SMART_LINK_VIEW, request.user, qs) - - + + return render_to_response('generic_list.html', { 'title': _(u'smart links'), 'object_list': qs, 'extra_columns': [ {'name': _(u'dynamic title'), 'attribute': 'dynamic_title'}, {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, - ], + ], 'hide_link': True, 'list_object_variable_name': 'smart_link', }, context_instance=RequestContext(request)) - - + + def smart_link_create(request): Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE]) @@ -155,9 +155,9 @@ def smart_link_create(request): return render_to_response('generic_form.html', { 'form': form, 'title': _(u'Create new smart link') - }, context_instance=RequestContext(request)) - - + }, context_instance=RequestContext(request)) + + def smart_link_edit(request, smart_link_pk): smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) @@ -180,16 +180,16 @@ def smart_link_edit(request, smart_link_pk): 'object': smart_link, 'form': form, 'title': _(u'Edit smart link: %s') % smart_link - }, context_instance=RequestContext(request)) - - + }, context_instance=RequestContext(request)) + + def smart_link_delete(request, smart_link_pk): smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_DELETE]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_SMART_LINK_DELETE, request.user, smart_link) + AccessEntry.objects.check_access(PERMISSION_SMART_LINK_DELETE, request.user, smart_link) 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', '/'))) @@ -212,26 +212,26 @@ def smart_link_delete(request, smart_link_pk): 'next': next, 'previous': previous, 'form_icon': u'link_delete.png', - }, context_instance=RequestContext(request)) - + }, context_instance=RequestContext(request)) + def smart_link_condition_list(request, smart_link_pk): smart_link = get_object_or_404(SmartLink, pk=smart_link_pk) - + try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) except PermissionDenied: - AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link) - + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link) + return render_to_response('generic_list.html', { 'title': _(u'conditions for smart link: %s') % smart_link, 'object_list': smart_link.smartlinkcondition_set.all(), 'extra_columns': [ {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, - ], + ], 'hide_link': True, 'object': smart_link, - 'list_object_variable_name': 'condition', + 'list_object_variable_name': 'condition', }, context_instance=RequestContext(request)) @@ -241,14 +241,14 @@ def smart_link_condition_create(request, smart_link_pk): try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) except PermissionDenied: - AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link) + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link) if request.method == 'POST': form = SmartLinkConditionForm(request.POST) if form.is_valid(): new_smart_link_condition = form.save(commit=False) new_smart_link_condition.smart_link = smart_link - new_smart_link_condition.save() + new_smart_link_condition.save() messages.success(request, _(u'Smart link condition: "%s" created successfully.') % new_smart_link_condition) return HttpResponseRedirect(reverse('smart_link_condition_list', args=[smart_link.pk])) else: @@ -257,8 +257,8 @@ def smart_link_condition_create(request, smart_link_pk): return render_to_response('generic_form.html', { 'form': form, 'title': _(u'Add new conditions to smart link: "%s"') % smart_link, - 'object': smart_link, - }, context_instance=RequestContext(request)) + 'object': smart_link, + }, context_instance=RequestContext(request)) def smart_link_condition_edit(request, smart_link_condition_pk): @@ -267,7 +267,7 @@ def smart_link_condition_edit(request, smart_link_condition_pk): try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) except PermissionDenied: - AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link) + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link) 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', '/'))) @@ -294,8 +294,8 @@ def smart_link_condition_edit(request, smart_link_condition_pk): {'object': 'object', 'name': _(u'smart link')}, {'object': 'condition', 'name': _(u'condition')} ], - - }, context_instance=RequestContext(request)) + + }, context_instance=RequestContext(request)) def smart_link_condition_delete(request, smart_link_condition_pk): @@ -304,7 +304,7 @@ def smart_link_condition_delete(request, smart_link_condition_pk): try: Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) except PermissionDenied: - AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link) + AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link) 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', '/'))) @@ -332,7 +332,7 @@ def smart_link_condition_delete(request, smart_link_condition_pk): 'next': next, 'previous': previous, 'form_icon': u'cog_delete.png', - }, context_instance=RequestContext(request)) + }, context_instance=RequestContext(request)) def smart_link_acl_list(request, smart_link_pk): diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 8a502f30f9..80d503ca7e 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -12,7 +12,7 @@ from .conf.settings import SIDE_BAR_SEARCH, DISABLE_HOME_VIEW __author__ = 'Roberto Rosario' __copyright__ = 'Copyright 2011 Roberto Rosario' -__credits__ = ['Roberto Rosario',] +__credits__ = ['Roberto Rosario',] __license__ = 'GPL' __maintainer__ = 'Roberto Rosario' __email__ = 'roberto.rosario.gonzalez@gmail.com' @@ -58,7 +58,7 @@ __version__ = get_version() if 'django.contrib.admin' in settings.INSTALLED_APPS: register_setup(admin_site) - + register_tool(maintenance_menu) register_tool(statistics) register_tool(diagnostics) diff --git a/apps/main/tests.py b/apps/main/tests.py index 2247054b35..3b31148896 100644 --- a/apps/main/tests.py +++ b/apps/main/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index 099b908216..f52465d568 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/apps/metadata/admin.py b/apps/metadata/admin.py index 53ca6f69cd..058d5d0544 100644 --- a/apps/metadata/admin.py +++ b/apps/metadata/admin.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.contrib import admin diff --git a/apps/metadata/api.py b/apps/metadata/api.py index 3473cf5bd0..60e611e5f6 100644 --- a/apps/metadata/api.py +++ b/apps/metadata/api.py @@ -1,5 +1,5 @@ -'''Metadata handling commonalities''' -from __future__ import absolute_import +"""Metadata handling commonalities""" +from __future__ import absolute_import from urllib import unquote_plus @@ -9,9 +9,9 @@ from .models import DocumentMetadata, MetadataType def decode_metadata_from_url(url_dict): - ''' + """ Parse a URL query string to a list of metadata - ''' + """ metadata_dict = { 'id': {}, 'value': {} @@ -35,19 +35,19 @@ def decode_metadata_from_url(url_dict): def save_metadata_list(metadata_list, document, create=False): - ''' + """ Take a list of metadata dictionaries and associate them to a document - ''' + """ for item in metadata_list: save_metadata(item, document, create) def save_metadata(metadata_dict, document, create=False): - ''' + """ Take a dictionary of metadata type & value and associate it to a document - ''' + """ if create: # Use matched metadata now to create document metadata document_metadata, created = DocumentMetadata.objects.get_or_create( @@ -81,16 +81,16 @@ def save_metadata(metadata_dict, document, create=False): def metadata_repr(metadata_list): - ''' + """ Return a printable representation of a metadata list - ''' + """ return u', '.join(metadata_repr_as_list(metadata_list)) def metadata_repr_as_list(metadata_list): - ''' + """ Turn a list of metadata into a list of printable representations - ''' + """ output = [] for metadata_dict in metadata_list: try: @@ -103,7 +103,7 @@ def metadata_repr_as_list(metadata_list): 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')]) diff --git a/apps/metadata/forms.py b/apps/metadata/forms.py index e319ff3f92..c2e281242c 100644 --- a/apps/metadata/forms.py +++ b/apps/metadata/forms.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ diff --git a/apps/metadata/models.py b/apps/metadata/models.py index 1c7fda9249..5e13f65c48 100644 --- a/apps/metadata/models.py +++ b/apps/metadata/models.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -12,9 +12,9 @@ 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, @@ -35,9 +35,9 @@ class MetadataType(models.Model): class MetadataSet(models.Model): - ''' + """ Define a group of metadata types - ''' + """ title = models.CharField(max_length=48, verbose_name=_(u'title')) def __unicode__(self): @@ -50,10 +50,10 @@ class MetadataSet(models.Model): class MetadataSetItem(models.Model): - ''' + """ Define the set of metadata that relates to a set or group of metadata fields - ''' + """ metadata_set = models.ForeignKey(MetadataSet, verbose_name=_(u'metadata set')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) #required = models.BooleanField(default=True, verbose_name=_(u'required')) @@ -67,10 +67,10 @@ class MetadataSetItem(models.Model): class DocumentMetadata(models.Model): - ''' + """ Link a document to a specific instance of a metadata type with it's current value - ''' + """ document = models.ForeignKey(Document, verbose_name=_(u'document')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'type')) value = models.CharField(max_length=256, blank=True, verbose_name=_(u'value'), db_index=True) @@ -84,10 +84,10 @@ class DocumentMetadata(models.Model): 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 index 5ed8f9cb43..9f6ff38a76 100644 --- a/apps/metadata/permissions.py +++ b/apps/metadata/permissions.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ diff --git a/apps/metadata/tests.py b/apps/metadata/tests.py index 2247054b35..3b31148896 100644 --- a/apps/metadata/tests.py +++ b/apps/metadata/tests.py @@ -20,4 +20,3 @@ 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 6f570beed8..6c66baaf4d 100644 --- a/apps/metadata/views.py +++ b/apps/metadata/views.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from django.shortcuts import render_to_response from django.template import RequestContext @@ -46,10 +46,10 @@ def metadata_edit(request, document_id=None, document_id_list=None): 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', '/')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) post_action_redirect = reverse('document_list_recent') @@ -141,7 +141,7 @@ def metadata_add(request, document_id=None, document_id_list=None): if not documents: messages.error(request, _(u'Must provide at least one document.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) for document in documents: RecentDocument.objects.add_document_for_user(request.user, document) @@ -205,12 +205,12 @@ 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(',')] - + 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', '/')) @@ -304,7 +304,7 @@ def metadata_view(request, document_id): 'hide_link': True, 'object': document, }, context_instance=RequestContext(request)) - + # Setup views def setup_metadata_type_list(request): @@ -323,12 +323,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): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_EDIT]) - + metadata_type = get_object_or_404(MetadataType, pk=metadatatype_id) if request.method == 'POST': @@ -351,12 +351,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): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_TYPE_CREATE]) - + if request.method == 'POST': form = MetadataTypeForm(request.POST) if form.is_valid(): @@ -375,7 +375,7 @@ def setup_metadata_type_create(request): def setup_metadata_type_delete(request, metadatatype_id): 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') @@ -423,7 +423,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): @@ -471,7 +471,7 @@ def setup_metadata_set_edit(request, metadata_set_id): def setup_metadata_set_create(request): Permission.objects.check_permissions(request.user, [PERMISSION_METADATA_SET_CREATE]) - + if request.method == 'POST': form = MetadataSetForm(request.POST) if form.is_valid(): @@ -490,7 +490,7 @@ def setup_metadata_set_create(request): def setup_metadata_set_delete(request, metadata_set_id): 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') @@ -566,7 +566,7 @@ def setup_document_type_metadata(request, 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)), diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index c2f2358039..ac2f29ce08 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -21,7 +21,7 @@ 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, PERMISSION_OCR_QUEUE_EDIT) + PERMISSION_OCR_CLEAN_ALL_PAGES) logger = logging.getLogger(__name__) diff --git a/apps/ocr/tasks.py b/apps/ocr/tasks.py index f042c51460..faab0df58c 100644 --- a/apps/ocr/tasks.py +++ b/apps/ocr/tasks.py @@ -40,7 +40,7 @@ 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') diff --git a/apps/ocr/tests.py b/apps/ocr/tests.py index 2247054b35..3b31148896 100644 --- a/apps/ocr/tests.py +++ b/apps/ocr/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/ocr/views.py b/apps/ocr/views.py index be640952b4..52e0fc9eb4 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -123,9 +123,9 @@ 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): document = get_object_or_404(Document, pk=document_id) @@ -134,7 +134,7 @@ def submit_document(request, document_id): 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', '/')) diff --git a/apps/permissions/api.py b/apps/permissions/api.py index 8b13789179..e69de29bb2 100644 --- a/apps/permissions/api.py +++ b/apps/permissions/api.py @@ -1 +0,0 @@ - diff --git a/apps/permissions/models.py b/apps/permissions/models.py index b21cdbf7ae..f59215b472 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -13,7 +13,7 @@ from django.core.exceptions import PermissionDenied from common.models import AnonymousUserSingleton from .managers import (RoleMemberManager, StoredPermissionManager) - + logger = logging.getLogger(__name__) @@ -21,7 +21,7 @@ class PermissionNamespace(object): def __init__(self, name, label): self.name = name self.label = label - + def __unicode__(self): return unicode(self.label) @@ -29,17 +29,17 @@ class PermissionNamespace(object): 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: @@ -49,11 +49,11 @@ class PermissionManager(object): 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 @@ -69,21 +69,21 @@ class PermissionManager(object): 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) @@ -93,7 +93,7 @@ class Permission(object): @property def uuid(self): return u'%s.%s' % (self.namespace.name, self.name) - + @property def stored_permission(self): return self.get_stored_permission() @@ -107,17 +107,17 @@ class Permission(object): 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')) @@ -126,15 +126,15 @@ class StoredPermission(models.Model): objects = StoredPermissionManager() class Meta: - ordering = ('namespace', ) + 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 unicode(getattr(self, 'volatile_permission', self.name)) @@ -164,7 +164,7 @@ class StoredPermission(models.Model): for membership in list(set(roles) | set(groups)): if self.requester_has_this(membership): return True - + logger.debug('Fallthru') return False @@ -181,7 +181,7 @@ class StoredPermission(models.Model): return True except PermissionHolder.DoesNotExist: return False - + class PermissionHolder(models.Model): permission = models.ForeignKey(StoredPermission, verbose_name=_(u'permission')) @@ -228,7 +228,7 @@ class Role(models.Model): 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() + role_member.delete() def members(self, filter_dict=None): filter_dict = filter_dict or {} diff --git a/apps/permissions/runtime.py b/apps/permissions/runtime.py index 8b13789179..e69de29bb2 100644 --- a/apps/permissions/runtime.py +++ b/apps/permissions/runtime.py @@ -1 +0,0 @@ - diff --git a/apps/permissions/tests.py b/apps/permissions/tests.py index 2247054b35..3b31148896 100644 --- a/apps/permissions/tests.py +++ b/apps/permissions/tests.py @@ -20,4 +20,3 @@ 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 a7e2df41fb..4d2230dbb2 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -24,7 +24,7 @@ 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) + PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE) from .widgets import role_permission_link @@ -133,20 +133,20 @@ def permission_grant(request): 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: @@ -174,13 +174,13 @@ 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): Permission.objects.check_permissions(request.user, [PERMISSION_PERMISSION_REVOKE]) @@ -197,20 +197,20 @@ def permission_revoke(request): 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: @@ -238,7 +238,7 @@ def permission_revoke(request): 'permissions_label': permissions_label, 'title_suffix': title_suffix, } - + if len(grouped_items) == 1: context['object'] = grouped_items[0][0] @@ -259,7 +259,7 @@ def get_role_members(role, separate=False): user_ct = ContentType.objects.get(model='user') group_ct = ContentType.objects.get(model='group') 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}) @@ -268,34 +268,34 @@ def get_role_members(role, separate=False): 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 + 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.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)))) @@ -303,7 +303,7 @@ def get_non_role_members(role): 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 diff --git a/apps/smart_settings/__init__.py b/apps/smart_settings/__init__.py index 5926e68754..e28aa67add 100644 --- a/apps/smart_settings/__init__.py +++ b/apps/smart_settings/__init__.py @@ -2,6 +2,7 @@ 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 diff --git a/apps/smart_settings/tests.py b/apps/smart_settings/tests.py index 2247054b35..3b31148896 100644 --- a/apps/smart_settings/tests.py +++ b/apps/smart_settings/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/sources/tests.py b/apps/sources/tests.py index 2247054b35..3b31148896 100644 --- a/apps/sources/tests.py +++ b/apps/sources/tests.py @@ -20,4 +20,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/apps/sources/views.py b/apps/sources/views.py index 4ab34935a4..f116dfad64 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -85,7 +85,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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]) @@ -149,7 +149,7 @@ 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'], new_filename, use_file_name=form.cleaned_data.get('use_file_name', False), document_type=document_type, @@ -157,7 +157,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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.')) @@ -180,7 +180,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': { @@ -214,7 +214,7 @@ 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(), new_filename, use_file_name=form.cleaned_data.get('use_file_name', False), document_type=document_type, @@ -222,7 +222,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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) @@ -258,7 +258,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', @@ -275,7 +275,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 'hide_link': True, } }, - ] + ] if document: context['object'] = document @@ -290,11 +290,11 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No }, 'upload_interactive': { 'links': results['tab_links'] - } + } } }, }) - + if not document: context.update( { @@ -310,7 +310,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)) @@ -420,12 +420,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): Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_EDIT]) - + if source_type == SOURCE_CHOICE_WEB_FORM: cls = WebForm form_class = WebFormSetupForm @@ -435,7 +435,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', '/'))) @@ -477,12 +477,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() @@ -511,7 +511,7 @@ def setup_source_delete(request, source_type, source_id): def setup_source_create(request, source_type): Permission.objects.check_permissions(request.user, [PERMISSION_SOURCES_SETUP_CREATE]) - + if source_type == SOURCE_CHOICE_WEB_FORM: cls = WebForm form_class = WebFormSetupForm @@ -521,7 +521,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(): @@ -545,7 +545,7 @@ def setup_source_create(request, source_type): def setup_source_transformation_list(request, source_type, source_id): 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: @@ -572,12 +572,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): 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))) @@ -605,7 +605,7 @@ 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): @@ -632,14 +632,14 @@ 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): @@ -651,11 +651,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(): @@ -669,7 +669,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/tags/forms.py b/apps/tags/forms.py index cd2bead2c2..b10ac68679 100644 --- a/apps/tags/forms.py +++ b/apps/tags/forms.py @@ -18,9 +18,9 @@ logger = logging.getLogger(__name__) class TagForm(forms.Form): - ''' + """ Form to edit an existing tag's properties - ''' + """ name = forms.CharField(label=_(u'Name')) color = forms.ChoiceField(choices=COLOR_CHOICES, label=_(u'Color')) @@ -36,7 +36,7 @@ class TagListForm(forms.Form): 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/urls.py b/apps/tags/urls.py index fff26800a8..14c9902303 100644 --- a/apps/tags/urls.py +++ b/apps/tags/urls.py @@ -12,6 +12,6 @@ urlpatterns = patterns('tags.views', url(r'^multiple/remove_from_document/(?P\d+)/$', 'tag_multiple_remove', (), 'tag_multiple_remove'), 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/views.py b/apps/tags/views.py index 50e8929c10..615c248829 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -40,11 +40,11 @@ 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() - + messages.success(request, _(u'Tag created succesfully.')) return HttpResponseRedirect(redirect_url) else: @@ -54,7 +54,7 @@ def tag_create(request): 'title': _(u'create tag'), 'form': form, }, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) def tag_attach(request, document_id): @@ -63,7 +63,7 @@ def tag_attach(request, document_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_TAG_ATTACH]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_TAG_ATTACH, request.user, document) + 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])))) @@ -108,7 +108,7 @@ def tag_list(request, queryset=None, extra_context=None): 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) @@ -126,11 +126,11 @@ def tag_delete(request, tag_id=None, tag_id_list=None): else: 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) + 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', '/'))) @@ -178,7 +178,7 @@ def tag_edit(request, tag_id): try: Permission.objects.check_permissions(request.user, [PERMISSION_TAG_EDIT]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_TAG_EDIT, request.user, tag) + AccessEntry.objects.check_access(PERMISSION_TAG_EDIT, request.user, tag) if request.method == 'POST': form = TagForm(request.POST) @@ -227,13 +227,13 @@ def document_tags(request, document_id): 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, 'title': _(u'tags for: %s') % document, } - + return tag_list(request, queryset=document.tags.all(), extra_context=context) @@ -243,7 +243,7 @@ def tag_remove(request, document_id, tag_id=None, tag_id_list=None): try: Permission.objects.check_permissions(request.user, [PERMISSION_TAG_REMOVE]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_TAG_REMOVE, request.user, document) + AccessEntry.objects.check_access(PERMISSION_TAG_REMOVE, request.user, document) post_action_redirect = None diff --git a/apps/tags/widgets.py b/apps/tags/widgets.py index b9dcb0266b..521ad6a1b2 100644 --- a/apps/tags/widgets.py +++ b/apps/tags/widgets.py @@ -3,9 +3,9 @@ from django.utils.safestring import mark_safe def get_tags_inline_widget(document): - ''' + """ A tag widget that includes the total tag count for a given document - ''' + """ tags_template = [] tag_count = document.tags.count() if tag_count: @@ -13,17 +13,17 @@ 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)) def get_tags_inline_widget_simple(document): - ''' + """ A tag widget that only displayes the rectangular colored boxes for a given document - ''' + """ tags_template = [] tag_count = document.tags.count() From e069243f7cab69ec953c754113a760415159f184 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 14:43:17 -0400 Subject: [PATCH 261/484] Add missing import --- apps/converter/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/converter/api.py b/apps/converter/api.py index 7e22354b2d..2c3269fab9 100644 --- a/apps/converter/api.py +++ b/apps/converter/api.py @@ -15,7 +15,7 @@ from .literals import (TRANSFORMATION_CHOICES, TRANSFORMATION_RESIZE, FILE_FORMATS) from .utils import cleanup from .runtime import office_converter -from .exceptions import OfficeConversionError +from .exceptions import OfficeConversionError, UnknownFileFormat HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() From 84f3fcd2dade4e3ea90b724890559bc2ec2e2243 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 14:43:33 -0400 Subject: [PATCH 262/484] Rename holder to actor --- apps/permissions/models.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/permissions/models.py b/apps/permissions/models.py index f59215b472..ff7dfd957f 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -141,23 +141,23 @@ class StoredPermission(models.Model): def get_holders(self): return [holder.holder_object for holder in self.permissionholder_set.all()] - def requester_has_this(self, requester): - requester = AnonymousUserSingleton.objects.passthru_check(requester) - logger.debug('requester: %s' % 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 = [] @@ -168,15 +168,15 @@ class StoredPermission(models.Model): logger.debug('Fallthru') return False - def grant_to(self, requester): - requester = AnonymousUserSingleton.objects.passthru_check(requester) - permission_holder, created = PermissionHolder.objects.get_or_create(permission=self, holder_type=ContentType.objects.get_for_model(requester), holder_id=requester.pk) + 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): - requester = AnonymousUserSingleton.objects.passthru_check(requester) + 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: From af106badac691199c36cf8708d53c6a106d155a8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 16:00:30 -0400 Subject: [PATCH 263/484] Cleanups and remove unused imports --- apps/acls/views.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index 694c4b1e68..45af37d086 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -1,25 +1,21 @@ from __future__ import absolute_import import logging -import operator -import itertools from django.utils.translation import ugettext_lazy as _ 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 -from django.views.generic.list_detail import object_list from django.core.urlresolvers import reverse from django.contrib.contenttypes.models import ContentType -from django.contrib.auth.models import User, Group from django.core.exceptions import ObjectDoesNotExist from django.utils.simplejson import loads from django.core.exceptions import PermissionDenied from django.utils.http import urlencode -from permissions.models import Permission, Role -from common.utils import generate_choices_w_labels, encapsulate +from permissions.models import Permission +from common.utils import encapsulate from common.widgets import two_state_template from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, @@ -29,7 +25,7 @@ from .classes import (AccessHolder, AccessObject, AccessObjectClass, ClassAccessHolder) from .widgets import object_w_content_type_icon from .forms import HolderSelectionForm -from .api import get_class_permissions_for, get_classes +from .api import get_class_permissions_for logger = logging.getLogger(__name__) @@ -46,7 +42,6 @@ def acl_list_for(request, obj, extra_context=None): logger.debug('obj: %s' % obj) - ct = ContentType.objects.get_for_model(obj) context = { 'object_list': AccessEntry.objects.get_holders_for(obj), 'title': _(u'access control lists for: %s' % obj), @@ -200,7 +195,7 @@ def acl_grant(request): for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: - if AccessEntry.objects.grant(permission, requester.source_object, obj.source_object): + if AccessEntry.objects.grant(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" granted to %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, @@ -294,7 +289,7 @@ def acl_revoke(request): for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: - if AccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): + if AccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, @@ -381,7 +376,7 @@ def acl_holder_new(request, access_object_gid): except ObjectDoesNotExist: raise Http404 - return acl_new_holder_for(request, access_object.source_object)#, extra_context={'access_object': access_object}) + return acl_new_holder_for(request, access_object.source_object) # , extra_context={'access_object': access_object}) # Setup views @@ -621,7 +616,7 @@ def acl_class_multiple_revoke(request): for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: - if DefaultAccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): + if DefaultAccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, From f374596a285be26ef5144b638667b9212416818a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 16:01:06 -0400 Subject: [PATCH 264/484] Cleanups, improve comments --- apps/acls/managers.py | 51 +++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index dd69b7d061..ffe3d08d7a 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -19,6 +19,10 @@ logger = logging.getLogger(__name__) class AccessEntryManager(models.Manager): + """ + Implement a 3 tier permission system, involving a permissions, an actor + and an object + """ def source_object(self, obj): if isinstance(obj, EncapsulatedObject): return obj.source_object @@ -26,9 +30,9 @@ class AccessEntryManager(models.Manager): return obj def grant(self, permission, actor, obj): - ''' + """ Grant a permission (what), (to) an actor, (on) a specific object - ''' + """ obj = self.source_object(obj) actor = self.source_object(actor) @@ -42,9 +46,9 @@ class AccessEntryManager(models.Manager): return created def revoke(self, permission, actor, obj): - ''' + """ Revoke a permission (what), (from) an actor, (on) a specific object - ''' + """ obj = self.source_object(obj) actor = self.source_object(actor) @@ -62,6 +66,9 @@ class AccessEntryManager(models.Manager): return False def has_access(self, permission, actor, obj): + """ + Returns whether an actor has a specific permission for an object + """ obj = self.source_object(obj) actor = self.source_object(actor) @@ -72,18 +79,20 @@ class AccessEntryManager(models.Manager): actor = AnonymousUserSingleton.objects.passthru_check(actor) try: - access_entry = self.model.objects.get( + self.model.objects.get( permission=permission.get_stored_permission(), holder_type=ContentType.objects.get_for_model(actor), holder_id=actor.pk, content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk ) - return True except self.model.DoesNotExist: return False + else: + return True def check_access(self, permission, actor, obj): + # TODO: Merge with has_access obj = self.source_object(obj) actor = self.source_object(actor) @@ -93,6 +102,9 @@ class AccessEntryManager(models.Manager): raise PermissionDenied(ugettext(u'Insufficient access.')) def check_accesses(self, permission_list, actor, obj): + """ + Returns whether an actor has at least one of a list of permissions for an object + """ obj = self.source_object(obj) actor = self.source_object(actor) for permission in permission_list: @@ -137,6 +149,10 @@ class AccessEntryManager(models.Manager): return holder_list def get_holder_permissions_for(self, obj, actor): + """ + Returns a list of actors that hold at least one permission for + a specific object + """ logger.debug('obj: %s' % obj) logger.debug('actor: %s' % actor) @@ -149,6 +165,10 @@ class AccessEntryManager(models.Manager): return (access.permission for access in self.model.objects.filter(content_type=content_type, object_id=obj.pk, holder_type=actor_type, holder_id=actor.pk)) def filter_objects_by_access(self, permission, actor, object_list, exception_on_empty=False, related=None): + """ + Filter a list of objects or a QuerySet elements depending on + whether the actor holds the specified permission + """ logger.debug('exception_on_empty: %s' % exception_on_empty) logger.debug('object_list: %s' % object_list) @@ -184,6 +204,12 @@ class AccessEntryManager(models.Manager): class DefaultAccessEntryManager(models.Manager): + """ + Implement a 3 tier permission system, involving a permission, an actor + and a class or content type. This model keeps track of the access + control lists that will be added when an instance of the recorded + content type is created. + """ def get_holders_for(self, cls): if isinstance(cls, EncapsulatedObject): cls = cls.source_object @@ -204,20 +230,21 @@ class DefaultAccessEntryManager(models.Manager): return True try: - access_entry = self.model.objects.get( + self.model.objects.get( permission=permission.get_stored_permission(), holder_type=ContentType.objects.get_for_model(actor), holder_id=actor.pk, content_type=ContentType.objects.get_for_model(cls), ) - return True except self.model.DoesNotExist: return False + else: + return True def grant(self, permission, actor, cls): - ''' + """ Grant a permission (what), (to) an actor, (on) a specific class - ''' + """ access_entry, created = self.model.objects.get_or_create( permission=permission, holder_type=ContentType.objects.get_for_model(actor), @@ -227,9 +254,9 @@ class DefaultAccessEntryManager(models.Manager): return created def revoke(self, permission, actor, cls): - ''' + """ Revoke a permission (what), (from) an actor, (on) a specific class - ''' + """ try: access_entry = self.model.objects.get( permission=permission, From c9e58bdfac81d42bbf9d27ccfbf77c4f6cdb0b36 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 16:05:11 -0400 Subject: [PATCH 265/484] Remove unused import --- apps/acls/widgets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/acls/widgets.py b/apps/acls/widgets.py index 521a60d40b..896d99611b 100644 --- a/apps/acls/widgets.py +++ b/apps/acls/widgets.py @@ -1,6 +1,5 @@ from __future__ import absolute_import -from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe from django.contrib.contenttypes.models import ContentType from django.db.models.base import ModelBase From 44aef884f487c51f300e0ba231d93eac3556c8b9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 16:06:06 -0400 Subject: [PATCH 266/484] Remove exporter app --- apps/exporter/__init__.py | 0 apps/exporter/models.py | 3 - apps/exporter/tests.py | 16 ---- apps/exporter/urls.py | 5 -- apps/exporter/views.py | 150 -------------------------------------- 5 files changed, 174 deletions(-) delete mode 100644 apps/exporter/__init__.py delete mode 100644 apps/exporter/models.py delete mode 100644 apps/exporter/tests.py delete mode 100644 apps/exporter/urls.py delete mode 100644 apps/exporter/views.py diff --git a/apps/exporter/__init__.py b/apps/exporter/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/apps/exporter/models.py b/apps/exporter/models.py deleted file mode 100644 index 71a8362390..0000000000 --- a/apps/exporter/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/apps/exporter/tests.py b/apps/exporter/tests.py deleted file mode 100644 index 501deb776c..0000000000 --- a/apps/exporter/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/exporter/urls.py b/apps/exporter/urls.py deleted file mode 100644 index 73fda937a8..0000000000 --- a/apps/exporter/urls.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf.urls.defaults import patterns, url - -urlpatterns = patterns('exporter.views', - url(r'^export_test/$', 'export_test', (), 'export_test'), -) diff --git a/apps/exporter/views.py b/apps/exporter/views.py deleted file mode 100644 index 407f3ffcc8..0000000000 --- a/apps/exporter/views.py +++ /dev/null @@ -1,150 +0,0 @@ -import os -import hashlib - -from django.utils import simplejson -from django.http import HttpResponse -from django.template.defaultfilters import slugify - -from documents.models import Document, DocumentType -from metadata.models import MetadataType, MetadataSet - -FORMAT_VERSION = 1.0 -HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() - - -def get_hash(obj): - if obj: - return u'%s_%s' % (HASH_FUNCTION(unicode(obj)), slugify(unicode(obj))) - else: - return None - - -''' - - -comments -tags -folders - -pages -pages transformation -metadata -doc_type metadata - -sources -sources transform - -users - -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')) - - -''' - -def export_test(request): - big_list = [] - big_list.append({'version': FORMAT_VERSION}) - - for metadata_type in MetadataType.objects.all(): - big_list.append( - { - 'metadata_types': [ - { - 'id': get_hash(metadata_type.name), - 'name': metadata_type.name, - 'title': metadata_type.title, - 'default': metadata_type.default, - 'lookup': metadata_type.lookup, - } - ] - } - ) - - for metadata_set in MetadataSet.objects.all(): - big_list.append( - { - 'metadata_sets': [ - { - 'id': get_hash(metadata_set.title), - 'name': metadata_set.title, - 'metadata_types': [ - { - 'id': get_hash(metadata_type), - } - for metadata_type in metadata_set.metadatasetitem_set.all() - ] - } - ] - } - ) - - - for document_type in DocumentType.objects.all(): - big_list.append( - { - 'document_types': [ - { - 'id': get_hash(document_type.name), - 'name': document_type.name, - 'filenames': [ - { - 'filename': doc_type_filename.filename, - 'enabled': doc_type_filename.enabled, - } - for doc_type_filename in document_type.documenttypefilename_set.all() - ], - 'metadata_defaults': [ - { - 'default_metadata': [get_hash(metadata_type.name) for metadata_type in doc_type_defaults.default_metadata.all()], - 'default_metadata_sets': [get_hash(metadata_set.title) for metadata_set in doc_type_defaults.default_metadata_sets.all()], - } - for doc_type_defaults in document_type.documenttypedefaults_set.all() - ] - } - ] - } - ) - - for document in Document.objects.all()[:10]: - big_list.append( - { - 'documents': [ - { - 'document_type': get_hash(document.document_type), - 'filename': os.extsep.join([document.file_filename, document.file_extension]), - #'date_added' - 'uuid': document.uuid, - 'description': unicode(document.description) if document.description else None, - 'tags': [get_hash(tag) for tag in document.tags.all()], - 'folders': [get_hash(folder_document.folder) for folder_document in document.folderdocument_set.all()], - 'comments': [ - { - 'comment': comment.comment, - 'user': unicode(comment.user), - 'submit_date': unicode(comment.submit_date), - } - for comment in document.comments.all() - ], - 'versions': [ - { - 1.0: { - 'mimetype': document.file_mimetype, - 'encoding': document.file_mime_encoding, - #'date_updated' - 'checksum': document.checksum, - } - } - ] - } - ] - } - ) - - return HttpResponse(simplejson.dumps(big_list, indent=4, ensure_ascii=True), mimetype='application/json') From c01c030ee60c718ecbe629a3f2557e7924ba4159 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 18 Jan 2012 16:34:59 -0400 Subject: [PATCH 267/484] Remove test --- apps/folders/tests.py | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 apps/folders/tests.py diff --git a/apps/folders/tests.py b/apps/folders/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/folders/tests.py +++ /dev/null @@ -1,22 +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 -"""} From 3b997f0d8f366cf39634557a6191697bfcf9277c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 19 Jan 2012 11:55:53 -0400 Subject: [PATCH 268/484] Silence AlreadyQueued For the moment until support for queueing document versions is avaiable --- apps/ocr/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index ac2f29ce08..f228843100 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -22,6 +22,7 @@ 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 logger = logging.getLogger(__name__) @@ -76,7 +77,10 @@ def document_post_save(sender, instance, **kwargs): logger.debug('instance: %s' % instance) if kwargs.get('created', False): if AUTOMATIC_OCR: - DocumentQueue.objects.queue_document(instance.document) + try: + DocumentQueue.objects.queue_document(instance.document) + except AlreadyQueued: + pass # Disabled because it appears Django execute signals using the same From 8a5825a27510a5a61badac2d2c5b7e6778d8f5ea Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 19 Jan 2012 12:04:02 -0400 Subject: [PATCH 269/484] Convert tabs to spaces --- apps/ocr/tasks.py | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/apps/ocr/tasks.py b/apps/ocr/tasks.py index faab0df58c..800d0623d2 100644 --- a/apps/ocr/tasks.py +++ b/apps/ocr/tasks.py @@ -15,7 +15,7 @@ from .literals import (QUEUEDOCUMENT_STATE_PENDING, QUEUEDOCUMENT_STATE_ERROR) from .models import QueueDocument, DocumentQueue from .conf.settings import (NODE_CONCURRENT_EXECUTION, REPLICATION_DELAY, - QUEUE_PROCESSING_INTERVAL) + QUEUE_PROCESSING_INTERVAL) LOCK_EXPIRE = 60 * 10 # Lock expires in 10 minutes # TODO: Tie LOCK_EXPIRATION with hard task timeout @@ -47,37 +47,9 @@ def task_process_queue_document(queue_document_id): 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)) From 6117fde64983d432bdb4e6bdd05bafbbd9cf680b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 19 Jan 2012 17:44:34 -0400 Subject: [PATCH 270/484] Initial default to current acl support --- apps/acls/managers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index ffe3d08d7a..5b772a4c86 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -211,8 +211,9 @@ class DefaultAccessEntryManager(models.Manager): content type is created. """ def get_holders_for(self, cls): - if isinstance(cls, EncapsulatedObject): - cls = cls.source_object + cls = AccessEntryManager.source_object(cls) + #if isinstance(cls, EncapsulatedObject): + # cls = cls.source_object content_type = ContentType.objects.get_for_model(cls) holder_list = [] From 796dcc908aee7ad5acbb34063fd236e12e6f090c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 20 Jan 2012 22:52:56 -0400 Subject: [PATCH 271/484] Move source_object class method to the classes module --- apps/acls/classes.py | 7 +++++++ apps/acls/managers.py | 36 ++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/acls/classes.py b/apps/acls/classes.py index f2b7c36ef2..2b4719dc95 100644 --- a/apps/acls/classes.py +++ b/apps/acls/classes.py @@ -16,6 +16,13 @@ logger = logging.getLogger(__name__) _cache = {} +def get_source_object(obj): + if isinstance(obj, EncapsulatedObject): + return obj.source_object + else: + return obj + + class EncapsulatedObject(object): source_object_name = u'source_object' diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 5b772a4c86..e46082e2e9 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -13,7 +13,8 @@ from django.core.urlresolvers import reverse from common.models import AnonymousUserSingleton from permissions.models import Permission -from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder +from .classes import (EncapsulatedObject, AccessHolder, ClassAccessHolder, + get_source_object) logger = logging.getLogger(__name__) @@ -23,18 +24,12 @@ class AccessEntryManager(models.Manager): Implement a 3 tier permission system, involving a permissions, an actor and an object """ - def source_object(self, obj): - if isinstance(obj, EncapsulatedObject): - return obj.source_object - else: - return obj - def grant(self, permission, actor, obj): """ Grant a permission (what), (to) an actor, (on) a specific object """ - obj = self.source_object(obj) - actor = self.source_object(actor) + obj = get_source_object(obj) + actor = get_source_object(actor) access_entry, created = self.model.objects.get_or_create( permission=permission, @@ -49,8 +44,8 @@ class AccessEntryManager(models.Manager): """ Revoke a permission (what), (from) an actor, (on) a specific object """ - obj = self.source_object(obj) - actor = self.source_object(actor) + obj = get_source_object(obj) + actor = get_source_object(actor) try: access_entry = self.model.objects.get( @@ -60,17 +55,18 @@ class AccessEntryManager(models.Manager): content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk ) - access_entry.delete() - return True except self.model.DoesNotExist: return False + else: + access_entry.delete() + return True def has_access(self, permission, actor, obj): """ Returns whether an actor has a specific permission for an object """ - obj = self.source_object(obj) - actor = self.source_object(actor) + obj = get_source_object(obj) + actor = get_source_object(actor) if isinstance(actor, User): if actor.is_superuser or actor.is_staff: @@ -93,8 +89,8 @@ class AccessEntryManager(models.Manager): def check_access(self, permission, actor, obj): # TODO: Merge with has_access - obj = self.source_object(obj) - actor = self.source_object(actor) + obj = get_source_object(obj) + actor = get_source_object(actor) if self.has_access(permission, actor, obj): return True @@ -105,8 +101,8 @@ class AccessEntryManager(models.Manager): """ Returns whether an actor has at least one of a list of permissions for an object """ - obj = self.source_object(obj) - actor = self.source_object(actor) + obj = get_source_object(obj) + actor = get_source_object(actor) for permission in permission_list: if self.has_access(permission, actor, obj): return True @@ -211,7 +207,7 @@ class DefaultAccessEntryManager(models.Manager): content type is created. """ def get_holders_for(self, cls): - cls = AccessEntryManager.source_object(cls) + cls = get_source_object(cls) #if isinstance(cls, EncapsulatedObject): # cls = cls.source_object From 39f47702c0506d87617e78847f18b31b6488f340 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 20 Jan 2012 22:53:48 -0400 Subject: [PATCH 272/484] Finish the apply_default_acls function and enable it for document creation --- apps/acls/utils.py | 27 +++++++++++++++++++++++++++ apps/sources/models.py | 3 +++ 2 files changed, 30 insertions(+) create mode 100644 apps/acls/utils.py diff --git a/apps/acls/utils.py b/apps/acls/utils.py new file mode 100644 index 0000000000..4da462d7c7 --- /dev/null +++ b/apps/acls/utils.py @@ -0,0 +1,27 @@ +from __future__ import absolute_import + +from django.contrib.contenttypes.models import ContentType + +from .models import AccessEntry, DefaultAccessEntry, CreatorSingleton +from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder + + +def apply_default_acls(self, obj, actor=None): + if isinstance(obj, EncapsulatedObject): + obj = obj.source_object + + if actor: + actor = AnonymousUserSingleton.objects.passthru_check(actor) + #actor_type = ContentType.objects.get_for_model(actor) + + content_type = ContentType.objects.get_for_model(obj) + + for default_acl in DefaultAccessEntry.objects.filter(content_type=content_type): + holder = CreatorSingleton.objects.passthru_check(default_acl.holder_object, actor) + + access_entry = AccessEntry( + permission=default_acl.permission, + holder_object=holder, + content_object=obj, + ) + access_entry.save() diff --git a/apps/sources/models.py b/apps/sources/models.py index 52e828a4fe..d6a997daf9 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -17,6 +17,7 @@ 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 .managers import SourceTransformationManager from .literals import (SOURCE_CHOICES, SOURCE_CHOICES_PLURAL, @@ -76,6 +77,8 @@ class BaseModel(models.Model): document.document_type = document_type document.save() + apply_default_acls(document, document, user) + if metadata_dict_list: save_metadata_list(metadata_dict_list, document, create=True) warnings = update_indexes(document) From d1eb387c16e18d880109ffebc8465f89a485b685 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 20 Jan 2012 22:54:26 -0400 Subject: [PATCH 273/484] Start work on the creator pseudo class acl holder --- apps/acls/forms.py | 4 ++++ apps/acls/models.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index e5a55a006c..f4b7b0b4b7 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -45,3 +45,7 @@ class HolderSelectionForm(forms.Form): super(HolderSelectionForm, self).__init__(*args, **kwargs) self.fields['holder_gid'].choices = non_holder_list + + +class ClassHolderSelectionForm(HolderSelectionForm): + pass diff --git a/apps/acls/models.py b/apps/acls/models.py index a255348760..b5e7c2829b 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -11,6 +11,7 @@ from django.core.exceptions import PermissionDenied from django.core.exceptions import ObjectDoesNotExist from permissions.models import StoredPermission +from common.models import Singleton, SingletonManager from .managers import AccessEntryManager, DefaultAccessEntryManager from .classes import AccessObjectClass @@ -91,3 +92,22 @@ class DefaultAccessEntry(models.Model): def __unicode__(self): return u'%s: %s' % (self.content_type, self.content_object) + + +class CreatorSingletonManager(SingletonManager): + def passthru_check(self, holder, creator=None): + if isinstance(holder, self.model): + # TODO: raise explicit error if is instance and creator=None + return creator + else: + return holder + +class CreatorSingleton(Singleton): + objects = CreatorSingletonManager() + + def __unicode__(self): + return ugettext('Creator') + + class Meta: + verbose_name = _(u'creator') + verbose_name_plural = _(u'creator') From 70953882a7c7c73bbea360bf078ffd92393d63ee Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 21 Jan 2012 03:57:26 -0400 Subject: [PATCH 274/484] Implement ClassHolderSelectionForm and HolderSelectionForm forms Subclassed from BaseHolderSelectionForm --- apps/acls/forms.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index f4b7b0b4b7..3f2c048320 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -9,13 +9,14 @@ from common.utils import get_object_name from common.models import AnonymousUserSingleton from .classes import AccessHolder +from .models import CreatorSingleton def _as_choice_list(holders): return sorted([(AccessHolder.encapsulate(holder).gid, get_object_name(holder, display_object_type=False)) for holder in holders], key=lambda x: x[1]) -class HolderSelectionForm(forms.Form): +class BaseHolderSelectionForm(forms.Form): holder_gid = forms.ChoiceField( label=_(u'New holder') ) @@ -30,6 +31,7 @@ class HolderSelectionForm(forms.Form): users = set(User.objects.filter(is_active=True)) - set(staff_users) - set(super_users) - set(current_holders) roles = set(Role.objects.all()) - set(current_holders) groups = set(Group.objects.all()) - set(current_holders) + special = set(self.special_holders) - set(current_holders) non_holder_list = [] if users: @@ -41,11 +43,16 @@ class HolderSelectionForm(forms.Form): if roles: non_holder_list.append((_(u'Roles'), _as_choice_list(list(roles)))) - non_holder_list.append((_(u'Special'), _as_choice_list([AnonymousUserSingleton.objects.get()]))) + if special: + non_holder_list.append((_(u'Special'), _as_choice_list(list(special)))) - super(HolderSelectionForm, self).__init__(*args, **kwargs) + super(BaseHolderSelectionForm, self).__init__(*args, **kwargs) self.fields['holder_gid'].choices = non_holder_list + +class HolderSelectionForm(BaseHolderSelectionForm): + special_holders = [AnonymousUserSingleton.objects.get()] + -class ClassHolderSelectionForm(HolderSelectionForm): - pass +class ClassHolderSelectionForm(BaseHolderSelectionForm): + special_holders = [AnonymousUserSingleton.objects.get(), CreatorSingleton.objects.get()] From 95f56cbd5a66ff5dedaae6d6d697c4ad34cdcdb5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 21 Jan 2012 04:03:58 -0400 Subject: [PATCH 275/484] Enable default acls setup upon creation for documents, folders, tags and smart_links --- apps/acls/utils.py | 12 +++++++++--- apps/folders/views.py | 2 ++ apps/linking/views.py | 2 ++ apps/sources/models.py | 2 +- apps/tags/views.py | 2 ++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/acls/utils.py b/apps/acls/utils.py index 4da462d7c7..2d9c9a92e7 100644 --- a/apps/acls/utils.py +++ b/apps/acls/utils.py @@ -1,24 +1,30 @@ from __future__ import absolute_import +import logging + from django.contrib.contenttypes.models import ContentType +from common.models import AnonymousUserSingleton + from .models import AccessEntry, DefaultAccessEntry, CreatorSingleton from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder +logger = logging.getLogger(__name__) -def apply_default_acls(self, obj, actor=None): + +def apply_default_acls(obj, actor=None): + logger.debug('actor, init: %s' % actor) if isinstance(obj, EncapsulatedObject): obj = obj.source_object if actor: actor = AnonymousUserSingleton.objects.passthru_check(actor) - #actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(obj) for default_acl in DefaultAccessEntry.objects.filter(content_type=content_type): holder = CreatorSingleton.objects.passthru_check(default_acl.holder_object, actor) - + access_entry = AccessEntry( permission=default_acl.permission, holder_object=holder, diff --git a/apps/folders/views.py b/apps/folders/views.py index 0bd85d2790..3c4a494aa6 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -17,6 +17,7 @@ from permissions import Permission from common.utils import encapsulate from acls.models import AccessEntry from acls.views import acl_list_for +from acls.utils import apply_default_acls from .models import Folder from .forms import FolderForm, FolderListForm @@ -64,6 +65,7 @@ def folder_create(request): if form.is_valid(): folder, created = Folder.objects.get_or_create(user=request.user, title=form.cleaned_data['title']) if created: + apply_default_acls(folder, request.user) messages.success(request, _(u'Folder created successfully')) return HttpResponseRedirect(reverse('folder_list')) else: diff --git a/apps/linking/views.py b/apps/linking/views.py index 07e1d42351..2153e3c3fc 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -17,6 +17,7 @@ from documents.permissions import PERMISSION_DOCUMENT_VIEW from permissions.models import Permission from acls.views import acl_list_for from acls.models import AccessEntry, PermissionDenied +from acls.utils import apply_default_acls from .models import SmartLink, SmartLinkCondition from .conf.settings import SHOW_EMPTY_SMART_LINKS @@ -147,6 +148,7 @@ def smart_link_create(request): form = SmartLinkForm(request.POST) if form.is_valid(): document_group = form.save() + apply_default_acls(document_group, request.user) messages.success(request, _(u'Smart link: %s created successfully.') % document_group) return HttpResponseRedirect(reverse('document_group_list')) else: diff --git a/apps/sources/models.py b/apps/sources/models.py index d6a997daf9..d7fb8f7161 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -77,7 +77,7 @@ class BaseModel(models.Model): document.document_type = document_type document.save() - apply_default_acls(document, document, user) + apply_default_acls(document, user) if metadata_dict_list: save_metadata_list(metadata_dict_list, document, create=True) diff --git a/apps/tags/views.py b/apps/tags/views.py index 615c248829..712ecd86c9 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -17,6 +17,7 @@ from documents.permissions import PERMISSION_DOCUMENT_VIEW from common.utils import encapsulate from acls.models import AccessEntry, PermissionDenied from acls.views import acl_list_for, acl_new_holder_for +from acls.utils import apply_default_acls from .forms import TagListForm, TagForm from .models import TagProperties @@ -44,6 +45,7 @@ def tag_create(request): 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) From bf9073fdce79af5bb41cb50b6c5db037ec0fe2e6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 21 Jan 2012 04:04:13 -0400 Subject: [PATCH 276/484] Add creator content type icon --- apps/acls/literals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/acls/literals.py b/apps/acls/literals.py index 5d86e0a013..0b867021a9 100644 --- a/apps/acls/literals.py +++ b/apps/acls/literals.py @@ -9,4 +9,5 @@ CONTENT_TYPE_ICON_MAP = { 'taggit.tag': 'tag_blue', 'linking.smartlink': 'page_link', 'common.anonymoususersingleton': 'user', + 'acls.creatorsingleton': 'user', } From 7714e62e9720219015d99a347dbd89d5f87c2dbb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 21 Jan 2012 04:04:42 -0400 Subject: [PATCH 277/484] Display proper unicode result for anonymous user class and creator class --- apps/acls/classes.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/acls/classes.py b/apps/acls/classes.py index 2b4719dc95..89802566ea 100644 --- a/apps/acls/classes.py +++ b/apps/acls/classes.py @@ -102,7 +102,7 @@ class EncapsulatedObject(object): def __init__(self, source_object): self.content_type = ContentType.objects.get_for_model(source_object) - self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.name) + self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.model) if isinstance(source_object, ModelBase): # Class @@ -116,9 +116,12 @@ class EncapsulatedObject(object): def __unicode__(self): if isinstance(self.source_object, ModelBase): return capfirst(unicode(self.source_object._meta.verbose_name_plural)) - elif self.ct_fullname == 'auth.user': return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name()) + elif self.ct_fullname == 'common.anonymoususersingleton': + return unicode(self.source_object) + elif self.ct_fullname == 'acls.creatorsingleton': + return unicode(self.source_object) else: return u'%s %s' % (self.source_object._meta.verbose_name, self.source_object) From f37500b0b4dcd58d1eaae3b8bc54daeeedef3cdb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 21 Jan 2012 04:06:48 -0400 Subject: [PATCH 278/484] Allow returning on the db stored permissions --- apps/acls/managers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index e46082e2e9..1fe21cf231 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -61,14 +61,14 @@ class AccessEntryManager(models.Manager): access_entry.delete() return True - def has_access(self, permission, actor, obj): + def has_access(self, permission, actor, obj, db_only=False): """ Returns whether an actor has a specific permission for an object """ obj = get_source_object(obj) actor = get_source_object(actor) - if isinstance(actor, User): + if isinstance(actor, User) and db_only == False: if actor.is_superuser or actor.is_staff: return True @@ -144,7 +144,7 @@ class AccessEntryManager(models.Manager): return holder_list - def get_holder_permissions_for(self, obj, actor): + def get_holder_permissions_for(self, obj, actor, db_only=False): """ Returns a list of actors that hold at least one permission for a specific object @@ -152,7 +152,7 @@ class AccessEntryManager(models.Manager): logger.debug('obj: %s' % obj) logger.debug('actor: %s' % actor) - if isinstance(actor, User): + if isinstance(actor, User) and db_only == False: if actor.is_superuser or actor.is_staff: return Permission.objects.all() From ec461c4f9b70fe970592e46d1d21a4feb5ae94ee Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 21 Jan 2012 04:07:23 -0400 Subject: [PATCH 279/484] Update acl views to use encapsulated objects --- apps/acls/views.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index 45af37d086..cfd4fc046c 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -24,7 +24,7 @@ from .models import AccessEntry, DefaultAccessEntry from .classes import (AccessHolder, AccessObject, AccessObjectClass, ClassAccessHolder) from .widgets import object_w_content_type_icon -from .forms import HolderSelectionForm +from .forms import HolderSelectionForm, ClassHolderSelectionForm from .api import get_class_permissions_for logger = logging.getLogger(__name__) @@ -47,7 +47,7 @@ def acl_list_for(request, obj, extra_context=None): 'title': _(u'access control lists for: %s' % obj), 'extra_columns': [ {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, - {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object)))}, + {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object, db_only=True)))}, ], 'hide_object': True, 'access_object': AccessObject.encapsulate(obj), @@ -78,7 +78,8 @@ def acl_detail(request, access_object_gid, holder_object_gid): except ObjectDoesNotExist: raise Http404 - return acl_detail_for(request, holder.source_object, access_object.source_object) + #return acl_detail_for(request, holder.source_object, access_object.source_object) + return acl_detail_for(request, holder, access_object) def acl_detail_for(request, actor, obj): @@ -87,8 +88,7 @@ def acl_detail_for(request, actor, obj): except PermissionDenied: AccessEntry.objects.check_accesses([ACLS_VIEW_ACL], actor, obj) - permission_list = get_class_permissions_for(obj) - + permission_list = get_class_permissions_for(obj.source_object) #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { @@ -105,7 +105,7 @@ def acl_detail_for(request, actor, obj): {'name': _(u'label'), 'attribute': 'label'}, { 'name':_(u'has permission'), - 'attribute': encapsulate(lambda permission: two_state_template(AccessEntry.objects.has_access(permission, actor, obj))) + 'attribute': encapsulate(lambda permission: two_state_template(AccessEntry.objects.has_access(permission, actor, obj, db_only=True))) }, ], 'hide_object': True, @@ -114,15 +114,15 @@ def acl_detail_for(request, actor, obj): ] context = { - 'object': obj, + 'object': obj.source_object, 'subtemplates_list': subtemplates_list, 'multi_select_as_buttons': True, 'multi_select_item_properties': { 'permission_pk': lambda x: x.pk, - 'holder_gid': lambda x: AccessHolder(actor).gid, - 'object_gid': lambda x: AccessObject(obj).gid, + 'holder_gid': lambda x: actor.gid, + 'object_gid': lambda x: obj.gid, }, - 'access_object': AccessObject.encapsulate(obj), + 'access_object': obj, 'navigation_object_list': [ {'object': 'object'}, {'object': 'access_object'} @@ -425,7 +425,6 @@ def acl_class_acl_detail(request, access_object_class_gid, holder_object_gid): except ObjectDoesNotExist: raise Http404 - #permission_list = list(access_object_class.get_class_permissions()) permission_list = get_class_permissions_for(access_object_class.content_type.model_class()) #TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ @@ -468,7 +467,7 @@ def acl_class_new_holder_for(request, access_object_class_gid): access_object_class = AccessObjectClass.get(gid=access_object_class_gid) if request.method == 'POST': - form = HolderSelectionForm(request.POST) + form = ClassHolderSelectionForm(request.POST) if form.is_valid(): try: access_holder = ClassAccessHolder.get(form.cleaned_data['holder_gid']) @@ -477,7 +476,7 @@ def acl_class_new_holder_for(request, access_object_class_gid): except ObjectDoesNotExist: raise Http404 else: - form = HolderSelectionForm(current_holders=DefaultAccessEntry.objects.get_holders_for(access_object_class)) + form = ClassHolderSelectionForm(current_holders=DefaultAccessEntry.objects.get_holders_for(access_object_class)) context = { 'form': form, From 2bfa30a59e93a8f988a48e2047b397fe68dec937 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 22 Jan 2012 05:44:08 -0400 Subject: [PATCH 280/484] Fix indentation from tab to spaces --- apps/ocr/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index f228843100..ba0892273b 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -77,10 +77,10 @@ def document_post_save(sender, instance, **kwargs): logger.debug('instance: %s' % instance) if kwargs.get('created', False): if AUTOMATIC_OCR: - try: - DocumentQueue.objects.queue_document(instance.document) - except AlreadyQueued: - pass + try: + DocumentQueue.objects.queue_document(instance.document) + except AlreadyQueued: + pass # Disabled because it appears Django execute signals using the same From c6fe73939a52b129bf8dd0e1126ffe544ef66c7a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 23 Jan 2012 19:20:19 -0400 Subject: [PATCH 281/484] Ignore database errors during the syncdb phase --- apps/history/api.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/history/api.py b/apps/history/api.py index 04e212d3a2..6bb8e42322 100644 --- a/apps/history/api.py +++ b/apps/history/api.py @@ -7,6 +7,7 @@ from django.db import transaction from django.core import serializers from django.shortcuts import get_object_or_404 from django.db import models +from django.db.utils import DatabaseError from .models import HistoryType, History from .runtime_data import history_types_dict @@ -17,9 +18,13 @@ def register_history_type(history_type_dict): namespace = history_type_dict['namespace'] name = history_type_dict['name'] - history_type_obj, created = HistoryType.objects.get_or_create( - namespace=namespace, name=name) - history_type_obj.save() + try: + history_type_obj, created = HistoryType.objects.get_or_create( + namespace=namespace, name=name) + history_type_obj.save() + except DatabaseError: + # Special case for syncdb + pass # Runtime history_types_dict.setdefault(namespace, {}) From 8d3824ea51e3fc188192003a8f139d245d5139d7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 23 Jan 2012 19:20:37 -0400 Subject: [PATCH 282/484] Only try create the defautl OCR queue after the database has been created --- apps/ocr/__init__.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index ba0892273b..668e20b4b6 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -5,7 +5,7 @@ import logging from django.db import transaction from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext -from django.db.models.signals import post_save +from django.db.models.signals import post_save, post_syncdb from django.dispatch import receiver from navigation.api import register_links, register_multi_item_links @@ -23,6 +23,7 @@ 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__) @@ -77,11 +78,10 @@ def document_post_save(sender, instance, **kwargs): logger.debug('instance: %s' % instance) if kwargs.get('created', False): if AUTOMATIC_OCR: - try: - DocumentQueue.objects.queue_document(instance.document) - except AlreadyQueued: - pass - + try: + DocumentQueue.objects.queue_document(instance.document) + except AlreadyQueued: + pass # Disabled because it appears Django execute signals using the same # process of the signal emiter effectively blocking the view until @@ -92,7 +92,9 @@ def document_post_save(sender, instance, **kwargs): # logger.debug('got call_queue signal: %s' % kwargs) # task_process_document_queues() -create_default_queue() +@receiver(post_syncdb, dispatch_uid='create_default_queue', sender=ocr_models) +def create_default_queue_signal_handler(sender, **kwargs): + create_default_queue() register_interval_job('task_process_document_queues', _(u'Checks the OCR queue for pending documents.'), task_process_document_queues, seconds=QUEUE_PROCESSING_INTERVAL) From d9aa63f8ca24caf2308506903a935f322f42be1f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 23 Jan 2012 20:00:39 -0400 Subject: [PATCH 283/484] Remove Sentry and celery from Mayan EDMS --- apps/job_processor/api.py | 13 +------------ apps/job_processor/conf/settings.py | 12 ------------ apps/ocr/views.py | 1 - contrib/supervisor/mayan-celery.conf | 23 ----------------------- contrib/supervisor/mayan-celerybeat.conf | 19 ------------------- docs/credits.rst | 8 -------- docs/requirements.rst | 6 ------ docs/settings.rst | 11 ----------- requirements/development.txt | 3 --- requirements/production.txt | 3 --- settings.py | 18 ------------------ urls.py | 1 - 12 files changed, 1 insertion(+), 117 deletions(-) delete mode 100644 apps/job_processor/conf/settings.py delete mode 100644 contrib/supervisor/mayan-celery.conf delete mode 100644 contrib/supervisor/mayan-celerybeat.conf diff --git a/apps/job_processor/api.py b/apps/job_processor/api.py index eee19321b1..781edbe5bc 100644 --- a/apps/job_processor/api.py +++ b/apps/job_processor/api.py @@ -1,16 +1,5 @@ -from celery.decorators import task, periodic_task -from celery.task.control import inspect - from job_processor.conf.settings import BACKEND -@task -def celery_task(func, *args, **kwargs): - return func(*args, **kwargs) - - def process_job(func, *args, **kwargs): - if BACKEND == 'celery': - return celery_task.delay(func, *args, **kwargs) - elif BACKEND is None: - return func(*args, **kwargs) + return func(*args, **kwargs) diff --git a/apps/job_processor/conf/settings.py b/apps/job_processor/conf/settings.py deleted file mode 100644 index 0d3b2fe9ea..0000000000 --- a/apps/job_processor/conf/settings.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Configuration options for the job_processing app""" -from django.utils.translation import ugettext_lazy as _ - -from smart_settings.api import register_settings - -register_settings( - namespace=u'job_processor', - module=u'job_processor.conf.settings', - settings=[ - {'name': u'BACKEND', 'global_name': u'JOB_PROCESSING_BACKEND', 'default': None, 'description': _('Specified which job processing library to use, option are: None and celery.')}, - ] -) diff --git a/apps/ocr/views.py b/apps/ocr/views.py index 52e0fc9eb4..7083fb817c 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -11,7 +11,6 @@ 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.models import Permission from documents.models import Document from documents.widgets import document_link, document_thumbnail 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/credits.rst b/docs/credits.rst index e0b3e815d6..e7d8e4a3a9 100644 --- a/docs/credits.rst +++ b/docs/credits.rst @@ -75,14 +75,6 @@ Credits * 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 diff --git a/docs/requirements.rst b/docs/requirements.rst index 665b9ba641..4b4cf9b00d 100644 --- a/docs/requirements.rst +++ b/docs/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/settings.rst b/docs/settings.rst index d27a0bb0ac..d39e9ca68a 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -179,17 +179,6 @@ Storage Default: ``document_storage`` - -Job processor -------------- - -.. data:: JOB_PROCESSING_BACKEND - - Default: ``None`` - - - Specifies which job processing library to use, option are: None and celery. - Document indexing ----------------- diff --git a/requirements/development.txt b/requirements/development.txt index 7cb6556ead..57f5c5272f 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -4,9 +4,6 @@ django-extensions==0.7.1 django-pagination==1.0.7 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 diff --git a/requirements/production.txt b/requirements/production.txt index cc3232892b..f8408ec634 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 diff --git a/settings.py b/settings.py index 1944232ed5..08221cb2fd 100644 --- a/settings.py +++ b/settings.py @@ -18,7 +18,6 @@ DEVELOPMENT = False TEMPLATE_DEBUG = False ADMINS = () -SENTRY_ADMINS = ('root@localhost',) MANAGERS = ADMINS DATABASES = { @@ -141,12 +140,6 @@ INSTALLED_APPS = ( 'filetransfers', 'acls', 'converter', - 'djcelery', - 'indexer', - 'paging', - 'sentry', - 'sentry.client', - 'sentry.client.celery', 'storage', 'folders', 'document_comments', @@ -278,18 +271,7 @@ COMPRESS_ENABLED=False #------------ 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 ------------------- diff --git a/urls.py b/urls.py index 4f88bbff7d..c125b3676d 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')), From 063cc063252f87d9f4956632d94e321b2d4591ee Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 23 Jan 2012 20:03:09 -0400 Subject: [PATCH 284/484] Remove unused import --- apps/job_processor/api.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/job_processor/api.py b/apps/job_processor/api.py index 781edbe5bc..00b9736fef 100644 --- a/apps/job_processor/api.py +++ b/apps/job_processor/api.py @@ -1,5 +1,2 @@ -from job_processor.conf.settings import BACKEND - - def process_job(func, *args, **kwargs): return func(*args, **kwargs) From 808b9488f5ff416638da5751ec3bcd1e2bed5398 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 01:50:06 -0400 Subject: [PATCH 285/484] Updated contributors file --- docs/contributors.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/contributors.rst b/docs/contributors.rst index df1edfa199..e05f8375bc 100644 --- a/docs/contributors.rst +++ b/docs/contributors.rst @@ -15,6 +15,7 @@ Bug fixes * 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,6 +26,8 @@ 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 ------- @@ -36,6 +39,7 @@ 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 ------------ @@ -46,3 +50,12 @@ Translations * Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Italian * SeeOpen.IT (Numero Verde: 800.910.125, E-mail: sales@seeopen.it) + +Remote access for debugging +--------------------------- +* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) +* David Herring (https://github.com/abadger1406) + +Monetary donations +------------------ +* David Herring (https://github.com/abadger1406) From 5a61de3dc4198fe8664bc48273515b3a3a1b4255 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 01:50:26 -0400 Subject: [PATCH 286/484] Updated changelog --- docs/changelog.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4a37902165..1f66818ea6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,8 @@ Version 0.12 ------------ +* Fixed issue #17, special thanks to Dave Herring for all the help including + access to a machine suffering with the issue +* Remove Celery and Sentry from the requirements * Removal of the OCR_CACHE_URI configuration option * Upgrade commands: @@ -18,7 +21,7 @@ If you're unsure, answer 'no'. Type 'yes' to continue, or 'no' to cancel: yes """ * ./manage.py migrate documents - + * ./manage.py migrate document_signatures * Added new configuration option COMMON_ALLOW_ANONYMOUS_ACCESS to allow non authenticated access. From a63b6e2039d4a7da81c6ceb79f8e7a9702934188 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 01:50:47 -0400 Subject: [PATCH 287/484] Reorganized app loading order --- settings.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/settings.py b/settings.py index 08221cb2fd..98a94a20b2 100644 --- a/settings.py +++ b/settings.py @@ -117,6 +117,7 @@ TEMPLATE_DIRS = ( ) INSTALLED_APPS = ( +#Django 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', @@ -126,6 +127,17 @@ INSTALLED_APPS = ( 'django.contrib.admindocs', 'django.contrib.comments', 'django.contrib.staticfiles', +# 3rd party +# South + 'south', +# Others + 'filetransfers', + 'taggit', + 'mptt', + 'compressor', + 'djangorestframework', + 'pagination', +# Base generic 'permissions', 'project_setup', 'project_tools', @@ -135,34 +147,28 @@ INSTALLED_APPS = ( 'web_theme', 'common', 'django_gpg', - 'pagination', 'dynamic_search', - 'filetransfers', 'acls', 'converter', + 'user_management', + 'mimetype', + 'scheduler', + 'job_processor', +# Mayan EDMS 'storage', 'folders', + 'tags', 'document_comments', - 'user_management', 'metadata', 'documents', - 'taggit', - 'tags', 'linking', - 'mptt', 'document_indexing', 'document_acls', 'ocr', 'sources', - 'mimetype', - 'scheduler', - 'job_processor', 'history', 'main', - 'compressor', - 'djangorestframework', 'rest_api', - 'south', 'document_signatures', ) From c48d158581fe4ae5fead18dac49f2f26f6067fca Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 01:51:12 -0400 Subject: [PATCH 288/484] Change the documentation structure to be more like Django's one --- docs/index.rst | 1 + docs/releases/0.12.rst | 73 +++++++++++++++++++++++++++++++++++++++++ docs/releases/index.rst | 31 +++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 docs/releases/0.12.rst create mode 100644 docs/releases/index.rst diff --git a/docs/index.rst b/docs/index.rst index 5c115df121..c94cf64484 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -40,6 +40,7 @@ Contents features requirements installation + releases/index settings updates development diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst new file mode 100644 index 0000000000..3cb27b57b1 --- /dev/null +++ b/docs/releases/0.12.rst @@ -0,0 +1,73 @@ +======================== +Mayan EDMS 0.12 release notes +======================== + +*February 2012* + +Welcome to Mayan EDMS 0.12! + +This release commemorates **Mayan EDMS** first aniversary! + +Overview +======== + +**Mayan EDMS** focus has mostly been on improving the code 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. + +What's new in Django 1.3 +======================== + +ACL support +~~~~~~~~~~~ + +Anonymous user support +~~~~~~~~~~~~~~~~~~~~~~ + + +Italian translation +~~~~~~~~~~~~~~~~~~~ + +Usability improvements +~~~~~~~~~~~~~~~~~~~~~~ + + +Upgrading +========= + +:: + + $ ./manage.py syncdb + $ ./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:`` + + Types ``yes`` and press **Enter** + +:: + + $ ./manage.py migrate documents + $ ./manage.py migrate document_signatures + + +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. diff --git a/docs/releases/index.rst b/docs/releases/index.rst new file mode 100644 index 0000000000..7f8ca647e4 --- /dev/null +++ b/docs/releases/index.rst @@ -0,0 +1,31 @@ +============= +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. + +Final releases +============== + + +0.12 release +----------- +.. toctree:: + :maxdepth: 1 + + 0.12 + +0.11 release +----------- +.. toctree:: + :maxdepth: 1 + + 0.11.1 + 0.11 From 4eaf4bd78531835822f6740c758c1660e1f81043 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 12:13:19 -0400 Subject: [PATCH 289/484] Add cancel button and previous hidden variable support to the generic form template --- apps/common/templates/generic_form_subtemplate.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/common/templates/generic_form_subtemplate.html b/apps/common/templates/generic_form_subtemplate.html index e502d78fd6..37eeee5db4 100644 --- a/apps/common/templates/generic_form_subtemplate.html +++ b/apps/common/templates/generic_form_subtemplate.html @@ -35,6 +35,10 @@ {% endif %} + {% if previous %} + + {% endif %} + {% for hidden_field in hidden_fields %} {{ hidden_field.as_hidden }} {% endfor %} @@ -77,6 +81,13 @@ {% endif %} {% if submit_label %}{{ submit_label }}{% else %}{% if object %}{% trans "Save" %}{% else %}{% trans "Submit" %}{% endif %}{% endif %} + + {% if previous %} + + {% if cancel_label %}{{ cancel_label }}{% else %}{% trans 'Cancel' %}{% endif %} {% if cancel_label %}{{ cancel_label }}{% else %}{% trans "Cancel" %}{% endif %} + + {% endif %} + {% comment %} {% trans 'Cancel' %} {% trans 'Cancel' %} From e44ef229b0ce62a81cea7ef40e5e136fd9caa686 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 12:13:53 -0400 Subject: [PATCH 290/484] Improve single, multiple document and document versions downloads By using a 2 step document download view --- apps/documents/forms.py | 13 ++++ apps/documents/views.py | 132 ++++++++++++++++++++++++++-------------- 2 files changed, 99 insertions(+), 46 deletions(-) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 398e9f59ae..62bd3fa00d 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -312,3 +312,16 @@ class DocumentTypeFilenameForm_create(forms.ModelForm): class Meta: model = DocumentTypeFilename fields = ('filename',) + + +class DocumentDownloadForm(forms.Form): + compressed = forms.BooleanField(label=_(u'Compress'), required=False, help_text=_(u'Download the document in the original format or in a compressed manner. This option is selectable only when downloading one document, for multiple documents, the bundle will always be downloads as a compressed file.')) + + def __init__(self, *args, **kwargs): + self.document_versions = kwargs.pop('document_versions', None) + super(DocumentDownloadForm, self).__init__(*args, **kwargs) + if len(self.document_versions) > 1: + self.fields['compressed'].initial = True + self.fields['compressed'].widget.attrs.update({'disabled': True}) + + diff --git a/apps/documents/views.py b/apps/documents/views.py index c33554edc1..af77a2f1aa 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -52,7 +52,7 @@ from .forms import (DocumentTypeSelectForm, DocumentPageTransformationForm, DocumentContentForm, DocumentPageForm_edit, DocumentPageForm_text, PrintForm, DocumentTypeForm, DocumentTypeFilenameForm, - DocumentTypeFilenameForm_create) + DocumentTypeFilenameForm_create, DocumentDownloadForm) from .wizards import DocumentCreateWizard from .models import (Document, DocumentType, DocumentPage, DocumentPageTransformation, RecentDocument, DocumentTypeFilename, @@ -320,65 +320,105 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F def document_download(request, document_id=None, document_id_list=None, document_version_pk=None): - document_version = None - documents = [] + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) if document_id: - documents = [get_object_or_404(Document, pk=document_id)] - post_action_redirect = reverse('document_list') + document_versions = [get_object_or_404(Document, pk=document_id).latest_version] elif document_id_list: - documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] + document_versions = [get_object_or_404(Document, pk=document_id).latest_version for document_id in document_id_list.split(',')] elif document_version_pk: - document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) + document_versions = [get_object_or_404(DocumentVersion, pk=document_version_pk)] try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) except PermissionDenied: - documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DOWNLOAD, request.user, documents, exception_on_empty=True) + document_versions = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DOWNLOAD, request.user, document_versions, related='document', exception_on_empty=True) - if len(documents) == 1: - document_version = documents[0].latest_version + subtemplates_list = [] + subtemplates_list.append( + { + 'name': 'generic_list_subtemplate.html', + 'context': { + 'title': _(u'documents to be downloaded'), + 'object_list': document_versions, + 'hide_link': True, + 'hide_object': True, + 'hide_links': True, + 'navigation_object_links': None, + 'scrollable_content': True, + 'scrollable_content_height': '200px', + 'extra_columns': [ + {'name': _(u'document'), 'attribute': 'document'}, + {'name': _(u'version'), 'attribute': encapsulate(lambda x: x.get_formated_version())}, + ], + } + } + ) - if document_version: - try: - # Test permissions and trigger exception - fd = document_version.open() - fd.close() - return serve_file( - request, - document_version.file, - save_as=u'"%s"' % document_version.filename, - content_type=document_version.mimetype if document_version.mimetype else 'application/octet-stream' - ) - except Exception, e: - if settings.DEBUG: - raise + if request.method == 'POST': + form = DocumentDownloadForm(request.POST, document_versions=document_versions) + if form.is_valid(): + if form.cleaned_data['compressed'] or len(document_versions) > 1: + try: + compressed_file = CompressedFile() + for document_version in document_versions: + descriptor = document_version.open() + compressed_file.add_file(descriptor, arcname=document_version.filename) + descriptor.close() + + compressed_file.close() + + return serve_file( + request, + compressed_file.as_file('document_bundle.zip'), + save_as=u'"document_bundle.zip"', + content_type='application/zip' + ) + # TODO: DO a redirection afterwards + except Exception, e: + if settings.DEBUG: + raise + else: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) else: - messages.error(request, e) - return HttpResponseRedirect(request.META['HTTP_REFERER']) + try: + # Test permissions and trigger exception + fd = document_versions[0].open() + fd.close() + return serve_file( + request, + document_versions[0].file, + save_as=u'"%s"' % document_versions[0].filename, + content_type=document_versions[0].mimetype if document_versions[0].mimetype else 'application/octet-stream' + ) + except Exception, e: + if settings.DEBUG: + raise + else: + messages.error(request, e) + return HttpResponseRedirect(request.META['HTTP_REFERER']) + else: - try: - compressed_file = CompressedFile() - for document in documents: - descriptor = document.open() - compressed_file.add_file(descriptor, arcname=document.filename) - descriptor.close() + form = DocumentDownloadForm(document_versions=document_versions) - compressed_file.close() + context = { + 'form': form, + 'subtemplates_list': subtemplates_list, + 'title': _(u'Download documents'), + 'submit_label': _(u'Download'), + 'previous': previous, + 'cancel_label': _(u'Return'), + } - return serve_file( - request, - compressed_file.as_file('document_bundle.zip'), - save_as=u'"document_bundle.zip"', - content_type='application/zip' - ) - # TODO: DO a redirection afterwards - except Exception, e: - if settings.DEBUG: - raise - else: - messages.error(request, e) - return HttpResponseRedirect(request.META['HTTP_REFERER']) + if len(document_versions) == 1: + context['object'] = document_versions[0].document + + return render_to_response( + 'generic_form.html', + context, + context_instance=RequestContext(request) + ) def document_multiple_download(request): From c88777cbc8d75e19880c0677c09fb0cdc405f4d2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 12:57:31 -0400 Subject: [PATCH 291/484] Release notes updates --- docs/changelog.rst | 59 ---------------------------- docs/index.rst | 1 - docs/releases/0.12.rst | 86 +++++++++++++++++++++++++++++++++++------ docs/releases/index.rst | 9 ++--- 4 files changed, 77 insertions(+), 78 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 1f66818ea6..0a8a36c649 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,62 +1,3 @@ -Version 0.12 ------------- -* Fixed issue #17, special thanks to Dave Herring for all the help including - access to a machine suffering with the issue -* Remove Celery and Sentry from the requirements -* Removal of the OCR_CACHE_URI configuration option -* Upgrade commands: - - * ./manage.py syncdb - * ./manage.py migrate permissions 0001 --fake - * ./manage.py migrate permissions - """ -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: yes - """ - * ./manage.py migrate documents - * ./manage.py migrate document_signatures - -* Added new configuration option COMMON_ALLOW_ANONYMOUS_ACCESS to allow - non authenticated access. -* Navigation improvements. -* Statistics fixes. -* ACL support for documents, folders, tags and smart links. -* Anonymous user support for the permissions system. -* 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 - option groups -* Fixed get_image_cache_name regression in the OCR app -* Italian translation by SeeOpen.IT (www.seeopen.it, info@seeopen.it) -* Removed the 'db_index' argument from Text fields definition and - migrations as it was causing error messages for MySQL users. -* 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. - Version 0.11.1 -------------- * Fixed a document deletion regression diff --git a/docs/index.rst b/docs/index.rst index c94cf64484..25e1ca5039 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -42,7 +42,6 @@ Contents installation releases/index settings - updates development contributors credits diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 3cb27b57b1..f8ccfd25eb 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -1,39 +1,86 @@ ======================== -Mayan EDMS 0.12 release notes +Mayan EDMS v0.12 release notes ======================== *February 2012* -Welcome to Mayan EDMS 0.12! +Welcome to Mayan EDMS v0.12! This release commemorates **Mayan EDMS** first aniversary! Overview ======== -**Mayan EDMS** focus has mostly been on improving the code quality standard +Aside from new features, the focus of this release of **Mayan EDMS** also +been about improving the code 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. +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: -What's new in Django 1.3 -======================== +* 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. +* 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 COMMON_ALLOW_ANONYMOUS_ACCESS that allows non authenticated 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. - -Italian translation +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 Сергей Глита. 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. + Upgrading ========= @@ -60,7 +107,7 @@ If you're unsure, answer 'no'. :: - $ ./manage.py migrate documents + $ ./manage.py migrate documents $ ./manage.py migrate document_signatures @@ -71,3 +118,18 @@ 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 +* Statistics fixes. +* Fixed get_image_cache_name regression in the OCR app + +Stuff removed +============= +* Removal of the OCR_CACHE_URI configuration option +* 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. diff --git a/docs/releases/index.rst b/docs/releases/index.rst index 7f8ca647e4..e944ce5a8d 100644 --- a/docs/releases/index.rst +++ b/docs/releases/index.rst @@ -22,10 +22,7 @@ Final releases 0.12 -0.11 release ------------ -.. toctree:: - :maxdepth: 1 +Historic releases +================= - 0.11.1 - 0.11 +.. include:: ../changelog.rst From 194a6b41f9fdf1414a3e3633ce71294f78d47760 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 24 Jan 2012 16:34:28 -0400 Subject: [PATCH 292/484] Fix redirect view name --- apps/linking/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/linking/views.py b/apps/linking/views.py index 2153e3c3fc..538badd895 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -150,7 +150,7 @@ def smart_link_create(request): document_group = form.save() apply_default_acls(document_group, request.user) messages.success(request, _(u'Smart link: %s created successfully.') % document_group) - return HttpResponseRedirect(reverse('document_group_list')) + return HttpResponseRedirect(reverse('smart_link_list')) else: form = SmartLinkForm() @@ -173,7 +173,7 @@ def smart_link_edit(request, smart_link_pk): if form.is_valid(): smart_link = form.save() messages.success(request, _(u'Smart link: %s edited successfully.') % smart_link) - return HttpResponseRedirect(reverse('document_group_list')) + return HttpResponseRedirect(reverse('smart_link_list')) else: form = SmartLinkForm(instance=smart_link) From c0ebff580ab99470654364e5e4995773aa73ef8c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 01:13:48 -0400 Subject: [PATCH 293/484] Add libapache2-mod-xsendfile installation step --- docs/faq.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/faq.rst b/docs/faq.rst index 2a125b02e1..43392409e2 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -109,6 +109,9 @@ Site search is slow 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:: From c56a67e33aa49c1d15428fffa812e9433a467852 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:01:19 -0400 Subject: [PATCH 294/484] Update website address in about view --- apps/main/templates/project_description.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/main/templates/project_description.html b/apps/main/templates/project_description.html index aac2662fd8..32aca2bb75 100644 --- a/apps/main/templates/project_description.html +++ b/apps/main/templates/project_description.html @@ -6,7 +6,7 @@ {% trans "Open source, Django based electronic document manager with custom metadata, indexing, tagging, file serving integration and OCR capabilities" %}

    - http://bit.ly/mayan-edms + http://bit.ly/mayan-edms

    http://www.github.com/rosarior/mayan/ From e7a2aed6a0f510e113293c3eac35afd4fd5edf50 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:17:04 -0400 Subject: [PATCH 295/484] Silence HTML validator --- apps/smart_settings/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/smart_settings/views.py b/apps/smart_settings/views.py index 2db39a143e..a08872d053 100644 --- a/apps/smart_settings/views.py +++ b/apps/smart_settings/views.py @@ -30,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'])), From 4fe7803ff10cf260a695674ac1c37f24758edeaf Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:17:17 -0400 Subject: [PATCH 296/484] Make GPG key import errors more verbose --- apps/django_gpg/api.py | 2 +- apps/django_gpg/views.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 7e188f8d4c..5b5d06fd8f 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -341,4 +341,4 @@ class GPG(object): if import_result: return Key.get(self, import_result.fingerprints[0], secret=False) - raise KeyImportError + raise KeyImportError(import_result.results[0].get('text', 'Unknown error')) diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index e3dcd4981e..09a74d0a4d 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -37,8 +37,15 @@ def key_receive(request, key_id): key = gpg.import_key(keys_dict[key_id].key) messages.success(request, _(u'Key: %s, imported successfully.') % key) return HttpResponseRedirect(next) - except (KeyImportError, KeyError, TypeError): - messages.error(request, _(u'Unable to import key id: %s') % key_id) + except (KeyImportError, KeyError, TypeError), e: + messages.error( + request, + _(u'Unable to import key id: %(key_id)s; %(error)s') % + { + 'key_id': key_id, + 'error': e, + } + ) return HttpResponseRedirect(previous) return render_to_response('generic_confirm.html', { From 0e87b5dc56135ec7705c229849f909f35aeb2584 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:26:49 -0400 Subject: [PATCH 297/484] Return raw gpg error result --- apps/django_gpg/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 5b5d06fd8f..21b41df4fd 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -341,4 +341,4 @@ class GPG(object): if import_result: return Key.get(self, import_result.fingerprints[0], secret=False) - raise KeyImportError(import_result.results[0].get('text', 'Unknown error')) + raise KeyImportError(import_result.results) From af04f532adcddda4c63bd05b5012ac4da9a59718 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:43:31 -0400 Subject: [PATCH 298/484] Add SIGNATURES_GPG_HOME configuration option --- .gitignore | 1 + apps/django_gpg/conf/settings.py | 5 +++-- apps/django_gpg/runtime.py | 4 ++-- docs/releases/0.12.rst | 8 +++++++- docs/settings.rst | 7 +++++++ 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c6ebd3a9d5..6a625abb94 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ misc/mayan.geany image_cache/ build/ _build/ +gpg_home/ diff --git a/apps/django_gpg/conf/settings.py b/apps/django_gpg/conf/settings.py index 696447b94a..03e5a8d622 100644 --- a/apps/django_gpg/conf/settings.py +++ b/apps/django_gpg/conf/settings.py @@ -1,6 +1,6 @@ -''' +""" Configuration options for the django_gpg app -''' +""" from django.utils.translation import ugettext_lazy as _ @@ -11,5 +11,6 @@ register_settings( module=u'django_gpg.conf.settings', settings=[ {'name': u'KEYSERVERS', 'global_name': u'SIGNATURES_KEYSERVERS', 'default': ['pool.sks-keyservers.net'], 'description': _(u'List of keyservers to be queried for unknown keys.')}, + {'name': u'GPG_HOME', 'global_name': u'SIGNATURES_GPG_HOME', 'default': 'gpg_home', 'description': _(u'Home directory used to store keys as well as configuration files.')}, ] ) diff --git a/apps/django_gpg/runtime.py b/apps/django_gpg/runtime.py index b3303059ff..545dc106c7 100644 --- a/apps/django_gpg/runtime.py +++ b/apps/django_gpg/runtime.py @@ -1,4 +1,4 @@ from django_gpg.api import GPG -from django_gpg.conf.settings import KEYSERVERS +from django_gpg.conf.settings import KEYSERVERS, GPG_HOME -gpg = GPG(keyservers=KEYSERVERS) +gpg = GPG(home=GPG_HOME, keyservers=KEYSERVERS) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index f8ccfd25eb..e00b715aa4 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -80,7 +80,13 @@ 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 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. + Upgrading ========= diff --git a/docs/settings.rst b/docs/settings.rst index d39e9ca68a..3b1fc65f25 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -412,3 +412,10 @@ Signatures Default: ``['pool.sks-keyservers.net']`` List of keyservers to be queried for unknown keys. + + +.. data:: SIGNATURES_GPG_HOME + + Default: ``gpg_home`` + + Home directory used to store keys as well as configuration files. From 7495026d69f10ee83caa6ab3836d0b5cf6e5c30e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:55:25 -0400 Subject: [PATCH 299/484] Display error on stderr and fallback to system default home on GPG initialization error --- apps/django_gpg/runtime.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/django_gpg/runtime.py b/apps/django_gpg/runtime.py index 545dc106c7..afb5d73867 100644 --- a/apps/django_gpg/runtime.py +++ b/apps/django_gpg/runtime.py @@ -1,4 +1,13 @@ -from django_gpg.api import GPG -from django_gpg.conf.settings import KEYSERVERS, GPG_HOME +from __future__ import absolute_import -gpg = GPG(home=GPG_HOME, keyservers=KEYSERVERS) +import sys + +from .api import GPG +from .conf.settings import KEYSERVERS, GPG_HOME + +try: + gpg = GPG(home=GPG_HOME, keyservers=KEYSERVERS) +except Exception, e: + gpg = GPG(keyservers=KEYSERVERS) + sys.stderr.write(u'ERROR: GPG initialization error: %s\n' % e) + sys.stderr.write(u'INFO: Initializating GPG with system default home\n') From 7eff8b77fcea4318fe5b933da54c865ba24db049 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:55:58 -0400 Subject: [PATCH 300/484] Show simple error messages when debug is True and debugging tools are not found --- settings.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/settings.py b/settings.py index 98a94a20b2..457d8dc732 100644 --- a/settings.py +++ b/settings.py @@ -324,22 +324,19 @@ if DEVELOPMENT: import rosetta INSTALLED_APPS += ('rosetta',) except ImportError: - #print 'rosetta is not installed' - pass + sys.stderr.write('DEBUG: rosetta is not installed\n') try: import django_extensions INSTALLED_APPS += ('django_extensions',) except ImportError: - #print 'django_extensions is not installed' - pass + sys.stderr.write('DEBUG: django_extensions is not installed\n') try: import debug_toolbar #INSTALLED_APPS +=('debug_toolbar',) except ImportError: - #print 'debug_toolbar is not installed' - pass + sys.stderr.write('DEBUG: debug_toolbar is not installed\n') TEMPLATE_CONTEXT_PROCESSORS += ('django.core.context_processors.debug',) From 8ce5c2594973c3ea2fde4b7f3156d74c028bd4f1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 02:58:01 -0400 Subject: [PATCH 301/484] Only list development tools in the development requirements file --- requirements/development.txt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/requirements/development.txt b/requirements/development.txt index 57f5c5272f..3f7ac40b11 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -1,21 +1,3 @@ -Django==1.3.1 Werkzeug==0.6.2 django-extensions==0.7.1 -django-pagination==1.0.7 django-rosetta==0.6.2 -wsgiref==0.1.2 -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 From 7276a111719335257708b65f700eeffedf289b9c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 03:05:18 -0400 Subject: [PATCH 302/484] Fix website address --- apps/main/templates/project_description.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/main/templates/project_description.html b/apps/main/templates/project_description.html index 32aca2bb75..8eb85f32d3 100644 --- a/apps/main/templates/project_description.html +++ b/apps/main/templates/project_description.html @@ -6,7 +6,7 @@ {% trans "Open source, Django based electronic document manager with custom metadata, indexing, tagging, file serving integration and OCR capabilities" %}

    - http://bit.ly/mayan-edms + http://www.mayan-edms.com

    http://www.github.com/rosarior/mayan/ From aa1ea252d83a4b24bcedb683563322a5fcb67a57 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 04:27:38 -0400 Subject: [PATCH 303/484] Remove Changelog view in the about menu, add documentation link to the about template --- apps/common/__init__.py | 3 +-- apps/common/forms.py | 5 ----- apps/common/urls.py | 1 - apps/common/views.py | 17 ++--------------- apps/main/templates/project_description.html | 3 +++ docs/releases/0.12.rst | 4 ++-- 6 files changed, 8 insertions(+), 25 deletions(-) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index 928a5d36b7..bc663d91d9 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -24,10 +24,9 @@ current_user_edit = {'text': _(u'edit details'), 'view': 'current_user_edit', 'f register_links(['current_user_details', 'current_user_edit', 'password_change_view'], [current_user_details, current_user_edit, password_change_view], menu_name='secondary_menu') about_view = {'text': _('about'), 'view': 'about_view', 'famfam': 'information'} -changelog_view = {'text': _('changelog'), 'view': 'changelog_view', 'famfam': 'book_open'} license_view = {'text': _('license'), 'view': 'license_view', 'famfam': 'script'} -register_links(['about_view', 'changelog_view', 'license_view'], [about_view, changelog_view, license_view], menu_name='secondary_menu') +register_links(['about_view', 'license_view'], [about_view, license_view], menu_name='secondary_menu') register_top_menu('about', link={'text': _(u'about'), 'view': 'about_view', 'famfam': 'information'}, position=-1) diff --git a/apps/common/forms.py b/apps/common/forms.py index 11d91d0c2c..1f6644cc1c 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -167,11 +167,6 @@ class FileDisplayForm(forms.Form): fd.close() -class ChangelogForm(FileDisplayForm): - FILENAME = u'changelog.rst' - DIRECTORY = u'docs' - - class LicenseForm(FileDisplayForm): FILENAME = u'LICENSE' DIRECTORY = u'docs' diff --git a/apps/common/urls.py b/apps/common/urls.py index 8ac491fbd5..844b490a50 100644 --- a/apps/common/urls.py +++ b/apps/common/urls.py @@ -4,7 +4,6 @@ from django.conf import settings urlpatterns = patterns('common.views', url(r'^about/$', direct_to_template, {'template': 'about.html'}, 'about_view'), - url(r'^changelog/$', 'changelog_view', (), 'changelog_view'), url(r'^license/$', 'license_view', (), 'license_view'), url(r'^password/change/done/$', 'password_change_done', (), name='password_change_done'), url(r'^object/multiple/action/$', 'multi_object_action_view', (), name='multi_object_action_view'), diff --git a/apps/common/views.py b/apps/common/views.py index 46aa782bad..fd5a81f1c8 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -12,8 +12,8 @@ from django.utils.http import urlencode from django.contrib.auth.views import login from django.utils.simplejson import dumps, loads -from .forms import (ChoiceForm, UserForm, UserForm_view, ChangelogForm, - LicenseForm, EmailAuthenticationForm) +from .forms import (ChoiceForm, UserForm, UserForm_view, LicenseForm, + EmailAuthenticationForm) from .conf.settings import LOGIN_METHOD @@ -216,19 +216,6 @@ def login_view(request): return login(request, extra_context=context, **kwargs) -def changelog_view(request): - """ - Display the included Changelog.txt file from the about menu - """ - form = ChangelogForm() - return render_to_response( - 'generic_detail.html', { - 'form': form, - 'title': _(u'Changelog'), - }, - context_instance=RequestContext(request)) - - def license_view(request): """ Display the included LICENSE file from the about menu diff --git a/apps/main/templates/project_description.html b/apps/main/templates/project_description.html index 8eb85f32d3..16a53de480 100644 --- a/apps/main/templates/project_description.html +++ b/apps/main/templates/project_description.html @@ -8,6 +8,9 @@

    http://www.mayan-edms.com

    +

    + http://mayan.readthedocs.org/ +

    http://www.github.com/rosarior/mayan/

    diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index e00b715aa4..0dda074160 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -1,6 +1,6 @@ -======================== +============================== Mayan EDMS v0.12 release notes -======================== +============================== *February 2012* From 376a31db96d704705b8e79f38480fbc8a4f3dd8d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 10:33:01 -0400 Subject: [PATCH 304/484] Reorder installed apps so that the web theme pagination template is found --- settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/settings.py b/settings.py index 457d8dc732..fb3ed62f47 100644 --- a/settings.py +++ b/settings.py @@ -136,7 +136,6 @@ INSTALLED_APPS = ( 'mptt', 'compressor', 'djangorestframework', - 'pagination', # Base generic 'permissions', 'project_setup', @@ -145,6 +144,9 @@ INSTALLED_APPS = ( 'navigation', 'lock_manager', 'web_theme', +# pagination needs to go after web_theme so that the pagination template +# if found + 'pagination', 'common', 'django_gpg', 'dynamic_search', @@ -170,6 +172,7 @@ INSTALLED_APPS = ( 'main', 'rest_api', 'document_signatures', + ) TEMPLATE_CONTEXT_PROCESSORS = ( From 8aa56dc11c57b69e403ab9eba22950b9f516c912 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 21:51:35 -0400 Subject: [PATCH 305/484] Fix typo --- apps/sources/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sources/views.py b/apps/sources/views.py index f116dfad64..6f574fe75f 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -206,7 +206,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No expand = False else: if staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK: - expand = form.cleaned_dataget('expand') + expand = form.cleaned_data.get('expand') else: if staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y: expand = True From 1d543cdd0adf751acf14908dcbaa64f572a6f67a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 22:35:55 -0400 Subject: [PATCH 306/484] Prevent database corruption on document saving error --- apps/sources/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/sources/models.py b/apps/sources/models.py index d7fb8f7161..77830f86a9 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -7,6 +7,7 @@ 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 @@ -70,6 +71,7 @@ class BaseModel(models.Model): file_object.close() + @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): if not document: document = Document() From 3d0865b93f8a92e007ad0d354f6b2506b5c0731e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 23:02:27 -0400 Subject: [PATCH 307/484] Fix uploading of compressed files --- apps/sources/models.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 77830f86a9..5f7cbeccd6 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -1,6 +1,7 @@ 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 _ @@ -28,6 +29,8 @@ from .literals import (SOURCE_CHOICES, SOURCE_CHOICES_PLURAL, SOURCE_UNCOMPRESS_CHOICE_Y) from .compressed_file import CompressedFile, NotACompressedFile +logger = logging.getLogger(__name__) + class BaseModel(models.Model): title = models.CharField(max_length=64, verbose_name=_(u'title')) @@ -57,19 +60,26 @@ class BaseModel(models.Model): 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): + is_compressed = None + if expand: try: cf = CompressedFile(file_object) for fp in cf.children(): - self.upload_single_file(fp, None, document_type, metadata_dict_list, user) + self.upload_single_file(file_object=fp, filename=None, document_type=document_type, metadata_dict_list=metadata_dict_list, user=user) fp.close() except NotACompressedFile: - self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user) + is_compressed = False + logging.debug('Exception: NotACompressedFile') + 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): From 7d1873588278edbf8855ee966bc48b76bbaebb57 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 23:02:42 -0400 Subject: [PATCH 308/484] Improve feedback messages when uploading files --- apps/sources/views.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/sources/views.py b/apps/sources/views.py index 6f574fe75f..900c3aba50 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -150,7 +150,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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, @@ -160,10 +160,18 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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: @@ -215,7 +223,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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, @@ -227,7 +235,14 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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() From c38d10ebf500d546ccc891d58af0782603805d43 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 23:52:38 -0400 Subject: [PATCH 309/484] Proper redirection on document deletion --- apps/documents/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index af77a2f1aa..e6c10db735 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -186,9 +186,11 @@ def document_view(request, document_id, advanced=False): def document_delete(request, document_id=None, document_id_list=None): + post_action_redirect = None + if document_id: documents = [get_object_or_404(Document, pk=document_id)] - post_action_redirect = reverse('document_list') + post_action_redirect = reverse('document_list_recent') elif document_id_list: documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')] else: @@ -200,8 +202,6 @@ def document_delete(request, document_id=None, document_id_list=None): except PermissionDenied: documents = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_DELETE, request.user, documents, exception_on_empty=True) - post_action_redirect = None - 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', '/'))) From 9afa641b1917c880d8cff83de73b36e29e5b4c21 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 25 Jan 2012 21:49:02 -0400 Subject: [PATCH 310/484] Move import to beginning of file --- apps/permissions/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/permissions/views.py b/apps/permissions/views.py index 4d2230dbb2..33d94ccdb2 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -18,6 +18,7 @@ from django.utils.simplejson import loads from common.views import assign_remove 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 .models import Role, Permission, PermissionHolder, RoleMember @@ -245,12 +246,11 @@ def permission_revoke(request): return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) -from common.models import AnonymousUserSingleton - 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]) From cf36e281feba50926d8d5a284f87dd7d00cfe76a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 09:35:20 -0400 Subject: [PATCH 311/484] Documentation updates --- docs/contributors.rst | 14 +++-- docs/faq.rst | 131 ++++++++++++++++++++--------------------- docs/index.rst | 6 +- docs/releases/0.12.rst | 18 +++--- 4 files changed, 87 insertions(+), 82 deletions(-) diff --git a/docs/contributors.rst b/docs/contributors.rst index e05f8375bc..8a21a722bf 100644 --- a/docs/contributors.rst +++ b/docs/contributors.rst @@ -44,12 +44,18 @@ Suggestions Translations ------------ * Portuguese - * Emerson Soares (http://emersonsoares.com) - * Renata Oliveira (https://twitter.com/#!/rnataoliveira) + + - Emerson Soares (http://emersonsoares.com) + - Renata Oliveira (https://twitter.com/#!/rnataoliveira) + * Russian - * Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) + + - Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) + * Italian - * SeeOpen.IT (Numero Verde: 800.910.125, E-mail: sales@seeopen.it) + + - SeeOpen.IT (Numero Verde: 800.910.125, E-mail: sales@seeopen.it) + Remote access for debugging --------------------------- diff --git a/docs/faq.rst b/docs/faq.rst index 43392409e2..ee80548d28 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -5,26 +5,24 @@ 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:: +* 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])) + $ 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 - +* 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 @@ -32,102 +30,101 @@ Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row When using ``MySQL`` and doing OCR on languages other than English - * Solution: +* 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 + - 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: +* Solution: - - Disable unix extensions in the [global] section and enable wide links for the file serving share - - - Example:: + - Disable unix extensions in the [global] section and enable wide links for the file serving share + - Example:: - [global] - unix extensions = no + [global] + unix extensions = no - ... + ... - [digitalizacion] - path = /var/local/mayan - guest ok = yes - read only = yes - wide links = yes - follow symlinks = yes + [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 + - 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: +* Sub class Django's ``FileSystemStorage`` class: - - Create a file called ``customstorage.py``:: + - Create a file called ``customstorage.py``:: - from django.core.files.storage import FileSystemStorage + 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' + 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:: + - In the ``settings.py`` add:: - from customstorage import CustomStorage - DOCUMENTS_STORAGE_BACKEND = CustomStorage + 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) +* 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: +* Add indexes to the following fields: - - ``documents_document`` - description, recommended size: 160 - - ``documents_documentpage`` - content, recommended size: 3000 + - ``documents_document`` - description, recommended size: 160 + - ``documents_documentpage`` - content, recommended size: 3000 How to enable x-sendile support for ``Apache`` ---------------------------------------------- - * If using Ubuntu execute the following:: - +* If using Ubuntu execute the following:: + $ sudo apt-get install libapache2-mod-xsendfile - * Add the following line to your ``settings.py`` file:: +* Add the following line to your ``settings.py`` file:: - SENDFILE_BACKEND = 'sendfile.backends.xsendfile' - - * On your apache configuration file add:: + SENDFILE_BACKEND = 'sendfile.backends.xsendfile' + +* On your apache configuration file add:: - XSendFile on - XSendFileAllowAbove on + 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:: +* 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' + CONVERTER_UNOCONV_PATH = '/usr/local/bin/unoconv' diff --git a/docs/index.rst b/docs/index.rst index 25e1ca5039..b6da2d88e8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,16 +2,16 @@ Overview ======== -Open source, Django_ based document manager with custom metadata indexing, file serving integration and OCR_ capabilities. +Open source, Django_ based document manager with custom metadata indexing, file serving integration, OCR_ capabilities, document versioning and digital signature verification. .. _Django: http://www.djangoproject.com/ -:Website: http://bit.ly/mayan-edms +:Website: http://www.mayan-edms.com :Source: http://github.com/rosarior/mayan :Video: http://bit.ly/pADNXv :Issue tracker: http://github.com/rosarior/mayan/issues - +:Mailing list: http://groups.google.com/group/mayan-edms **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. diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 0dda074160..45c7ab9e75 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -84,7 +84,7 @@ the download of several documents in a single compressed file. Customizable GPG home directory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Addition of the SIGNATURES_GPG_HOME configuration option to let -administrators set Mayan EDMS's GPG instance home directory, used to +administrators set **Mayan EDMS**'s GPG instance home directory, used to store keyrings and other GPG configuration files. Upgrading @@ -99,15 +99,16 @@ Upgrading When the following message appears -``The following content types are stale and need to be deleted: +.. epigraph:: + The following content types are stale and need to be deleted: - permissions | permission + 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'. + 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' to continue, or 'no' to cancel: Types ``yes`` and press **Enter** @@ -138,4 +139,5 @@ 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. + migrations as it was causing error messages for MySQL users, thanks to + Сергей Глита for reporting this one. From e08c93e88b0be2ec41f47f0e6a2a83d44ff66fb1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 10:31:07 -0400 Subject: [PATCH 312/484] Add out of process bulk document upload --- apps/sources/management/__init__.py | 0 apps/sources/management/commands/__init__.py | 0 .../management/commands/bulk_upload.py | 48 +++++++++++++++++++ apps/sources/models.py | 26 +++++++++- 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 apps/sources/management/__init__.py create mode 100644 apps/sources/management/commands/__init__.py create mode 100644 apps/sources/management/commands/bulk_upload.py 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..42563116d5 --- /dev/null +++ b/apps/sources/management/commands/bulk_upload.py @@ -0,0 +1,48 @@ +from __future__ import absolute_import + +import os +from optparse import make_option + +from django.core.management.base import BaseCommand, CommandError, LabelCommand + +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 to apply to the documents.'), + ) + + def handle_label(self, label, **options): + if not os.access(label, os.R_OK): + raise CommandError("File '%s' is not readable." % label) + + if _confirm(options['interactive']) == 'yes': + print 'Beginning upload...' + fd = open(label) + source = OutOfProcess() + try: + result = source.upload_file(fd, filename=None, use_file_name=False, document_type=None, expand=True, metadata_dict_list=None, user=None, document=None, new_version_data=None, verbose=True) + except NotACompressedFile: + print '%s is not a compressed file.' + 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/models.py b/apps/sources/models.py index d7fb8f7161..7243583f90 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -55,13 +55,17 @@ class BaseModel(models.Model): 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, verbose=False): if expand: try: cf = CompressedFile(file_object) + count = 1 for fp in cf.children(): + if verbose: + print 'Uploading file #%d: %s' % (count, fp) self.upload_single_file(fp, None, document_type, metadata_dict_list, user) fp.close() + count += 1 except NotACompressedFile: self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user) @@ -256,3 +260,23 @@ class SourceTransformation(models.Model): ordering = ('order',) verbose_name = _(u'document source transformation') verbose_name_plural = _(u'document source transformations') + + +class OutOfProcess(BaseModel): + #icon = models.CharField(blank=True, null=True, max_length=24, choices=SOURCE_ICON_CHOICES, verbose_name=_(u'icon'), help_text=_(u'An icon to visually distinguish this source.')) + + #def save(self, *args, **kwargs): + # if not self.icon: + # self.icon = self.default_icon + # super(BaseModel, self).save(*args, **kwargs) + + is_interactive = False + #source_type = SOURCE_CHOICE_WEB_FORM + #default_icon = SOURCE_ICON_DISK + + #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.')) + #Default path + + class Meta(BaseModel.Meta): + verbose_name = _(u'out of process') + verbose_name_plural = _(u'out of process') From 850c6dd69a9038c90761a2a9f7e8323115104bf0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 11:14:22 -0400 Subject: [PATCH 313/484] Add the options --metadata and --document_type to the bulk uploader --- apps/metadata/api.py | 12 ++++++ .../management/commands/bulk_upload.py | 42 ++++++++++++++++--- apps/sources/models.py | 14 +++---- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/apps/metadata/api.py b/apps/metadata/api.py index 60e611e5f6..77a86056bb 100644 --- a/apps/metadata/api.py +++ b/apps/metadata/api.py @@ -107,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/sources/management/commands/bulk_upload.py b/apps/sources/management/commands/bulk_upload.py index 42563116d5..f31c62d48c 100644 --- a/apps/sources/management/commands/bulk_upload.py +++ b/apps/sources/management/commands/bulk_upload.py @@ -1,9 +1,13 @@ from __future__ import absolute_import -import os +import os, sys from optparse import make_option from django.core.management.base import BaseCommand, CommandError, LabelCommand +from django.utils.simplejson import loads, dumps + +from metadata.api import convert_dict_to_dict_list +from documents.models import DocumentType from ...models import OutOfProcess from ...compressed_file import CompressedFile, NotACompressedFile @@ -16,20 +20,48 @@ class Command(LabelCommand): 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 to apply to the documents.'), + 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...' - fd = open(label) + 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=None, expand=True, metadata_dict_list=None, user=None, document=None, new_version_data=None, verbose=True) + 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, verbose=True) + pass except NotACompressedFile: print '%s is not a compressed file.' else: diff --git a/apps/sources/models.py b/apps/sources/models.py index 195022cfcf..7d181a17cd 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -94,7 +94,7 @@ class BaseModel(models.Model): document.save() apply_default_acls(document, user) - + if metadata_dict_list: save_metadata_list(metadata_dict_list, document, create=True) warnings = update_indexes(document) @@ -163,7 +163,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() @@ -177,7 +177,7 @@ class SourceMetadata(models.Model): class Meta: verbose_name = _(u'source metadata') verbose_name_plural = _(u'sources metadata') -''' +""" class WebForm(InteractiveBaseModel): @@ -239,9 +239,9 @@ class ArgumentsValidator(object): self.code = code def __call__(self, value): - ''' + """ Validates that the input evaluates correctly. - ''' + """ value = value.strip() try: literal_eval(value) @@ -250,10 +250,10 @@ class ArgumentsValidator(object): class SourceTransformation(models.Model): - ''' + """ Model that stores the transformation and transformation arguments for a given document source - ''' + """ content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') From af58a8ccd07b010255f40ae86350ed8ad1a086e3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 11:24:29 -0400 Subject: [PATCH 314/484] Added documentation for the bulk uploading command --- docs/releases/0.12.rst | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 45c7ab9e75..621145bdee 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -87,8 +87,25 @@ Addition of the 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. -Upgrading -========= +Out of process bulk uploading +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A management command has been added to help upload a large number of documents +from a compressed file. The command line options for this feature are as +follow:: + + $ ./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 inmediately. +* 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. + + +Upgrading from a previous version +================================= :: @@ -129,13 +146,13 @@ 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 + access to a machine suffering with the issue. * Statistics fixes. -* Fixed get_image_cache_name regression in the OCR app +* Fixed get_image_cache_name regression in the OCR app. Stuff removed ============= -* Removal of the OCR_CACHE_URI configuration option +* Removal of the OCR_CACHE_URI configuration option. * Support for Celery and Sentry has been drop for now. * Removed the 'db_index' argument from Text fields definition and From 266fcc75df2f80f5772028d4610c10ee0405058e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 11:37:20 -0400 Subject: [PATCH 315/484] Prevent upload error from desynchonizing the database --- apps/sources/models.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 7d181a17cd..6fb3ca3f67 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -59,7 +59,7 @@ class BaseModel(models.Model): 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, verbose=False): + 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: @@ -67,7 +67,7 @@ class BaseModel(models.Model): cf = CompressedFile(file_object) count = 1 for fp in cf.children(): - if verbose: + 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() @@ -76,6 +76,8 @@ class BaseModel(models.Model): except NotACompressedFile: 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 @@ -112,8 +114,14 @@ 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() + raise + if filename: new_version.filename = filename new_version.save() From d79e86ae30bf2219e7bf44e95dcb3318c59d99bb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 11:37:44 -0400 Subject: [PATCH 316/484] Only allow compressed files for bulk upload command --- apps/sources/management/commands/bulk_upload.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sources/management/commands/bulk_upload.py b/apps/sources/management/commands/bulk_upload.py index f31c62d48c..47c0a179d1 100644 --- a/apps/sources/management/commands/bulk_upload.py +++ b/apps/sources/management/commands/bulk_upload.py @@ -60,10 +60,10 @@ class Command(LabelCommand): 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, verbose=True) + 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.' + print '%s is not a compressed file.' % label else: print 'Finished.' From 30351225f68c1b2869754748eff27126293ba65b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 22:42:36 -0400 Subject: [PATCH 317/484] Allow current to edit more details of himself, saner redirection after password change --- apps/common/forms.py | 2 +- apps/common/urls.py | 2 +- apps/common/views.py | 33 ++++++++++++++++++++++++--------- apps/user_management/views.py | 1 + 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/common/forms.py b/apps/common/forms.py index 1f6644cc1c..b34bf101a5 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -122,7 +122,7 @@ class UserForm(forms.ModelForm): """ class Meta: model = User - fields = ('first_name', 'last_name') + fields = ('username', 'first_name', 'last_name', 'email') class EmailAuthenticationForm(AuthenticationForm): diff --git a/apps/common/urls.py b/apps/common/urls.py index 844b490a50..2a74759a75 100644 --- a/apps/common/urls.py +++ b/apps/common/urls.py @@ -12,12 +12,12 @@ urlpatterns = patterns('common.views', url(r'^user/edit/$', 'current_user_edit', (), 'current_user_edit'), url(r'^login/$', 'login_view', (), name='login_view'), + url(r'^password/change/$', 'password_change_view', (), name='password_change_view'), ) urlpatterns += patterns('', url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout_view'), - url(r'^password/change/$', 'django.contrib.auth.views.password_change', {'template_name': 'password_change_form.html', 'post_change_redirect': '/password/change/done/'}, name='password_change_view'), url(r'^password/reset/$', 'django.contrib.auth.views.password_reset', {'email_template_name': 'password_reset_email.html', 'template_name': 'password_reset_form.html', 'post_reset_redirect': '/password/reset/done'}, name='password_reset_view'), url(r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'template_name': 'password_reset_confirm.html', 'post_reset_redirect': '/password/reset/complete/'}, name='password_reset_confirm_view'), url(r'^password/reset/complete/$', 'django.contrib.auth.views.password_reset_complete', {'template_name': 'password_reset_complete.html'}, name='password_reset_complete_view'), diff --git a/apps/common/views.py b/apps/common/views.py index fd5a81f1c8..b823b2b33d 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -11,21 +11,13 @@ from django.core.urlresolvers import reverse from django.utils.http import urlencode from django.contrib.auth.views import login from django.utils.simplejson import dumps, loads +from django.contrib.auth.views import password_change from .forms import (ChoiceForm, UserForm, UserForm_view, LicenseForm, EmailAuthenticationForm) from .conf.settings import LOGIN_METHOD -def password_change_done(request): - """ - View called when the new user password has been accepted - """ - - messages.success(request, _(u'Your password has been successfully changed.')) - return redirect('home') - - def multi_object_action_view(request): """ Proxy view called first when using a multi object action, which @@ -227,3 +219,26 @@ def license_view(request): 'title': _(u'License'), }, context_instance=RequestContext(request)) + + +def password_change_view(request): + """ + Password change wrapper for better control + """ + context={'title': _(u'Current user password change')} + + return password_change( + request, + extra_context=context, + template_name='password_change_form.html', + post_change_redirect=reverse('password_change_done'), + ) + + +def password_change_done(request): + """ + View called when the new user password has been accepted + """ + + messages.success(request, _(u'Your password has been successfully changed.')) + return redirect('current_user_details') diff --git a/apps/user_management/views.py b/apps/user_management/views.py index f859a6940f..743c723a35 100644 --- a/apps/user_management/views.py +++ b/apps/user_management/views.py @@ -211,6 +211,7 @@ def user_multiple_set_password(request): ) +# Group views def group_list(request): Permission.objects.check_permissions(request.user, [PERMISSION_GROUP_VIEW]) From 8ebd5b80629c5abe9a656e644e8f1169d6234382 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 23:10:28 -0400 Subject: [PATCH 318/484] Make email field full width in email login form --- apps/common/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/forms.py b/apps/common/forms.py index b34bf101a5..ac5527fc9f 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -131,7 +131,7 @@ class EmailAuthenticationForm(AuthenticationForm): authentication """ email = forms.CharField(label=_(u'Email'), max_length=75, - widget=EmailInput() + widget=EmailInput(attrs={'style': 'width: 100%;'}) ) def clean(self): From 485573c5d6ba02ca7869e35d97f655d72cfd81de Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 23:11:11 -0400 Subject: [PATCH 319/484] Validate email in user details edit to avoid email clashes --- apps/common/views.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/common/views.py b/apps/common/views.py index b823b2b33d..c5d995bb59 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -12,6 +12,7 @@ from django.utils.http import urlencode from django.contrib.auth.views import login from django.utils.simplejson import dumps, loads from django.contrib.auth.views import password_change +from django.contrib.auth.models import User from .forms import (ChoiceForm, UserForm, UserForm_view, LicenseForm, EmailAuthenticationForm) @@ -175,9 +176,12 @@ def current_user_edit(request): if request.method == 'POST': form = UserForm(instance=request.user, data=request.POST) if form.is_valid(): - form.save() - messages.success(request, _(u'Current user\'s details updated.')) - return HttpResponseRedirect(next) + if User.objects.filter(email=form.cleaned_data['email']).exclude(pk=request.user.pk).count(): + messages.error(request, _(u'E-mail conflict, another user has that same email.')) + else: + form.save() + messages.success(request, _(u'Current user\'s details updated.')) + return HttpResponseRedirect(next) else: form = UserForm(instance=request.user) From 4737b393b5a37a13d3d715ce0f80f3a10344c795 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 23:13:13 -0400 Subject: [PATCH 320/484] Add email authentication backend note to the documentation --- docs/settings.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index 3b1fc65f25..ffac3c7179 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -330,7 +330,9 @@ Common Default: ``username`` - Controls the mechanism used to authenticated user. Options are: ``username``, ``email`` + 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',) .. data:: COMMON_ALLOW_ANONYMOUS_ACCESS From 5de9b460488ad32fe5eb4f39dd1cae431c5ecf7e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 26 Jan 2012 23:17:29 -0400 Subject: [PATCH 321/484] Redirect to user password reset view after a new user is created --- apps/user_management/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user_management/views.py b/apps/user_management/views.py index 743c723a35..b9c9a6c9e8 100644 --- a/apps/user_management/views.py +++ b/apps/user_management/views.py @@ -84,7 +84,7 @@ def user_add(request): if form.is_valid(): user = form.save() messages.success(request, _(u'User "%s" created successfully.') % user) - return HttpResponseRedirect(reverse('user_list')) + return HttpResponseRedirect(reverse('user_set_password', args=[user.pk])) else: form = UserForm() From 1fe99021444bcbc20e4e243ba3aa105af7442e37 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 00:40:30 -0400 Subject: [PATCH 322/484] Set new users' password as unusable until one is set, add column to user list showing if password is usable --- apps/user_management/views.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/user_management/views.py b/apps/user_management/views.py index b9c9a6c9e8..85fea6a198 100644 --- a/apps/user_management/views.py +++ b/apps/user_management/views.py @@ -42,8 +42,11 @@ def user_list(request): { 'name': _(u'active'), 'attribute': encapsulate(lambda x: two_state_template(x.is_active)), - } - + }, + { + 'name': _(u'has usable password?'), + 'attribute': encapsulate(lambda x: two_state_template(x.has_usable_password())), + }, ], 'multi_select_as_buttons': True, }, @@ -82,7 +85,9 @@ def user_add(request): if request.method == 'POST': form = UserForm(request.POST) if form.is_valid(): - user = form.save() + user = form.save(commit=False) + user.set_unusable_password() + user.save() messages.success(request, _(u'User "%s" created successfully.') % user) return HttpResponseRedirect(reverse('user_set_password', args=[user.pk])) else: From ff88e1a422b022002d2f698561ec84e2ea22b7cb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 00:41:15 -0400 Subject: [PATCH 323/484] Add command line function to import a list users from a CSV file --- apps/user_management/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/import_users.py | 83 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 apps/user_management/management/__init__.py create mode 100644 apps/user_management/management/commands/__init__.py create mode 100644 apps/user_management/management/commands/import_users.py diff --git a/apps/user_management/management/__init__.py b/apps/user_management/management/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/user_management/management/commands/__init__.py b/apps/user_management/management/commands/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/user_management/management/commands/import_users.py b/apps/user_management/management/commands/import_users.py new file mode 100644 index 0000000000..b02d08d5b4 --- /dev/null +++ b/apps/user_management/management/commands/import_users.py @@ -0,0 +1,83 @@ +from __future__ import absolute_import + +import csv, os, sys +from optparse import make_option + +from django.core.management.base import BaseCommand, CommandError, LabelCommand +from django.utils.simplejson import loads, dumps +from django.contrib.auth.models import User +from django.db.utils import IntegrityError + + +def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs): + # csv.py doesn't do Unicode; encode temporarily as UTF-8: + csv_reader = csv.reader(utf_8_encoder(unicode_csv_data), + dialect=dialect, **kwargs) + for row in csv_reader: + # decode UTF-8 back to Unicode, cell by cell: + yield [unicode(cell, 'utf-8') for cell in row] + +def utf_8_encoder(unicode_csv_data): + for line in unicode_csv_data: + yield line.encode('utf-8') + + +class Command(LabelCommand): + args = '' + help = 'Import users from a CSV file with the field order: username, firstname, lastname, email.' + 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('--password', action='store', dest='password', + help='The default password to assign to each new user.'), + make_option('--skip-repeated', action='store_true', dest='skip_repeated', + default=False, help='Don\'t exit if the user already exists.'), + ) + + def handle_label(self, label, **options): + if not os.access(label, os.R_OK): + raise CommandError("File '%s' is not readable." % label) + + if options['password']: + default_password = options['password'] + else: + default_password = None + + if _confirm(options['interactive']) == 'yes': + print 'Beginning import...' + with open(label, 'rb') as f: + reader = unicode_csv_reader(f) + try: + for row in reader: + print 'Adding: %s' % ', '.join(row) + try: + user = User( + username=row[0], + first_name=row[1], + last_name=row[2], + email=row[3] + ) + user.set_password(default_password) + user.save() + except IntegrityError: + print 'Repeated user entry: %s' % ', '.join(row) + if options['skip_repeated']: + print 'Ignoring.' + else: + sys.exit() + + except csv.Error, e: + sys.exit('file %s, line %d: %s' % (label, reader.line_num, e)) + else: + print 'Finish.' + else: + print 'Cancelled.' + + +def _confirm(interactive): + if not interactive: + return 'yes' + return raw_input('You have requested to import a number of users from a CSV file.\n' + 'Are you sure you want to do this?\n' + 'Type \'yes\' to continue, or any other value to cancel: ') From 70aec4a0b7a5ec00bc7506013c7bb557ec59e67a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 00:46:13 -0400 Subject: [PATCH 324/484] Add information about the user CSV importer to the documentation --- docs/releases/0.12.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 621145bdee..fab6ac8d7d 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -97,12 +97,28 @@ follow:: **Optional arguments** -* The ``--noinput`` argument skips confirmation and starts the upload inmediately. +* 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. +Out of process user import +~~~~~~~~~~~~~~~~~~~~~~~~~~ +A management command has been added 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 + +**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. + Upgrading from a previous version ================================= From 0b92fad9c223b80102487d3562f273fce705d249 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 00:47:30 -0400 Subject: [PATCH 325/484] Add information about the CSV field order --- docs/releases/0.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index fab6ac8d7d..965e12617e 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -111,6 +111,9 @@ 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. From 9057d3c481cf03bc00c2eaf0771e6a04c30ac348 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 11:11:05 -0400 Subject: [PATCH 326/484] Add actor membership access checking --- apps/acls/managers.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 1fe21cf231..384c01b504 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -11,7 +11,7 @@ from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from common.models import AnonymousUserSingleton -from permissions.models import Permission +from permissions.models import Permission, RoleMember from .classes import (EncapsulatedObject, AccessHolder, ClassAccessHolder, get_source_object) @@ -61,6 +61,7 @@ class AccessEntryManager(models.Manager): access_entry.delete() return True + def has_access(self, permission, actor, obj, db_only=False): """ Returns whether an actor has a specific permission for an object @@ -69,6 +70,8 @@ class AccessEntryManager(models.Manager): actor = get_source_object(actor) if isinstance(actor, User) and db_only == False: + # db_only causes the return of only the stored permissions + # and not the perceived permissions for an actor if actor.is_superuser or actor.is_staff: return True @@ -83,6 +86,20 @@ class AccessEntryManager(models.Manager): object_id=obj.pk ) except self.model.DoesNotExist: + # If not check if the actor's memberships is one of + # the access's holder? + roles = RoleMember.objects.get_roles_for_member(actor) + + if isinstance(actor, User): + groups = actor.groups.all() + else: + groups = [] + + for membership in list(set(roles) | set(groups)): + if self.has_access(permission, membership, obj, db_only): + return True + + logger.debug('Fallthru') return False else: return True From 9d52ce6683255f45615a6a6406b188f4f13ae078 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 15:54:05 -0400 Subject: [PATCH 327/484] Add object_list/queryset ACL inheritance --- apps/acls/managers.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 384c01b504..66991003d2 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -9,6 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse +from django.db.models import Q from common.models import AnonymousUserSingleton from permissions.models import Permission, RoleMember @@ -132,15 +133,48 @@ class AccessEntryManager(models.Manager): actor = AnonymousUserSingleton.objects.passthru_check(actor) actor_type = ContentType.objects.get_for_model(actor) content_type = ContentType.objects.get_for_model(cls) + + # Calculate actor role membership ACL query + total_queries = None + for role in RoleMember.objects.get_roles_for_member(actor): + role_type = ContentType.objects.get_for_model(role) + if related: + query = Q(holder_type=role_type, holder_id=role.pk, permission=permission.get_stored_permission) + else: + query = Q(holder_type=role_type, holder_id=role.pk, content_type=content_type, permission=permission.get_stored_permission) + if total_queries is None: + total_queries = query + else: + total_queries = total_queries | query + + # Calculate actor group membership ACL query + if isinstance(actor, User): + groups = actor.groups.all() + else: + groups = [] + + for group in groups: + group_type = ContentType.objects.get_for_model(group) + if related: + query = Q(holder_type=group_type, holder_id=group.pk, permission=permission.get_stored_permission) + else: + query = Q(holder_type=group_type, holder_id=group.pk, content_type=content_type, permission=permission.get_stored_permission) + if total_queries is None: + total_queries = query + else: + total_queries = total_queries | query + if related: - master_list = [obj.content_object for obj in self.model.objects.select_related().filter(holder_type=actor_type, holder_id=actor.pk, permission=permission.get_stored_permission)] + actor_query = Q(holder_type=actor_type, holder_id=actor.pk, permission=permission.get_stored_permission) + master_list = [obj.content_object for obj in self.model.objects.select_related().filter(actor_query | total_queries)] logger.debug('master_list: %s' % master_list) # TODO: update to use Q objects and check performance diff # kwargs = {'%s__in' % related: master_list} # Q(**kwargs) return (obj for obj in cls.objects.all() if getattr(obj, related) in master_list) else: - return (obj.content_object for obj in self.model.objects.filter(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission)) + actor_query = Q(holder_type=actor_type, holder_id=actor.pk, content_type=content_type, permission=permission.get_stored_permission) + return (obj.content_object for obj in self.model.objects.filter(actor_query | total_queries)) def get_acl_url(self, obj): content_type = ContentType.objects.get_for_model(obj) From 58bea814f1e6e7c5f202370cd70531f6c61fea5f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 27 Jan 2012 16:33:29 -0400 Subject: [PATCH 328/484] Remove deprecated OCR task view --- apps/ocr/__init__.py | 4 +--- apps/ocr/urls.py | 1 - apps/ocr/views.py | 36 ------------------------------------ 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 668e20b4b6..5f160d4fce 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -43,8 +43,6 @@ all_document_ocr_cleanup = {'text': _(u'clean up pages content'), 'view': 'all_d 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]} - 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'} setup_queue_transformation_edit = {'text': _(u'edit'), 'view': 'setup_queue_transformation_edit', 'args': 'transformation.pk', 'famfam': 'shape_square_edit'} @@ -58,7 +56,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')) 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 7083fb817c..fbeafc7b3a 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -302,42 +302,6 @@ def display_link(obj): return obj -def node_active_list(request): - Permission.objects.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): Permission.objects.check_permissions(request.user, [PERMISSION_OCR_QUEUE_EDIT]) From 640ff7146cb09bb1473fac23034e848208f29395 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 31 Jan 2012 22:48:00 -0400 Subject: [PATCH 329/484] Initial update to support multiple indexes --- apps/document_indexing/__init__.py | 5 +- apps/document_indexing/admin.py | 29 +-- apps/document_indexing/api.py | 3 +- .../migrations/0001_initial.py | 189 +++++++++++++++++ ...namecount__del_indexinstance__del_index.py | 75 +++++++ ...enode__add_indexinstancenode__add_index.py | 191 ++++++++++++++++++ .../0004_auto__add_documentrenamecount.py | 153 ++++++++++++++ apps/document_indexing/migrations/__init__.py | 0 apps/document_indexing/models.py | 49 +++-- apps/document_indexing/views.py | 2 +- apps/document_indexing/widgets.py | 6 +- docs/releases/0.12.rst | 13 ++ 12 files changed, 682 insertions(+), 33 deletions(-) create mode 100644 apps/document_indexing/migrations/0001_initial.py create mode 100644 apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py create mode 100644 apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py create mode 100644 apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py create mode 100644 apps/document_indexing/migrations/__init__.py diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index c71a55f544..59d6b30895 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -9,11 +9,11 @@ from main.api import register_maintenance_links from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document -from .models import IndexInstance +#from .models import IndexInstance from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) - +""" index_list = {'text': _(u'index list'), 'view': 'index_instance_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True} document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} @@ -29,3 +29,4 @@ register_sidebar_template(['index_instance_list'], 'indexing_help.html') register_links(IndexInstance, [index_parent]) register_links(Document, [document_index_list], menu_name='form_header') +""" diff --git a/apps/document_indexing/admin.py b/apps/document_indexing/admin.py index cfe2cd6f99..7ec0de2423 100644 --- a/apps/document_indexing/admin.py +++ b/apps/document_indexing/admin.py @@ -1,27 +1,30 @@ +from __future__ import absolute_import + from django.contrib import admin from mptt.admin import MPTTModelAdmin -from document_indexing.models import Index, IndexInstance, \ - DocumentRenameCount +from .models import (Index, IndexTemplateNode, IndexInstanceNode, + DocumentRenameCount) -class IndexInstanceInline(admin.StackedInline): - model = IndexInstance - extra = 1 - classes = ('collapse-open',) - allow_add = True +#class IndexInstanceInline(admin.StackedInline): +# model = IndexInstance +# extra = 1# +# classes = ('collapse-open',) +# allow_add = True -class IndexAdmin(MPTTModelAdmin): +class IndexTemplateNodeAdmin(MPTTModelAdmin): list_display = ('expression', 'enabled', 'link_documents') -class IndexInstanceAdmin(MPTTModelAdmin): - model = IndexInstance - list_display = ('value', 'index', 'get_document_list_display') +class IndexInstanceNodeAdmin(MPTTModelAdmin): + model = IndexInstanceNode + list_display = ('value',)# 'get_document_list_display') -admin.site.register(Index, IndexAdmin) -admin.site.register(IndexInstance, IndexInstanceAdmin) +admin.site.register(Index) +admin.site.register(IndexTemplateNode, IndexTemplateNodeAdmin) +admin.site.register(IndexInstanceNode, IndexInstanceNodeAdmin) admin.site.register(DocumentRenameCount) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 6b996fce17..6a6cfde3a4 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -9,7 +9,8 @@ from django.template.defaultfilters import slugify from documents.models import Document from metadata.classes import MetadataObject -from .models import (Index, IndexInstance, DocumentRenameCount) +from .models import (Index, IndexTemplateNode, IndexInstanceNode, + DocumentRenameCount) from .conf.settings import (AVAILABLE_INDEXING_FUNCTIONS, MAX_SUFFIX_COUNT, SLUGIFY_PATHS) from .filesystem import (fs_create_index_directory, diff --git a/apps/document_indexing/migrations/0001_initial.py b/apps/document_indexing/migrations/0001_initial.py new file mode 100644 index 0000000000..40847032c5 --- /dev/null +++ b/apps/document_indexing/migrations/0001_initial.py @@ -0,0 +1,189 @@ +# 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 'Index' + db.create_table('document_indexing_index', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_meta_class', null=True, to=orm['document_indexing.Index'])), + ('expression', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('link_documents', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + )) + db.send_create_signal('document_indexing', ['Index']) + + # Adding model 'IndexInstance' + db.create_table('document_indexing_indexinstance', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_meta_instance', null=True, to=orm['document_indexing.IndexInstance'])), + ('index', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.Index'])), + ('value', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + )) + db.send_create_signal('document_indexing', ['IndexInstance']) + + # Adding M2M table for field documents on 'IndexInstance' + db.create_table('document_indexing_indexinstance_documents', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('indexinstance', models.ForeignKey(orm['document_indexing.indexinstance'], null=False)), + ('document', models.ForeignKey(orm['documents.document'], null=False)) + )) + db.create_unique('document_indexing_indexinstance_documents', ['indexinstance_id', 'document_id']) + + # Adding model 'DocumentRenameCount' + db.create_table('document_indexing_documentrenamecount', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('index_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexInstance'])), + ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])), + ('suffix', self.gf('django.db.models.fields.PositiveIntegerField')(blank=True)), + )) + db.send_create_signal('document_indexing', ['DocumentRenameCount']) + + + def backwards(self, orm): + + # Deleting model 'Index' + db.delete_table('document_indexing_index') + + # Deleting model 'IndexInstance' + db.delete_table('document_indexing_indexinstance') + + # Removing M2M table for field documents on 'IndexInstance' + db.delete_table('document_indexing_indexinstance_documents') + + # Deleting model 'DocumentRenameCount' + db.delete_table('document_indexing_documentrenamecount') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_indexing.documentrenamecount': { + 'Meta': {'object_name': 'DocumentRenameCount'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_instance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexInstance']"}), + 'suffix': ('django.db.models.fields.PositiveIntegerField', [], {'blank': 'True'}) + }, + 'document_indexing.index': { + 'Meta': {'object_name': 'Index'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'expression': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'link_documents': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_meta_class'", 'null': 'True', 'to': "orm['document_indexing.Index']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'document_indexing.indexinstance': { + 'Meta': {'object_name': 'IndexInstance'}, + 'documents': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.Document']", 'symmetrical': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.Index']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_meta_instance'", 'null': 'True', 'to': "orm['document_indexing.IndexInstance']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_indexing'] diff --git a/apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py b/apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py new file mode 100644 index 0000000000..5ec49448dd --- /dev/null +++ b/apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py @@ -0,0 +1,75 @@ +# 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): + + # Deleting model 'DocumentRenameCount' + db.delete_table('document_indexing_documentrenamecount') + + # Deleting model 'IndexInstance' + db.delete_table('document_indexing_indexinstance') + + # Removing M2M table for field documents on 'IndexInstance' + db.delete_table('document_indexing_indexinstance_documents') + + # Deleting model 'Index' + db.delete_table('document_indexing_index') + + + def backwards(self, orm): + + # Adding model 'DocumentRenameCount' + db.create_table('document_indexing_documentrenamecount', ( + ('suffix', self.gf('django.db.models.fields.PositiveIntegerField')(blank=True)), + ('index_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexInstance'])), + ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal('document_indexing', ['DocumentRenameCount']) + + # Adding model 'IndexInstance' + db.create_table('document_indexing_indexinstance', ( + ('index', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.Index'])), + ('parent', self.gf('mptt.fields.TreeForeignKey')(related_name='index_meta_instance', null=True, to=orm['document_indexing.IndexInstance'], blank=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('value', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal('document_indexing', ['IndexInstance']) + + # Adding M2M table for field documents on 'IndexInstance' + db.create_table('document_indexing_indexinstance_documents', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('indexinstance', models.ForeignKey(orm['document_indexing.indexinstance'], null=False)), + ('document', models.ForeignKey(orm['documents.document'], null=False)) + )) + db.create_unique('document_indexing_indexinstance_documents', ['indexinstance_id', 'document_id']) + + # Adding model 'Index' + db.create_table('document_indexing_index', ( + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('parent', self.gf('mptt.fields.TreeForeignKey')(related_name='index_meta_class', null=True, to=orm['document_indexing.Index'], blank=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('link_documents', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('expression', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + )) + db.send_create_signal('document_indexing', ['Index']) + + + models = { + + } + + complete_apps = ['document_indexing'] diff --git a/apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py b/apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py new file mode 100644 index 0000000000..6d488c2c34 --- /dev/null +++ b/apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py @@ -0,0 +1,191 @@ +# 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 'IndexTemplateNode' + db.create_table('document_indexing_indextemplatenode', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_template_node', null=True, to=orm['document_indexing.IndexTemplateNode'])), + ('index', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.Index'])), + ('expression', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('link_documents', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + )) + db.send_create_signal('document_indexing', ['IndexTemplateNode']) + + # Adding model 'IndexInstanceNode' + db.create_table('document_indexing_indexinstancenode', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_instance_node', null=True, to=orm['document_indexing.IndexInstanceNode'])), + ('index_template_node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexTemplateNode'])), + ('value', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)), + ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + )) + db.send_create_signal('document_indexing', ['IndexInstanceNode']) + + # Adding M2M table for field documents on 'IndexInstanceNode' + db.create_table('document_indexing_indexinstancenode_documents', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('indexinstancenode', models.ForeignKey(orm['document_indexing.indexinstancenode'], null=False)), + ('document', models.ForeignKey(orm['documents.document'], null=False)) + )) + db.create_unique('document_indexing_indexinstancenode_documents', ['indexinstancenode_id', 'document_id']) + + # Adding model 'Index' + db.create_table('document_indexing_index', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('document_indexing', ['Index']) + + + def backwards(self, orm): + + # Deleting model 'IndexTemplateNode' + db.delete_table('document_indexing_indextemplatenode') + + # Deleting model 'IndexInstanceNode' + db.delete_table('document_indexing_indexinstancenode') + + # Removing M2M table for field documents on 'IndexInstanceNode' + db.delete_table('document_indexing_indexinstancenode_documents') + + # Deleting model 'Index' + db.delete_table('document_indexing_index') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_indexing.index': { + 'Meta': {'object_name': 'Index'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'document_indexing.indexinstancenode': { + 'Meta': {'object_name': 'IndexInstanceNode'}, + 'documents': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.Document']", 'symmetrical': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_template_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexTemplateNode']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_instance_node'", 'null': 'True', 'to': "orm['document_indexing.IndexInstanceNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}) + }, + 'document_indexing.indextemplatenode': { + 'Meta': {'object_name': 'IndexTemplateNode'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'expression': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.Index']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'link_documents': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_template_node'", 'null': 'True', 'to': "orm['document_indexing.IndexTemplateNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_indexing'] diff --git a/apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py b/apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py new file mode 100644 index 0000000000..1b3c59c0c5 --- /dev/null +++ b/apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py @@ -0,0 +1,153 @@ +# 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 'DocumentRenameCount' + db.create_table('document_indexing_documentrenamecount', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('index_instance_node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexInstanceNode'])), + ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])), + ('suffix', self.gf('django.db.models.fields.PositiveIntegerField')(blank=True)), + )) + db.send_create_signal('document_indexing', ['DocumentRenameCount']) + + + def backwards(self, orm): + + # Deleting model 'DocumentRenameCount' + db.delete_table('document_indexing_documentrenamecount') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_indexing.documentrenamecount': { + 'Meta': {'object_name': 'DocumentRenameCount'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_instance_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexInstanceNode']"}), + 'suffix': ('django.db.models.fields.PositiveIntegerField', [], {'blank': 'True'}) + }, + 'document_indexing.index': { + 'Meta': {'object_name': 'Index'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'document_indexing.indexinstancenode': { + 'Meta': {'object_name': 'IndexInstanceNode'}, + 'documents': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.Document']", 'symmetrical': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_template_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexTemplateNode']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_instance_node'", 'null': 'True', 'to': "orm['document_indexing.IndexInstanceNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}) + }, + 'document_indexing.indextemplatenode': { + 'Meta': {'object_name': 'IndexTemplateNode'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'expression': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.Index']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'link_documents': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_template_node'", 'null': 'True', 'to': "orm['document_indexing.IndexTemplateNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_indexing'] diff --git a/apps/document_indexing/migrations/__init__.py b/apps/document_indexing/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index a9df3f4dc2..48c24c6673 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -13,8 +13,22 @@ from .conf.settings import AVAILABLE_INDEXING_FUNCTIONS available_indexing_functions_string = (_(u'Available functions: %s') % u','.join([u'%s()' % name for name, function in AVAILABLE_INDEXING_FUNCTIONS.items()])) if AVAILABLE_INDEXING_FUNCTIONS else u'' -class Index(MPTTModel): - parent = TreeForeignKey('self', null=True, blank=True, related_name='index_meta_class') +class Index(models.Model): + name = models.CharField(max_length=64, verbose_name=_(u'name')) + title = models.CharField(max_length=128, verbose_name=_(u'title')) + enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) + + def __unicode__(self): + return self.title + + class Meta: + verbose_name = _(u'index') + verbose_name_plural = _(u'indexes') + + +class IndexTemplateNode(MPTTModel): + parent = TreeForeignKey('self', null=True, blank=True, related_name='index_template_node') + index = models.ForeignKey(Index, verbose_name=_(u'index')) expression = models.CharField(max_length=128, verbose_name=_(u'indexing expression'), help_text=_(u'Enter a python string expression to be evaluated.')) # % available_indexing_functions_string) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) @@ -23,14 +37,21 @@ class Index(MPTTModel): def __unicode__(self): return self.expression if not self.link_documents else u'%s/[document]' % self.expression + #@models.permalink + #def get_absolute_url(self): + # return ('index_instance_list', [self.pk]) + + #def get_document_list_display(self): + # return u', '.join([d.file_filename for d in self.documents.all()]) + class Meta: - verbose_name = _(u'index') - verbose_name_plural = _(u'indexes') + verbose_name = _(u'index template node') + verbose_name_plural = _(u'indexes template nodes') + - -class IndexInstance(MPTTModel): - parent = TreeForeignKey('self', null=True, blank=True, related_name='index_meta_instance') - index = models.ForeignKey(Index, verbose_name=_(u'index')) +class IndexInstanceNode(MPTTModel): + parent = TreeForeignKey('self', null=True, blank=True, related_name='index_instance_node') + index_template_node = models.ForeignKey(IndexTemplateNode, verbose_name=_(u'index template node')) value = models.CharField(max_length=128, blank=True, verbose_name=_(u'value')) documents = models.ManyToManyField(Document, verbose_name=_(u'documents')) @@ -41,21 +62,21 @@ class IndexInstance(MPTTModel): def get_absolute_url(self): return ('index_instance_list', [self.pk]) - def get_document_list_display(self): - return u', '.join([d.file_filename for d in self.documents.all()]) + #def get_document_list_display(self): + # return u', '.join([d.file_filename for d in self.documents.all()]) class Meta: - verbose_name = _(u'index instance') - verbose_name_plural = _(u'indexes instances') + verbose_name = _(u'index instance node') + verbose_name_plural = _(u'indexes instance nodes') class DocumentRenameCount(models.Model): - index_instance = models.ForeignKey(IndexInstance, verbose_name=_(u'index instance')) + index_instance_node = models.ForeignKey(IndexInstanceNode, verbose_name=_(u'index instance')) document = models.ForeignKey(Document, verbose_name=_(u'document')) suffix = models.PositiveIntegerField(blank=True, verbose_name=(u'suffix')) def __unicode__(self): - return u'%s - %s - %s' % (self.index_instance, self.document, self.suffix or u'0') + return u'%s - %s - %s' % (self.index_instance_node, self.document, self.suffix or u'0') class Meta: verbose_name = _(u'document rename count') diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 8d405fc3d5..98aaee47e1 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -15,7 +15,7 @@ from common.utils import encapsulate from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) -from .models import IndexInstance +from .models import (Index, IndexTemplateNode, IndexInstanceNode) from .api import (get_breadcrumbs, get_instance_link, do_rebuild_all_indexes) from .widgets import index_instance_item_link diff --git a/apps/document_indexing/widgets.py b/apps/document_indexing/widgets.py index bc25f8e0e5..6e01a407ed 100644 --- a/apps/document_indexing/widgets.py +++ b/apps/document_indexing/widgets.py @@ -1,13 +1,15 @@ +from __future__ import absolute_import + from django.utils.safestring import mark_safe -from document_indexing.models import IndexInstance +from .models import IndexInstanceNode FOLDER_W_DOCUMENTS = u'folder_page' FOLDER_ICON = u'folder' def index_instance_item_link(index_instance_item): - if isinstance(index_instance_item, IndexInstance): + if isinstance(index_instance_item, IndexInstanceNode): if index_instance_item.index.link_documents: icon = FOLDER_W_DOCUMENTS else: diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 965e12617e..2cf404612d 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -152,6 +152,19 @@ When the following message appears $ ./manage.py migrate documents $ ./manage.py migrate document_signatures + $ ./manage.py migrate permissions 0001 --fake + $ ./manage.py migrate permissions + +:: +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: yes Backward incompatible changes From 36a077fb7ef87f02a9075d18a338edecc86eb828 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 01:25:22 -0400 Subject: [PATCH 330/484] Add index setup views and related permissions, urls and links --- apps/document_indexing/__init__.py | 40 +++- apps/document_indexing/permissions.py | 5 + apps/document_indexing/urls.py | 15 +- apps/document_indexing/views.py | 290 +++++++++++++++++++++++++- 4 files changed, 338 insertions(+), 12 deletions(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 59d6b30895..0adb88c37a 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -8,13 +8,34 @@ from navigation.api import register_top_menu, register_sidebar_template, \ from main.api import register_maintenance_links from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document +from project_setup.api import register_setup -#from .models import IndexInstance +from .models import (Index, IndexTemplateNode, IndexInstanceNode) from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, - PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) + PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES, + PERMISSION_DOCUMENT_INDEXING_SETUP, + PERMISSION_DOCUMENT_INDEXING_CREATE, + PERMISSION_DOCUMENT_INDEXING_EDIT, + PERMISSION_DOCUMENT_INDEXING_DELETE +) -""" -index_list = {'text': _(u'index list'), 'view': 'index_instance_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} + +def is_root_node(context): + return context['node'].parent==None + + +index_setup = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} +index_setup_list = {'text': _(u'index list'), 'view': 'index_setup_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} +index_setup_create = {'text': _(u'create index'), 'view': 'index_setup_create', 'famfam': 'tab_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_CREATE]} +index_setup_edit = {'text': _(u'edit'), 'view': 'index_setup_edit', 'args': 'index.pk', 'famfam': 'tab_edit', 'permissions': [PERMISSION_DOCUMENT_INDEXING_EDIT]} +index_setup_delete = {'text': _(u'delete'), 'view': 'index_setup_delete', 'args': 'index.pk', 'famfam': 'tab_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_DELETE]} +index_setup_view = {'text': _(u'tree template'), 'view': 'index_setup_view', 'args': 'index.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} + +template_node_create = {'text': _(u'new child node'), 'view': 'template_node_create', 'args': 'node.pk', 'famfam': 'textfield_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} +template_node_edit = {'text': _(u'edit'), 'view': 'template_node_edit', 'args': 'node.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} +template_node_delete = {'text': _(u'delete'), 'view': 'template_node_delete', 'args': 'node.pk', 'famfam': 'textfield_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} + +index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True} document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} @@ -26,7 +47,14 @@ register_maintenance_links([rebuild_index_instances], namespace='document_indexi register_sidebar_template(['index_instance_list'], 'indexing_help.html') -register_links(IndexInstance, [index_parent]) +register_links(IndexInstanceNode, [index_parent]) register_links(Document, [document_index_list], menu_name='form_header') -""" + +register_setup(index_setup) + +register_links([Index, 'index_setup_list', 'index_setup_create', 'template_node_edit', 'template_node_delete'], [index_setup_list, index_setup_create], menu_name='secondary_menu') + +register_links(Index, [index_setup_edit, index_setup_delete, index_setup_view]) + +register_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete]) diff --git a/apps/document_indexing/permissions.py b/apps/document_indexing/permissions.py index 01f1afa652..d752e158b6 100644 --- a/apps/document_indexing/permissions.py +++ b/apps/document_indexing/permissions.py @@ -6,5 +6,10 @@ from permissions.models import PermissionNamespace, Permission document_indexing_namespace = PermissionNamespace('document_indexing', _(u'Indexing')) +PERMISSION_DOCUMENT_INDEXING_SETUP = Permission.objects.register(document_indexing_namespace, 'document_index_setup', _(u'Configure document indexes')) +PERMISSION_DOCUMENT_INDEXING_CREATE = Permission.objects.register(document_indexing_namespace, 'document_index_create', _(u'Create new document indexes')) +PERMISSION_DOCUMENT_INDEXING_EDIT = Permission.objects.register(document_indexing_namespace, 'document_index_edit', _(u'Edit document indexes')) +PERMISSION_DOCUMENT_INDEXING_DELETE = Permission.objects.register(document_indexing_namespace, 'document_index_delete', _(u'Delete document indexes')) + PERMISSION_DOCUMENT_INDEXING_VIEW = Permission.objects.register(document_indexing_namespace, 'document_index_view', _(u'View document indexes')) PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES = Permission.objects.register(document_indexing_namespace, 'document_rebuild_indexes', _(u'Rebuild document indexes')) diff --git a/apps/document_indexing/urls.py b/apps/document_indexing/urls.py index d3337e4991..74e7b11aae 100644 --- a/apps/document_indexing/urls.py +++ b/apps/document_indexing/urls.py @@ -1,7 +1,20 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('document_indexing.views', - url(r'^(?P\d+)/list/$', 'index_instance_list', (), 'index_instance_list'), + url(r'^setup/index/list/$', 'index_setup_list', (), 'index_setup_list'), + url(r'^setup/index/create/$', 'index_setup_create', (), 'index_setup_create'), + url(r'^setup/index/(?P\d+)/edit/$', 'index_setup_edit', (), 'index_setup_edit'), + url(r'^setup/index/(?P\d+)/delete/$', 'index_setup_delete', (), 'index_setup_delete'), + url(r'^setup/index/(?P\d+)/view/$', 'index_setup_view', (), 'index_setup_view'), + + url(r'^setup/template/node/(?P\d+)/create/child/$', 'template_node_create', (), 'template_node_create'), + url(r'^setup/template/node/(?P\d+)/edit/$', 'template_node_edit', (), 'template_node_edit'), + url(r'^setup/template/node/(?P\d+)/delete/$', 'template_node_delete', (), 'template_node_delete'), + + url(r'^list/$', 'index_list', (), 'index_list'), + + #Broken + url(r'^(?P\d+)/list/$', 'index_instance_list', (), 'index_instance_list'), url(r'^list/$', 'index_instance_list', (), 'index_instance_list'), url(r'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'), diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 98aaee47e1..758e2ad945 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ @@ -5,7 +7,9 @@ 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.utils.safestring import mark_safe +#from django.utils.safestring import mark_safe +from django.core.urlresolvers import reverse +from django.utils.html import conditional_escape, mark_safe from permissions.models import Permission from documents.permissions import PERMISSION_DOCUMENT_VIEW @@ -13,26 +17,302 @@ from documents.models import Document from documents.views import document_list from common.utils import encapsulate -from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, - PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES) +from .forms import IndexForm, IndexTemplateNodeForm from .models import (Index, IndexTemplateNode, IndexInstanceNode) from .api import (get_breadcrumbs, get_instance_link, do_rebuild_all_indexes) from .widgets import index_instance_item_link +from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, + PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES, + PERMISSION_DOCUMENT_INDEXING_SETUP, + PERMISSION_DOCUMENT_INDEXING_CREATE, + PERMISSION_DOCUMENT_INDEXING_EDIT, + PERMISSION_DOCUMENT_INDEXING_DELETE +) + +# Setup views +def index_setup_list(request): + context = { + 'title': _(u'indexes'), + 'hide_object': True, + 'list_object_variable_name': 'index', + 'extra_columns': [ + {'name': _(u'name'), 'attribute': 'name'}, + {'name': _(u'title'), 'attribute': 'title'}, + ] + } + + queryset = Index.objects.all() + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + except PermissionDenied: + queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, queryset) + + context['object_list'] = queryset + + return render_to_response('generic_list.html', + context, + context_instance=RequestContext(request) + ) +def index_setup_create(request): + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_CREATE]) + + if request.method == 'POST': + form = IndexForm(request.POST) + if form.is_valid(): + index = form.save() + #apply_default_acls(folder, request.user) + messages.success(request, _(u'Index created successfully.')) + return HttpResponseRedirect(reverse('index_setup_list')) + else: + form = IndexForm() + + return render_to_response('generic_form.html', { + 'title': _(u'create index'), + 'form': form, + }, + context_instance=RequestContext(request)) + + +def index_setup_edit(request, index_pk): + index = get_object_or_404(Index, pk=index_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_CREATE, request.user, index) + + if request.method == 'POST': + form = IndexForm(request.POST, instance=index) + if form.is_valid(): + form.save() + messages.success(request, _(u'Index edited successfully')) + return HttpResponseRedirect(reverse('index_setup_list')) + else: + form = IndexForm(instance=index) + + return render_to_response('generic_form.html', { + 'title': _(u'edit index: %s') % index, + 'form': form, + 'index': index, + 'object_name': _(u'index'), + 'navigation_object_name': 'index', + }, + context_instance=RequestContext(request)) + + +def index_setup_delete(request, index_pk): + index = get_object_or_404(Index, pk=index_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_DELETE]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_DELETE, request.user, index) + + post_action_redirect = reverse('index_setup_list') + + 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', '/'))) + + if request.method == 'POST': + try: + index.delete() + messages.success(request, _(u'Index: %s deleted successfully.') % index) + except Exception, e: + messages.error(request, _(u'Index: %(index)s delete error: %(error)s') % { + 'index': index, 'error': e}) + + return HttpResponseRedirect(next) + + context = { + 'index': index, + 'object_name': _(u'index'), + 'navigation_object_name': 'index', + 'delete_view': True, + 'previous': previous, + 'next': next, + 'title': _(u'Are you sure you with to delete the index: %s?') % index, + 'form_icon': u'tab_delete.png', + } + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + + +def index_setup_view(request, index_pk): + index = get_object_or_404(Index, pk=index_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, index) + + root, created = IndexTemplateNode.objects.get_or_create(parent=None, index=index) + object_list = root.get_descendants(include_self=True) + + context = { + 'object_list': object_list, + 'index': index, + 'object_name': _(u'index'), + 'list_object_variable_name': 'node', + 'navigation_object_name': 'index', + 'title': _(u'tree template nodes for index: %s') % index, + 'hide_object': True, + 'extra_columns': [ + {'name': _(u'level'), 'attribute': encapsulate(lambda x: u''.join([mark_safe(conditional_escape(u'--') * (getattr(x, x._mptt_meta.level_attr) - 0)), unicode(x if x.parent else 'root') ] ))}, + ], + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def index_list(request): + context = { + 'title': _(u'indexes'), + #'hide_object': True, + #'list_object_variable_name': 'index', + #'extra_columns': [ + # {'name': _(u'name'), 'attribute': 'name'}, + # {'name': _(u'title'), 'attribute': 'title'}, + #] + 'overrided_object_links': [{}], + } + + queryset = Index.objects.all() + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + except PermissionDenied: + queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, queryset) + + context['object_list'] = queryset + + return render_to_response('generic_list.html', + context, + context_instance=RequestContext(request) + ) + +# Node views +def template_node_create(request, parent_pk): + parent_node = get_object_or_404(IndexTemplateNode, pk=parent_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, parent_node.index) + + if request.method == 'POST': + form = IndexTemplateNodeForm(request.POST) + if form.is_valid(): + node = form.save() + messages.success(request, _(u'Index template node created successfully.')) + return HttpResponseRedirect(reverse('index_setup_view', args=[node.index.pk])) + else: + form = IndexTemplateNodeForm(initial={'index': parent_node.index, 'parent': parent_node}) + + return render_to_response('generic_form.html', { + 'title': _(u'create child node'), + 'form': form, + 'index': parent_node.index, + 'object_name': _(u'index'), + 'navigation_object_name': 'index', + }, + context_instance=RequestContext(request)) + + +def template_node_edit(request, node_pk): + node = get_object_or_404(IndexTemplateNode, pk=node_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, node.index) + + if request.method == 'POST': + form = IndexTemplateNodeForm(request.POST, instance=node) + if form.is_valid(): + form.save() + messages.success(request, _(u'Index template node edited successfully')) + return HttpResponseRedirect(reverse('index_setup_view', args=[node.index.pk])) + else: + form = IndexTemplateNodeForm(instance=node) + + return render_to_response('generic_form.html', { + 'title': _(u'edit index template node: %s') % node, + 'form': form, + 'index': node.index, + 'node': node, + + 'navigation_object_list': [ + {'object': 'index', 'name': _(u'index')}, + {'object': 'node', 'name': _(u'node')} + ], + }, + context_instance=RequestContext(request)) + + +def template_node_delete(request, node_pk): + node = get_object_or_404(IndexTemplateNode, pk=node_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, node.index) + + post_action_redirect = reverse('index_setup_view', args=[node.index.pk]) + + 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', '/'))) + + if request.method == 'POST': + try: + node.delete() + messages.success(request, _(u'Node: %s deleted successfully.') % node) + except Exception, e: + messages.error(request, _(u'Node: %(node)s delete error: %(error)s') % { + 'node': node, 'error': e}) + + return HttpResponseRedirect(next) + + context = { + #'node': node, + #'object_name': _(u'index'), + #'navigation_object_name': 'index', + 'delete_view': True, + 'previous': previous, + 'next': next, + 'title': _(u'Are you sure you with to delete the index template node: %s?') % node, + 'form_icon': u'textfield_delete.png', + 'index': node.index, + 'node': node, + + 'navigation_object_list': [ + {'object': 'index', 'name': _(u'index')}, + {'object': 'node', 'name': _(u'node')} + ], + } + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + + +# User views def index_instance_list(request, index_id=None): Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) if index_id: - index_instance = get_object_or_404(IndexInstance, pk=index_id) + index_instance = get_object_or_404(IndexInstanceNode, pk=index_id) index_instance_list = [index for index in index_instance.get_children().order_by('value')] breadcrumbs = get_breadcrumbs(index_instance) if index_instance.documents.count(): for document in index_instance.documents.all().order_by('file_filename'): index_instance_list.append(document) else: - index_instance_list = IndexInstance.objects.filter(parent=None) + index_instance_list = IndexInstanceNode.objects.filter(parent=None) breadcrumbs = get_instance_link() index_instance = None From 8e54649b2a033c893a3b376fed9b1c055330df11 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 01:26:33 -0400 Subject: [PATCH 331/484] Add indexing migrations and new models --- ...ique_index_name__add_unique_index_title.py | 153 ++++++++++++++++++ apps/document_indexing/models.py | 4 +- 2 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py diff --git a/apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py b/apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py new file mode 100644 index 0000000000..8593f8253a --- /dev/null +++ b/apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py @@ -0,0 +1,153 @@ +# 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 unique constraint on 'Index', fields ['name'] + db.create_unique('document_indexing_index', ['name']) + + # Adding unique constraint on 'Index', fields ['title'] + db.create_unique('document_indexing_index', ['title']) + + + def backwards(self, orm): + + # Removing unique constraint on 'Index', fields ['title'] + db.delete_unique('document_indexing_index', ['title']) + + # Removing unique constraint on 'Index', fields ['name'] + db.delete_unique('document_indexing_index', ['name']) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'document_indexing.documentrenamecount': { + 'Meta': {'object_name': 'DocumentRenameCount'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_instance_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexInstanceNode']"}), + 'suffix': ('django.db.models.fields.PositiveIntegerField', [], {'blank': 'True'}) + }, + 'document_indexing.index': { + 'Meta': {'object_name': 'Index'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) + }, + 'document_indexing.indexinstancenode': { + 'Meta': {'object_name': 'IndexInstanceNode'}, + 'documents': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.Document']", 'symmetrical': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_template_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexTemplateNode']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_instance_node'", 'null': 'True', 'to': "orm['document_indexing.IndexInstanceNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}) + }, + 'document_indexing.indextemplatenode': { + 'Meta': {'object_name': 'IndexTemplateNode'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'expression': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.Index']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'link_documents': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_template_node'", 'null': 'True', 'to': "orm['document_indexing.IndexTemplateNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_indexing'] diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index 48c24c6673..274d2b06f3 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -14,8 +14,8 @@ available_indexing_functions_string = (_(u'Available functions: %s') % u','.join class Index(models.Model): - name = models.CharField(max_length=64, verbose_name=_(u'name')) - title = models.CharField(max_length=128, verbose_name=_(u'title')) + name = models.CharField(unique=True, max_length=64, verbose_name=_(u'name'), help_text=_(u'Internal name used to reference this index.')) + title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title')) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) def __unicode__(self): From 65b20313d795409026b9db48f351efd11ec9357c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 01:26:50 -0400 Subject: [PATCH 332/484] Add index creation and edit form --- apps/document_indexing/forms.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 apps/document_indexing/forms.py diff --git a/apps/document_indexing/forms.py b/apps/document_indexing/forms.py new file mode 100644 index 0000000000..e9224b9ab0 --- /dev/null +++ b/apps/document_indexing/forms.py @@ -0,0 +1,27 @@ +from __future__ import absolute_import + +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from .models import Index, IndexTemplateNode + + +class IndexForm(forms.ModelForm): + """ + A standard model form to allow users to create a new index + """ + class Meta: + model = Index + + +class IndexTemplateNodeForm(forms.ModelForm): + """ + A standard model form to allow users to create a new index template node + """ + def __init__(self, *args, **kwargs): + super(IndexTemplateNodeForm, self).__init__(*args, **kwargs) + self.fields['index'].widget = forms.widgets.HiddenInput() + self.fields['parent'].widget = forms.widgets.HiddenInput() + + class Meta: + model = IndexTemplateNode From 9cb23ffc1597c1c5ba4592b21c8a45bdc6aec8d1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 01:27:04 -0400 Subject: [PATCH 333/484] Add new indexing static media --- .../static/images/icons/tab.png | Bin 0 -> 578 bytes .../static/images/icons/tab_delete.png | Bin 0 -> 1162 bytes .../static/images/icons/textfield_delete.png | Bin 0 -> 1232 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/document_indexing/static/images/icons/tab.png create mode 100644 apps/document_indexing/static/images/icons/tab_delete.png create mode 100644 apps/document_indexing/static/images/icons/textfield_delete.png diff --git a/apps/document_indexing/static/images/icons/tab.png b/apps/document_indexing/static/images/icons/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..0bff3c4d63c2cbbdcd72dfe90f90f4e9d1fd705c GIT binary patch literal 578 zcmV-I0=@l-P)u(Zue;%*G7_bH(XOxHXd=P2f+(Kz6qTNxCo5V@>EML`?LUNPkRVX>BJ%Q-lQD z3t(^uth+OU?>|e3>bL@UB7sOQ{MTO#v;8g57!x^-hX5M)hh@N20mX;pZiqVhKg&TU z^_4p>^9FN@4r}m5es>voLkSLt^E>aD7nM^$Nb`SxinMj2@b0NwfS%-3j429gL}{r0 zt^SS*H0o4~cycmU%x4d7wxO1q`*zvU9z}AX58+4%)PR`2M z{*uy#0;Z_@)aZLuDm5bH&?4HioqR@H3*{O_ZmS?3O#z@PvV_HzZScCNk@L()uLPO$ z$x5TkR3UVXy!ZP0l6FG=yU_ze3PJP209A6U*&jnl!GA#j5CFV-fd2vv08ek5h7xZh Q7ytkO07*qoM6N<$f-V984gdfE literal 0 HcmV?d00001 diff --git a/apps/document_indexing/static/images/icons/tab_delete.png b/apps/document_indexing/static/images/icons/tab_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..e2aec7a214c2bda3e1ec57438a4fc82d00baabc4 GIT binary patch literal 1162 zcmV;51aKdesDl`cBqk*C!=KCx8jK;37=LJ^L4t`1iP20%W#ABg7@33+ z87M@=&7go=$1dGjFY9`GF1}ye>Do2AjwbuzzUIw2{qlX^`@GM4`wnN@HWqU5Sm3b; zU=aY93+SO&JD-5!KB$O-R8>)mo6QoAexYa_S|px?9)0@c?u|!i+R6ujf3V}@Hbmr3i2h}696uX@M?o3@SExcRYhwxk*?Rs) z99!;lLl#A*(~%EA>V0Gqa7lnruyPJI&%+WVn4(1Qq?r4M2EhP=3Bb2(NtRwQ_ZW-# za>^)-ep+ntB1~CDdEXh-e*HeG&vwD$(n-b<1=s6aAU(ewaoLr%H5&jaw=4^)TtI#@ z<$?%9RdLTpucP+#C-677qU@;v1ZP^AIT=IE#UBye*^b8Bn{g-~fE7*c<)R?KAhZr? z?$+A^4?|H=7kCl3_V?hfm)}Ixn!Hg)hDMoG#Ao1-{R6pK^^{2W(`RHN*B!TA;*nbR`X~Tv+=X5g! z8BwJK`_CLh*_sZ-db-J46J$vy0ds01bMcivcEwv_IH&Ni_mMVuxa&b zlX|_koDNr=={TAl0;H1zPuVf5O(1NT=a34`n;-h|VeMU?Q$66T@Pel@Y*8)A?c&T} zK12J};0S0B3l?1{0s#Am@yPhYOFg$GW6|2`%E}Z7o+6&(h164E)YBYC0D3Q7M!yz4 z{L0UN?4!No#Q?ziy7k52*txZ(?wYBvc85b%;3_EruP79BQi}SqPzV=)?Z@S@@X;;3 zeLHB+5bKB>iZhrYr6kqQ)%coP{Yze0Dhey@8MmG>!@O`f82aGAwc+pS?*Pll=~9d$ zf?(Z;^;<8AJ2RK+MD!eZPprObsx&aTC&RA-lvWS%m)fVbksZ^QpR cfWHJ703@b#hm%ozWdHyG07*qoM6N<$f}{Q{-T(jq literal 0 HcmV?d00001 diff --git a/apps/document_indexing/static/images/icons/textfield_delete.png b/apps/document_indexing/static/images/icons/textfield_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..1b0e5b470c01a8f6013c4c2060208e8ad70094b9 GIT binary patch literal 1232 zcmV;>1TXuEP);AN9vNcI*?!BMqyZ7ccY1S-hmwLmwH@W}LIltfUob!co&hdY4j7%9E z92{Vb?J!MqO`J-S1WJ4;6bf~T-}T{en6LFFdGAi)H8qR#DBTkjnHKmg@KsRTdgx(7%4QDij3!FGE>EZ$SV|W+W0j+daE> zLap&&VPOGBj(mk|HVbowNHA{VskWzKkO0{db_+$wWEbxK6W?L)TYGVwj;YifRHFub z#R1sQiQFt7%U8i7JYJs%x~{`VN6rlxhOsLCbAn=02?{KHoM;)d`ZYz&P^;C#G|HS4 zf@3oA$+b9^ca4=o0J8nC`%|`Wrv3;?mRDbjst1y)ltN(9`L3NION3paP7Dl&%XV^a z^gPD%5VkL*iT%y#xCZ!wA|wK1da(EC%3;n}TX=X~C8gSEyvT+rcOS>v+G#1eau( zzFNE!Ie?BEza!Xt2-&ewq`&_L`kg7;$;M{XcWg&{&jCcg{2bRc4eYs&VhT*1W4h-> z=gquK!Ks+Pa2C;{zhLu+pCA)C34L;c1f&oG>+JjH?qU8+82V@w?eBen=ogXA?yK!;&j7xf6 zBVta~mS=Xk0XKgd!1_o1Fven(0QHMZ21uvK<{V2|=fpK*Jcjj6e#nGcaVut0o*>I% zz=>Z`ApLWds+gf+=+BbRBtt>4f5!c(J66PWMr?%qd7e^F;FGmib+w!Bo& zGQCaBk3mvuXzH2w1As(sBYo}W9sD>kb&$Shnd8(a24Mc&s9+P%Z#e$Krca-3YJ4TQ z`FY{VLV>%3%~@wsa~t{V0xrgrkvB$S@6)A8F=51*TOdo5rB-P31Gf@qw?3k^%->D6 z`Me%z_4SZEV)&?*^O<-Y=PzBx-!pfI-uxrhL(hmdnR!^tUy(=y+2gObG;Ql_-tcat zBDd#tc+BX=x$soHumAe(-$dr3BE^_^nCov5geK^4^i=1Zv*wX#$Yj%GaR)U6E9Cq^ ue|A+zQ#FOX*rGWjgjZ3wtM>Mv00RJPiy!RflEfJR0000 Date: Wed, 1 Feb 2012 13:43:24 -0400 Subject: [PATCH 334/484] Documentation updates --- docs/changelog.rst | 721 ------------------ docs/conf.py | 4 +- docs/{faq.rst => faq/index.rst} | 17 +- docs/features.rst | 100 --- docs/index.rst | 96 ++- docs/intro/features.rst | 100 +++ docs/{ => intro}/installation.rst | 74 +- docs/intro/overview.rst | 19 + docs/{ => intro}/requirements.rst | 0 docs/releases/0.10.1.rst | 10 + docs/releases/0.10.rst | 51 ++ docs/releases/0.11.1.rst | 8 + docs/releases/0.11.rst | 32 + docs/releases/0.12.rst | 30 +- docs/releases/0.5.1.rst | 10 + docs/releases/0.5.rst | 300 ++++++++ docs/releases/0.7.3.rst | 32 + docs/releases/0.7.4.rst | 6 + docs/releases/0.7.5.rst | 16 + docs/releases/0.7.6.rst | 23 + docs/releases/0.7.rst | 13 + docs/releases/0.8.1.rst | 32 + docs/releases/0.8.2.rst | 24 + docs/releases/0.8.3.rst | 29 + docs/releases/0.8.rst | 62 ++ docs/releases/0.9.1.rst | 7 + docs/releases/0.9.rst | 44 ++ docs/releases/index.rst | 25 +- docs/{ => topics}/contributors.rst | 0 docs/{ => topics}/development.rst | 0 docs/{ => topics}/settings.rst | 0 .../{credits.rst => topics/software_used.rst} | 6 +- docs/{ => topics}/technical.rst | 0 docs/topics/transformations.rst | 12 + docs/updates.rst | 5 - 35 files changed, 994 insertions(+), 914 deletions(-) delete mode 100644 docs/changelog.rst rename docs/{faq.rst => faq/index.rst} (89%) delete mode 100644 docs/features.rst create mode 100644 docs/intro/features.rst rename docs/{ => intro}/installation.rst (69%) create mode 100644 docs/intro/overview.rst rename docs/{ => intro}/requirements.rst (100%) create mode 100644 docs/releases/0.10.1.rst create mode 100644 docs/releases/0.10.rst create mode 100644 docs/releases/0.11.1.rst create mode 100644 docs/releases/0.11.rst create mode 100644 docs/releases/0.5.1.rst create mode 100644 docs/releases/0.5.rst create mode 100644 docs/releases/0.7.3.rst create mode 100644 docs/releases/0.7.4.rst create mode 100644 docs/releases/0.7.5.rst create mode 100644 docs/releases/0.7.6.rst create mode 100644 docs/releases/0.7.rst create mode 100644 docs/releases/0.8.1.rst create mode 100644 docs/releases/0.8.2.rst create mode 100644 docs/releases/0.8.3.rst create mode 100644 docs/releases/0.8.rst create mode 100644 docs/releases/0.9.1.rst create mode 100644 docs/releases/0.9.rst rename docs/{ => topics}/contributors.rst (100%) rename docs/{ => topics}/development.rst (100%) rename docs/{ => topics}/settings.rst (100%) rename docs/{credits.rst => topics/software_used.rst} (98%) rename docs/{ => topics}/technical.rst (100%) create mode 100644 docs/topics/transformations.rst delete mode 100644 docs/updates.rst diff --git a/docs/changelog.rst b/docs/changelog.rst deleted file mode 100644 index 0a8a36c649..0000000000 --- a/docs/changelog.rst +++ /dev/null @@ -1,721 +0,0 @@ -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 - - -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..6c4a38113a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,10 +48,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. diff --git a/docs/faq.rst b/docs/faq/index.rst similarity index 89% rename from docs/faq.rst rename to docs/faq/index.rst index ee80548d28..2f836bcbdd 100644 --- a/docs/faq.rst +++ b/docs/faq/index.rst @@ -4,9 +4,11 @@ FAQ Frequently asked questions and solutions +Database related +---------------- -_mysql_exceptions.OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='") ------------------------------------------------------------------------------------------------------------------------------------------------------- +Q: _mysql_exceptions.OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='") +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Solution:: @@ -25,8 +27,8 @@ _mysql_exceptions.OperationalError: (1267, "Illegal mix of collations (latin1_sw - http://stackoverflow.com/questions/1073295/django-character-set-with-mysql-weirdness -Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row 1 ----------------------------------------------------------------------------------- +Q: Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row 1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When using ``MySQL`` and doing OCR on languages other than English @@ -37,8 +39,11 @@ When using ``MySQL`` and doing OCR on languages other than English - Ref: 2- http://markmail.org/message/bqajx2utvmtriixi -File system links not showing when serving content with ``Samba`` ------------------------------------------------------------------ +Document sharing +---------------- + +Q: File system links not showing when serving content with ``Samba`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Solution: 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/index.rst b/docs/index.rst index b6da2d88e8..3e90a4a9ae 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,49 +1,81 @@ -======== -Overview -======== -Open source, Django_ based document manager with custom metadata indexing, file serving integration, OCR_ capabilities, document versioning and digital signature verification. +.. _index: + +======================== +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. .. _Django: http://www.djangoproject.com/ +================= +Links of interest +================= + :Website: http://www.mayan-edms.com :Source: http://github.com/rosarior/mayan -:Video: http://bit.ly/pADNXv +:Video: http://bit.ly/pADNXv :Issue tracker: http://github.com/rosarior/mayan/issues :Mailing list: http://groups.google.com/group/mayan-edms -**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/ +First steps +=========== + + :doc:`Overview ` | + :doc:`Features ` | + :doc:`Requirements ` | + :doc:`Installation ` -======== -Contents -======== +Understanding Mayan EDMS +======================== + :doc:`Transformations ` + + +Between versions +================ .. toctree:: :maxdepth: 2 - features - requirements - installation - releases/index - settings - development - contributors - credits - faq - license + releases/index + + +Customization and fine tunning +============================== + + :doc:`Settings ` + + +For developers +============== + + :doc:`Development ` + + +Credits +======= + + :doc:`Contributors ` | + :doc:`Software used ` | + :doc:`Lincensing ` + + +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`_. + +* Report bugs with **Mayan EDMS** using Github's `ticket tracker`_. + +.. _archives of the mayan-edms mailing list: http://groups.google.com/group/django-users/ +.. _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..c1f77d519f --- /dev/null +++ b/docs/intro/features.rst @@ -0,0 +1,100 @@ +======== +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`_ + +* 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. + +* 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. + +* Multilingual OCR support. + + * As supported by the OCR engine tesseract. + +* Duplicated document search. + +* Plugable storage backends (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/installation.rst b/docs/intro/installation.rst similarity index 69% rename from docs/installation.rst rename to docs/intro/installation.rst index cba4e5e9f7..346318a96a 100644 --- a/docs/installation.rst +++ b/docs/intro/installation.rst @@ -52,25 +52,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 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,11 +81,11 @@ 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': { @@ -98,45 +98,45 @@ To install **Mayan EDMS** on Webfaction_, follow these steps: $ } $ } -#. 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 (during this step two errors will appears about failling to install indexes on ``documents.Document`` and ``documents.DocumentPage`` models, ignore them for now):: $ ./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 DjangoZoom ---------- @@ -152,6 +152,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 +161,4 @@ 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 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 100% rename from docs/requirements.rst rename to docs/intro/requirements.rst 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..fc6c4accb6 --- /dev/null +++ b/docs/releases/0.11.rst @@ -0,0 +1,32 @@ +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 index 965e12617e..bbfc252a3a 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -126,16 +126,20 @@ column after those is ignored. Upgrading from a previous version ================================= -:: +Start off by creating the new database structures with:: $ ./manage.py syncdb + +Then migrate existing database schema with:: + $ ./manage.py migrate permissions 0001 --fake $ ./manage.py migrate permissions When the following message appears -.. epigraph:: +:: + The following content types are stale and need to be deleted: permissions | permission @@ -146,13 +150,31 @@ When the following message appears Type 'yes' to continue, or 'no' to cancel: - Types ``yes`` and press **Enter** +Type ``yes`` and press **Enter** -:: +And continue migrating database schema with:: $ ./manage.py migrate documents $ ./manage.py migrate document_signatures + $ ./manage.py migrate permissions 0001 --fake + $ ./manage.py migrate permissions +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 complete. Backward incompatible changes ============================= 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 index e944ce5a8d..508bb73812 100644 --- a/docs/releases/index.rst +++ b/docs/releases/index.rst @@ -14,7 +14,6 @@ up to and including the new version. Final releases ============== - 0.12 release ----------- .. toctree:: @@ -22,7 +21,25 @@ Final releases 0.12 -Historic releases -================= +Historic changelogs +=================== +.. toctree:: + :maxdepth: 1 -.. include:: ../changelog.rst + 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/contributors.rst b/docs/topics/contributors.rst similarity index 100% rename from docs/contributors.rst rename to docs/topics/contributors.rst diff --git a/docs/development.rst b/docs/topics/development.rst similarity index 100% rename from docs/development.rst rename to docs/topics/development.rst diff --git a/docs/settings.rst b/docs/topics/settings.rst similarity index 100% rename from docs/settings.rst rename to docs/topics/settings.rst diff --git a/docs/credits.rst b/docs/topics/software_used.rst similarity index 98% rename from docs/credits.rst rename to docs/topics/software_used.rst index e7d8e4a3a9..b6b0fccf79 100644 --- a/docs/credits.rst +++ b/docs/topics/software_used.rst @@ -1,6 +1,6 @@ -======= -Credits -======= +============= +Software used +============= * Python * Copyright (c) 2001-2010 Python Software Foundation. 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/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/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 From eff399612d0094cd0ead0f5e5a2b1e93e773965d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 14:41:45 -0400 Subject: [PATCH 335/484] Documentation updates --- docs/faq/index.rst | 141 +++++++++++++++++++++++-- docs/index.rst | 31 ++++-- docs/topics/document_visualization.rst | 21 ++++ docs/topics/file_storage.rst | 25 +++++ docs/topics/indexes.rst | 12 +++ docs/topics/ocr.rst | 19 ++++ docs/topics/smart_links.rst | 9 ++ 7 files changed, 238 insertions(+), 20 deletions(-) create mode 100644 docs/topics/document_visualization.rst create mode 100644 docs/topics/file_storage.rst create mode 100644 docs/topics/indexes.rst create mode 100644 docs/topics/ocr.rst create mode 100644 docs/topics/smart_links.rst diff --git a/docs/faq/index.rst b/docs/faq/index.rst index 2f836bcbdd..c92c72cc02 100644 --- a/docs/faq/index.rst +++ b/docs/faq/index.rst @@ -7,7 +7,19 @@ Frequently asked questions and solutions Database related ---------------- -Q: _mysql_exceptions.OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='") +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:: @@ -66,8 +78,11 @@ Q: File system links not showing when serving content with ``Samba`` - 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: @@ -87,8 +102,8 @@ How to store documents outside of **Mayan EDMS's** path DOCUMENTS_STORAGE_BACKEND = CustomStorage -How to enable the ``GridFS`` storage backend --------------------------------------------- +Q: How to enable the ``GridFS`` storage backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Solution: @@ -99,9 +114,19 @@ How to enable the ``GridFS`` storage backend - 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? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Site search is slow -------------------- +* 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: @@ -109,8 +134,12 @@ Site search is slow - ``documents_documentpage`` - content, recommended size: 3000 -How to enable x-sendile support for ``Apache`` ----------------------------------------------- +Webserver +--------- + +Q: How to enable x-sendile support for ``Apache`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * If using Ubuntu execute the following:: $ sudo apt-get install libapache2-mod-xsendfile @@ -125,11 +154,103 @@ How to enable x-sendile support for ``Apache`` XSendFileAllowAbove on -The included version of ``unoconv`` in my distribution is too old -------------------------------------------------------------- +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' + + +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/index.rst b/docs/index.rst index 3e90a4a9ae..2d59c73f8d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,20 +5,26 @@ 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. +.. rubric:: `Open source`_, Django_ based document manager with custom + metadata_ indexing_, file serving integration, OCR_ capabilities, + document versioning_ and `digital signature verification`_. .. _Django: http://www.djangoproject.com/ +.. _OCR: https://secure.wikimedia.org/wikipedia/en/wiki/Optical_character_recognition +.. _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 - -================= Links of interest ================= -:Website: http://www.mayan-edms.com -:Source: http://github.com/rosarior/mayan -:Video: http://bit.ly/pADNXv -:Issue tracker: http://github.com/rosarior/mayan/issues -:Mailing list: http://groups.google.com/group/mayan-edms +* Website: http://www.mayan-edms.com +* Source: http://github.com/rosarior/mayan +* Video: http://bit.ly/pADNXv +* Issue tracker: http://github.com/rosarior/mayan/issues +* Mailing list: http://groups.google.com/group/mayan-edms First steps @@ -33,7 +39,12 @@ First steps Understanding Mayan EDMS ======================== - :doc:`Transformations ` + :doc:`Transformations ` | + :doc:`Indexes ` | + :doc:`Smart links ` | + :doc:`Document visualization ` | + :doc:`OCR ` | + :doc:`File storage ` Between versions @@ -61,7 +72,7 @@ Credits :doc:`Contributors ` | :doc:`Software used ` | - :doc:`Lincensing ` + :doc:`Licensing ` Getting help diff --git a/docs/topics/document_visualization.rst b/docs/topics/document_visualization.rst new file mode 100644 index 0000000000..9474f353df --- /dev/null +++ b/docs/topics/document_visualization.rst @@ -0,0 +1,21 @@ +====================== +Document visualization +====================== + + +Mayan EDMS tries to avoid having users to download a document 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 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 user +(``python``, ``graphicsmagick``, imagemagick``) 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 rotate interactively +in the details view. diff --git a/docs/topics/file_storage.rst b/docs/topics/file_storage.rst new file mode 100644 index 0000000000..054df85465 --- /dev/null +++ b/docs/topics/file_storage.rst @@ -0,0 +1,25 @@ +============ +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 access to the files the recommended way is to create and +index which would create a directory tree like structure in the database +and then turn on the index filesystem mirror options which would create +an actual directory tree and links to the actual stored files but using +the filename of the documents as stored in the database. This +filesystem mirror of the index can them be shared with Samba across the +network. This access would be read-only, and new versions of the files +would have to be uploaded from the web GUI using the new document +versioning support. + +Mayan's 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. diff --git a/docs/topics/indexes.rst b/docs/topics/indexes.rst new file mode 100644 index 0000000000..ed4ab46e51 --- /dev/null +++ b/docs/topics/indexes.rst @@ -0,0 +1,12 @@ +======= +Indexes +======= + +Administrators first define the template of the index and 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 againts the metadata +of the documents. The index cannot be edited manually, 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. diff --git a/docs/topics/ocr.rst b/docs/topics/ocr.rst new file mode 100644 index 0000000000..ef17a2885c --- /dev/null +++ b/docs/topics/ocr.rst @@ -0,0 +1,19 @@ +=== +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 ``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 ``OCR_AUTOMATIC_OCR`` +option to ``True`` would cause all newly uploaded documents to be +queued automatically for OCR. + diff --git a/docs/topics/smart_links.rst b/docs/topics/smart_links.rst new file mode 100644 index 0000000000..ea2559e965 --- /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 currently +displayed document. The index is global, the smart links are dependant +on the current document the user is viewing. From 600fdf0b8a873ba224ca73cc3e849b08d21f161f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 17:04:33 -0400 Subject: [PATCH 336/484] Add djangodoc extension --- docs/_ext/djangodocs.py | 229 ++++++++++++++++++++++++++++++++++++++++ docs/conf.py | 13 ++- 2 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 docs/_ext/djangodocs.py 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/conf.py b/docs/conf.py index 6c4a38113a..d881a7cad6 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'] @@ -51,7 +54,7 @@ copyright = u'2011, Roberto Rosario' version = '0.12' # The full version, including alpha/beta/rc tags. -release = '0.12' +release = '0.12 beta' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -71,15 +74,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' From 3b327ff5b30de119f446d10215fb42e851039684 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 1 Feb 2012 17:04:54 -0400 Subject: [PATCH 337/484] Documentation updates, allow settings reference linking from other documents --- docs/index.rst | 2 +- docs/intro/features.rst | 2 +- docs/releases/0.12.rst | 8 +- docs/topics/document_visualization.rst | 25 +- docs/topics/ocr.rst | 5 +- docs/topics/settings.rst | 677 ++++++++++++++++--------- 6 files changed, 455 insertions(+), 264 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 2d59c73f8d..060a132d72 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -87,6 +87,6 @@ Having trouble? We'd like to help! * Report bugs with **Mayan EDMS** using Github's `ticket tracker`_. -.. _archives of the mayan-edms mailing list: http://groups.google.com/group/django-users/ +.. _archives of the mayan-edms mailing list: http://groups.google.com/group/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 index c1f77d519f..43e9bfa267 100644 --- a/docs/intro/features.rst +++ b/docs/intro/features.rst @@ -18,7 +18,7 @@ Features * Office document format support. - * Word processing files? Spreadsheets? Sresentations? They are supported too. + * Word processing files? Spreadsheets? Presentations? They are supported too. * User defined metadata fields and meta data sets. diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index bbfc252a3a..6a05583d18 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -56,10 +56,10 @@ ACL support Anonymous user support ~~~~~~~~~~~~~~~~~~~~~~ Anonymous user support is a two tier function, first is the addition of -the COMMON_ALLOW_ANONYMOUS_ACCESS that allows non authenticated 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. +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 ~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/document_visualization.rst b/docs/topics/document_visualization.rst index 9474f353df..daa9cead49 100644 --- a/docs/topics/document_visualization.rst +++ b/docs/topics/document_visualization.rst @@ -3,19 +3,32 @@ Document visualization ====================== -Mayan EDMS tries to avoid having users to download a document and leave -Mayan EDMS to be able to see them, so in essence making Mayan EDMS a +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 for conversion to PDF. The PDF is stored in a temporary +to Libreoffice_ working in headless mode (and managed by supervisor) +via unoconv 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 user -(``python``, ``graphicsmagick``, imagemagick``) and a high resolution +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 rotate 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/ diff --git a/docs/topics/ocr.rst b/docs/topics/ocr.rst index ef17a2885c..52c57282ef 100644 --- a/docs/topics/ocr.rst +++ b/docs/topics/ocr.rst @@ -4,7 +4,7 @@ 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 ``OCR_NODE_CONCURRENT_EXECUTION`` configuration +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. @@ -13,7 +13,6 @@ 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 ``OCR_AUTOMATIC_OCR`` +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/settings.rst b/docs/topics/settings.rst index ffac3c7179..9989752a7d 100644 --- a/docs/topics/settings.rst +++ b/docs/topics/settings.rst @@ -5,419 +5,598 @@ Settings **Mayan EDMS** has many configuration options that make it very adaptable to different server configurations. +.. contents:: + :local: + :depth: 1 + + Documents ---------- +========= -.. data:: DOCUMENTS_CHECKSUM_FUNCTION +.. setting:: DOCUMENTS_CHECKSUM_FUNCTION - Default: ``hashlib.sha256(x).hexdigest()`` +DOCUMENTS_CHECKSUM_FUNCTION +--------------------------- + +Default: ``hashlib.sha256(x).hexdigest()`` -.. data:: DOCUMENTS_UUID_FUNCTION +.. setting:: \DOCUMENTS_UUID_FUNCTION - Default: ``unicode(uuid.uuid4())`` +DOCUMENTS_UUID_FUNCTION +----------------------- + +Default: ``unicode(uuid.uuid4())`` -.. data:: DOCUMENTS_STORAGE_BACKEND +.. setting:: DOCUMENTS_STORAGE_BACKEND - Default: ``FileBasedStorage`` class +DOCUMENTS_STORAGE_BACKEND +------------------------- + +Default: ``FileBasedStorage`` class -.. data:: DOCUMENTS_PREVIEW_SIZE +.. setting:: DOCUMENTS_PREVIEW_SIZE + +DOCUMENTS_PREVIEW_SIZE +---------------------- - Default: ``640x480`` +Default: ``640x480`` -.. data:: DOCUMENTS_PRINT_SIZE +.. setting:: DOCUMENTS_PRINT_SIZE + +DOCUMENTS_PRINT_SIZE +-------------------- - Default: ``1400`` +Default: ``1400`` -.. data:: DOCUMENTS_MULTIPAGE_PREVIEW_SIZE - - Default: ``160x120`` +.. setting:: DOCUMENTS_MULTIPAGE_PREVIEW_SIZE + +DOCUMENTS_MULTIPAGE_PREVIEW_SIZE +-------------------------------- + +Default: ``160x120`` -.. data:: DOCUMENTS_THUMBNAIL_SIZE +.. setting:: DOCUMENTS_THUMBNAIL_SIZE + +DOCUMENTS_THUMBNAIL_SIZE +------------------------ - Default: ``50x50`` +Default: ``50x50`` -.. data:: DOCUMENTS_DISPLAY_SIZE +.. setting:: DOCUMENTS_DISPLAY_SIZE + +DOCUMENTS_DISPLAY_SIZE +---------------------- - Default: ``1200`` +Default: ``1200`` -.. data:: DOCUMENTS_RECENT_COUNT +.. setting:: DOCUMENTS_RECENT_COUNT + +DOCUMENTS_RECENT_COUNT +---------------------- - Default: ``40`` +Default: ``40`` - Maximum number of recent (created, edited, viewed) documents to - remember per user. +Maximum number of recent (created, edited, viewed) documents to +remember per user. -.. data:: DOCUMENTS_ZOOM_PERCENT_STEP +.. setting:: DOCUMENTS_ZOOM_PERCENT_STEP + +DOCUMENTS_ZOOM_PERCENT_STEP +--------------------------- - Default: ``50`` +Default: ``50`` - Amount in percent zoom in or out a document page per user interaction. +Amount in percent zoom in or out a document page per user interaction. -.. data:: DOCUMENTS_ZOOM_MAX_LEVEL +.. setting:: DOCUMENTS_ZOOM_MAX_LEVEL + +DOCUMENTS_ZOOM_MAX_LEVEL +------------------------ - Default: ``200`` +Default: ``200`` - Maximum amount in percent (%) to allow user to zoom in a document page interactively. +Maximum amount in percent (%) to allow user to zoom in a document page interactively. -.. data:: DOCUMENTS_ZOOM_MIN_LEVEL +.. setting:: DOCUMENTS_ZOOM_MIN_LEVEL + +DOCUMENTS_ZOOM_MIN_LEVEL +------------------------ - Default: ``50`` +Default: ``50`` - Minimum amount in percent (%) to allow user to zoom out a document page interactively. +Minimum amount in percent (%) to allow user to zoom out a document page interactively. -.. data:: DOCUMENTS_ROTATION_STEP +.. setting:: DOCUMENTS_ROTATION_STEP + +DOCUMENTS_ROTATION_STEP +----------------------- - Default: ``90`` +Default: ``90`` - Amount in degrees to rotate a document page per user interaction. +Amount in degrees to rotate a document page per user interaction. -.. data:: DOCUMENTS_CACHE_PATH +.. setting:: DOCUMENTS_CACHE_PATH + +DOCUMENTS_CACHE_PATH +-------------------- - Default: ``image_cache`` (relative to the installation path) +Default: ``image_cache`` (relative to the installation path) - The path where the visual representations of the documents are stored for fast display. +The path where the visual representations of the documents are stored for fast display. Converter ---------- +========= -.. data:: CONVERTER_IM_CONVERT_PATH +.. setting:: CONVERTER_IM_CONVERT_PATH + +CONVERTER_IM_CONVERT_PATH +------------------------- - Default: ``/usr/bin/convert`` +Default: ``/usr/bin/convert`` + +File path to imagemagick's convert program. - 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. -.. data:: CONVERTER_IM_IDENTIFY_PATH +.. setting:: CONVERTER_GM_PATH + +CONVERTER_GM_PATH +----------------- + +Default: ``/usr/bin/gm`` - 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. +File path to graphicsmagick's program. -.. data:: CONVERTER_GM_SETTINGS +.. setting:: CONVERTER_GM_SETTINGS + +CONVERTER_GM_SETTINGS +--------------------- + +Default: None - Default: None +Suggested options: ``-limit files 1 -limit memory 1GB -limit map 2GB -density 200`` + + +.. setting:: CONVERTER_GRAPHICS_BACKEND + +CONVERTER_GRAPHICS_BACKEND +-------------------------- + +Default: ``converter.backends.python`` +Graphics conversion backend to use. Options are: + +* ``converter.backends.imagemagick`` +* ``converter.backends.graphicsmagick`` +* ``converter.backends.python`` -.. data:: CONVERTER_GRAPHICS_BACKEND +.. setting:: CONVERTER_UNOCONV_PATH + +CONVERTER_UNOCONV_PATH +---------------------- - Default: ``converter.backends.python`` +Default: ``/usr/bin/unoconv`` - Graphics conversion backend to use. Options are: ``converter.backends.imagemagick``, - ``converter.backends.graphicsmagick`` and ``converter.backends.python``. +Path to the unoconv program. + - Suggested options: ``-limit files 1 -limit memory 1GB -limit map 2GB -density 200`` +.. setting:: CONVERTER_UNOCONV_USE_PIPE + +CONVERTER_UNOCONV_USE_PIPE +-------------------------- +Default: ``True`` -.. 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. +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 +.. setting:: LINKING_SHOW_EMPTY_SMART_LINKS + +LINKING_SHOW_EMPTY_SMART_LINKS +------------------------------ - Default: ``True`` +Default: ``True`` - Show smart links even when they don't return any documents. +Show smart links even when they don't return any documents. Storage -------- +======= -.. data:: STORAGE_GRIDFS_HOST +.. setting:: STORAGE_GRIDFS_HOST + +STORAGE_GRIDFS_HOST +------------------- - Default: ``localhost`` +Default: ``localhost`` -.. data:: STORAGE_GRIDFS_PORT +.. setting:: STORAGE_GRIDFS_PORT + +STORAGE_GRIDFS_PORT +------------------- - Default: ``27017`` +Default: ``27017`` -.. data:: STORAGE_GRIDFS_DATABASE_NAME +.. setting:: STORAGE_GRIDFS_DATABASE_NAME + +STORAGE_GRIDFS_DATABASE_NAME +---------------------------- - Default: ``document_storage`` +Default: ``document_storage`` -.. data:: STORAGE_FILESTORAGE_LOCATION +.. setting:: STORAGE_FILESTORAGE_LOCATION + +STORAGE_FILESTORAGE_LOCATION +---------------------------- - Default: ``document_storage`` +Default: ``document_storage`` Document indexing ------------------ +================= -.. data:: DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS +.. setting:: DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS + +DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS +---------------------------------------------- - Default: ``proper_name`` +Default: ``proper_name`` -.. data:: DOCUMENT_INDEXING_SUFFIX_SEPARATOR +.. setting:: DOCUMENT_INDEXING_SUFFIX_SEPARATOR + +DOCUMENT_INDEXING_SUFFIX_SEPARATOR +---------------------------------- - Default: ``_`` (underscore) +Default: ``_`` (underscore) -.. data:: DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS +.. setting:: DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS + +DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS +------------------------------------------ - Default: ``False`` +Default: ``False`` -.. data:: DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT +.. setting:: DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT + +DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT +--------------------------------------------- - Default: ``1000`` +Default: ``1000`` -.. data:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH +.. setting:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH + +DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH +--------------------------------------------- - Default: ``/tmp/mayan/documents`` +Default: ``/tmp/mayan/documents`` -.. data:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE +.. setting:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE + +DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE +----------------------------------------------- - Default: ``True`` +Default: ``True`` OCR ---- +=== -.. data:: OCR_TESSERACT_PATH - - Default: ``/bin/tesseract`` +.. setting:: OCR_TESSERACT_PATH - File path to the ``tesseract`` executable, used to perform OCR on document - page's images. +OCR_TESSERACT_PATH +------------------ - -.. data:: OCR_TESSERACT_LANGUAGE - - Default: ``eng`` +Default: ``/bin/tesseract`` - Language code passed to the ``tesseract`` executable. +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. -.. data:: OCR_REPLICATION_DELAY +.. setting:: OCR_REPLICATION_DELAY + +OCR_REPLICATION_DELAY +--------------------- - Default: ``0`` +Default: ``0`` - Amount of seconds to delay OCR of documents to allow for the node's - storage replication overhead. +Amount of seconds to delay OCR of documents to allow for the node's +storage replication overhead. -.. data:: OCR_NODE_CONCURRENT_EXECUTION +.. setting:: OCR_NODE_CONCURRENT_EXECUTION + +OCR_NODE_CONCURRENT_EXECUTION +----------------------------- - Default: ``1`` +Default: ``1`` - Maximum amount of concurrent document OCRs a node can perform. +Maximum amount of concurrent document OCRs a node can perform. -.. data:: OCR_AUTOMATIC_OCR +.. setting:: OCR_AUTOMATIC_OCR + +OCR_AUTOMATIC_OCR +----------------- - Default: ``False`` +Default: ``False`` - Automatically queue newly created documents or newly uploaded versions - of existing documents for OCR. +Automatically queue newly created documents or newly uploaded versions +of existing documents for OCR. -.. data:: OCR_QUEUE_PROCESSING_INTERVAL +.. setting:: OCR_QUEUE_PROCESSING_INTERVAL + +OCR_QUEUE_PROCESSING_INTERVAL +----------------------------- - Default: ``10`` +Default: ``10`` +.. setting:: OCR_UNPAPER_PATH -.. data:: OCR_UNPAPER_PATH +OCR_UNPAPER_PATH +---------------- - Default: ``/usr/bin/unpaper`` +Default: ``/usr/bin/unpaper`` - File path to the ``unpaper`` executable, used to clean up images before - doing OCR. +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`` + -.. 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() +====== + +.. 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() -.. data:: COMMON_DEFAULT_PAPER_SIZE - - Default: ``Letter`` - +.. setting:: COMMON_DEFAULT_PAPER_SIZE -.. data:: COMMON_DEFAULT_PAGE_ORIENTATION - - Default: ``Portrait`` - +COMMON_DEFAULT_PAPER_SIZE +------------------------- -.. data:: 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 - - -.. data:: COMMON_AUTO_ADMIN_USERNAME - - Default: ``admin`` - - Username of the automatically created superuser - - -.. data:: COMMON_AUTO_ADMIN_PASSWORD - - Default: ``admin`` - - Default password of the automatically created superuser - - -.. data:: 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',) +Default: ``Letter`` -.. data:: COMMON_ALLOW_ANONYMOUS_ACCESS +.. setting:: COMMON_DEFAULT_PAGE_ORIENTATION - Default: ``False`` - - Allow non authenticated users, access to all views +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. -.. 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. - - +.. 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 ----- +==== -.. data:: MAIN_SIDE_BAR_SEARCH - - Default: ``False`` - - Controls whether the search functionality is provided by a sidebar widget or by a menu entry. - +.. setting:: MAIN_SIDE_BAR_SEARCH -.. data:: MAIN_DISABLE_HOME_VIEW - - Default: ``False`` +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`` + + +.. setting:: MAIN_DISABLE_ICONS + +MAIN_DISABLE_ICONS +------------------ + +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 +.. setting:: ROLES_DEFAULT_ROLES + +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. +.. setting:: SIGNATURES_KEYSERVERS + +SIGNATURES_KEYSERVERS +--------------------- + +Default: ``['pool.sks-keyservers.net']`` + +List of keyservers to be queried for unknown keys. -.. data:: SIGNATURES_GPG_HOME - - Default: ``gpg_home`` - - Home directory used to store keys as well as configuration files. +.. setting:: SIGNATURES_GPG_HOME + +SIGNATURES_GPG_HOME +------------------- + +Default: ``gpg_home`` + +Home directory used to store keys as well as configuration files. From a91d7882f8f74ba9fe85430566c555bfb1fd18a9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 00:05:20 -0400 Subject: [PATCH 338/484] Don't display object type on the metadata set member add remove view --- apps/metadata/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/metadata/views.py b/apps/metadata/views.py index 6c66baaf4d..370271f04a 100644 --- a/apps/metadata/views.py +++ b/apps/metadata/views.py @@ -456,8 +456,8 @@ def setup_metadata_set_edit(request, 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, From 78b73b81e3e7c959379deecb9949e73f9f2e3289 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 00:10:16 -0400 Subject: [PATCH 339/484] Increase folder title field size to 128 characters --- apps/folders/migrations/0001_initial.py | 144 ++++++++++++++++++ .../migrations/0002_increase_title_size.py | 121 +++++++++++++++ apps/folders/migrations/__init__.py | 0 apps/folders/models.py | 2 +- docs/releases/0.12.rst | 6 +- 5 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 apps/folders/migrations/0001_initial.py create mode 100644 apps/folders/migrations/0002_increase_title_size.py create mode 100644 apps/folders/migrations/__init__.py diff --git a/apps/folders/migrations/0001_initial.py b/apps/folders/migrations/0001_initial.py new file mode 100644 index 0000000000..a821c8cd6e --- /dev/null +++ b/apps/folders/migrations/0001_initial.py @@ -0,0 +1,144 @@ +# 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 'Folder' + db.create_table('folders_folder', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('datetime_created', self.gf('django.db.models.fields.DateTimeField')()), + )) + db.send_create_signal('folders', ['Folder']) + + # Adding unique constraint on 'Folder', fields ['title', 'user'] + db.create_unique('folders_folder', ['title', 'user_id']) + + # Adding model 'FolderDocument' + db.create_table('folders_folderdocument', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('folder', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['folders.Folder'])), + ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])), + )) + db.send_create_signal('folders', ['FolderDocument']) + + + def backwards(self, orm): + + # Removing unique constraint on 'Folder', fields ['title', 'user'] + db.delete_unique('folders_folder', ['title', 'user_id']) + + # Deleting model 'Folder' + db.delete_table('folders_folder') + + # Deleting model 'FolderDocument' + db.delete_table('folders_folderdocument') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'folders.folder': { + 'Meta': {'ordering': "('title',)", 'unique_together': "(('title', 'user'),)", 'object_name': 'Folder'}, + 'datetime_created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'folders.folderdocument': { + 'Meta': {'object_name': 'FolderDocument'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'folder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['folders.Folder']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['folders'] diff --git a/apps/folders/migrations/0002_increase_title_size.py b/apps/folders/migrations/0002_increase_title_size.py new file mode 100644 index 0000000000..f992dd36d2 --- /dev/null +++ b/apps/folders/migrations/0002_increase_title_size.py @@ -0,0 +1,121 @@ +# 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 'Folder.title' + db.alter_column('folders_folder', 'title', self.gf('django.db.models.fields.CharField')(max_length=128)) + + + def backwards(self, orm): + + # Changing field 'Folder.title' + db.alter_column('folders_folder', 'title', self.gf('django.db.models.fields.CharField')(max_length=32)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'folders.folder': { + 'Meta': {'ordering': "('title',)", 'unique_together': "(('title', 'user'),)", 'object_name': 'Folder'}, + 'datetime_created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'folders.folderdocument': { + 'Meta': {'object_name': 'FolderDocument'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'folder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['folders.Folder']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['folders'] diff --git a/apps/folders/migrations/__init__.py b/apps/folders/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/folders/models.py b/apps/folders/models.py index e58db8ab91..a52578e158 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -8,7 +8,7 @@ from documents.models import Document class Folder(models.Model): - title = models.CharField(max_length=32, verbose_name=_(u'title'), db_index=True) + title = models.CharField(max_length=128, verbose_name=_(u'title'), db_index=True) user = models.ForeignKey(User, verbose_name=_(u'user')) datetime_created = models.DateTimeField(verbose_name=_(u'datetime created')) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 6a05583d18..dd198d13ed 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -158,6 +158,10 @@ And continue migrating database schema with:: $ ./manage.py migrate document_signatures $ ./manage.py migrate permissions 0001 --fake $ ./manage.py migrate permissions + $ ./manage.py migrate folders 0001 --fake + $ ./manage.py migrate folders + $ ./manage.py migrate document_indexing 0001 --fake + $ ./manage.py migrate document_indexing Again when a similar messages appears :: @@ -174,7 +178,7 @@ Again when a similar messages appears Type ``yes`` and press **Enter** -The upgrade procedure is complete. +The upgrade procedure is now complete. Backward incompatible changes ============================= From 556c0824fbee8cbf63032298ab80b181a96858fa Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 00:16:34 -0400 Subject: [PATCH 340/484] Return a QuerySet instead of a list of documents --- apps/tags/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/tags/views.py b/apps/tags/views.py index 712ecd86c9..aa6799343b 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -209,11 +209,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, From 4e3a16da829a557d7bfcfa775c3fc5b7a95e8477 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 00:38:58 -0400 Subject: [PATCH 341/484] Return a QuerySet of documents instead --- apps/folders/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/folders/models.py b/apps/folders/models.py index a52578e158..cf234cf397 100644 --- a/apps/folders/models.py +++ b/apps/folders/models.py @@ -26,7 +26,7 @@ class Folder(models.Model): @property def documents(self): - return [folder_document.document for folder_document in self.folderdocument_set.all()] + return Document.objects.filter(folderdocument__folder=self) def remove_document(self, document): folder_document = self.folderdocument_set.get(document=document) From 1ccdbb7973623c8352fc08dada8db43ae67388dc Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 01:01:25 -0400 Subject: [PATCH 342/484] Add extra logging --- apps/acls/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/acls/views.py b/apps/acls/views.py index cfd4fc046c..728cc16b65 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -398,9 +398,13 @@ def acl_setup_valid_classes(request): def acl_class_acl_list(request, access_object_class_gid): + logger.debug('access_object_class_gid: %s' % access_object_class_gid) + Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL]) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) + logger.debug('access_object_class: %s' % access_object_class) + context = { 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), 'title': _(u'default access control lists for class: %s') % access_object_class, From 4ed7c714e027ccd3a90313062641a8a6b00a7620 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 01:02:17 -0400 Subject: [PATCH 343/484] Don't return non existant class default holders --- apps/acls/managers.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 66991003d2..540c1ff3b2 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -259,16 +259,15 @@ class DefaultAccessEntryManager(models.Manager): """ def get_holders_for(self, cls): cls = get_source_object(cls) - #if isinstance(cls, EncapsulatedObject): - # cls = cls.source_object - content_type = ContentType.objects.get_for_model(cls) holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type): - entry = ClassAccessHolder.encapsulate(access_entry.holder_object) + if access_entry.holder_object: + # Reference to a non existant content type object + entry = ClassAccessHolder.encapsulate(access_entry.holder_object) - if entry not in holder_list: - holder_list.append(entry) + if entry not in holder_list: + holder_list.append(entry) return holder_list From a3ccc9c005d387af58313fe0b1b47b0ffccb9241 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 01:02:40 -0400 Subject: [PATCH 344/484] Don't assign an ACL to a non existant holder --- apps/acls/utils.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/acls/utils.py b/apps/acls/utils.py index 2d9c9a92e7..01673490e2 100644 --- a/apps/acls/utils.py +++ b/apps/acls/utils.py @@ -7,15 +7,15 @@ from django.contrib.contenttypes.models import ContentType from common.models import AnonymousUserSingleton from .models import AccessEntry, DefaultAccessEntry, CreatorSingleton -from .classes import EncapsulatedObject, AccessHolder, ClassAccessHolder +from .classes import (EncapsulatedObject, AccessHolder, ClassAccessHolder, + get_source_object) logger = logging.getLogger(__name__) def apply_default_acls(obj, actor=None): logger.debug('actor, init: %s' % actor) - if isinstance(obj, EncapsulatedObject): - obj = obj.source_object + obj = get_source_object(obj) if actor: actor = AnonymousUserSingleton.objects.passthru_check(actor) @@ -24,10 +24,12 @@ def apply_default_acls(obj, actor=None): for default_acl in DefaultAccessEntry.objects.filter(content_type=content_type): holder = CreatorSingleton.objects.passthru_check(default_acl.holder_object, actor) - - access_entry = AccessEntry( - permission=default_acl.permission, - holder_object=holder, - content_object=obj, - ) - access_entry.save() + + if holder: + # When the creator is admin + access_entry = AccessEntry( + permission=default_acl.permission, + holder_object=holder, + content_object=obj, + ) + access_entry.save() From 7b7153f7f65bb73aa1e66da58c713eb5000da2dd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 01:05:15 -0400 Subject: [PATCH 345/484] Apply same invalid holder check to object ACL holder list manager method --- apps/acls/managers.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 540c1ff3b2..061359d102 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -188,10 +188,12 @@ class AccessEntryManager(models.Manager): content_type = ContentType.objects.get_for_model(obj) holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): - entry = AccessHolder.encapsulate(access_entry.holder_object) - - if entry not in holder_list: - holder_list.append(entry) + if access_entry.holder_object: + # Don't add references to non existant content type objects + entry = AccessHolder.encapsulate(access_entry.holder_object) + + if entry not in holder_list: + holder_list.append(entry) return holder_list @@ -263,7 +265,7 @@ class DefaultAccessEntryManager(models.Manager): holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type): if access_entry.holder_object: - # Reference to a non existant content type object + # Don't add references to non existant content type objects entry = ClassAccessHolder.encapsulate(access_entry.holder_object) if entry not in holder_list: From 59f6f7f8cca989aa54c1bf0c637ad8012f24139a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:01:42 -0400 Subject: [PATCH 346/484] Document indexing refactoring update --- apps/document_indexing/__init__.py | 11 ++- apps/document_indexing/api.py | 70 ++++++++++--------- apps/document_indexing/models.py | 15 ++++- apps/document_indexing/os_specifics.py | 2 +- apps/document_indexing/urls.py | 9 +-- apps/document_indexing/views.py | 93 +++++++++++++------------- apps/document_indexing/widgets.py | 2 +- 7 files changed, 114 insertions(+), 88 deletions(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 0adb88c37a..7b1b921442 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -21,7 +21,11 @@ from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, def is_root_node(context): - return context['node'].parent==None + return context['node'].parent is None + + +def is_not_instance_root_node(context): + return context['object'].parent is not None index_setup = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} @@ -36,10 +40,11 @@ template_node_edit = {'text': _(u'edit'), 'view': 'template_node_edit', 'args': template_node_delete = {'text': _(u'delete'), 'view': 'template_node_delete', 'args': 'node.pk', 'famfam': 'textfield_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} -index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True} + +index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_node_view', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True, 'condition': is_not_instance_root_node} document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} -register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'folder_page', 'view': 'index_instance_list'}) +register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'folder_page', 'view': 'index_list'}) rebuild_index_instances = {'text': _('rebuild indexes'), 'view': 'rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _(u'Deletes and creates from scratch all the document indexes.')} diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 6a6cfde3a4..d815e3cec6 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -41,9 +41,11 @@ def update_indexes(document): eval_dict['document'] = document eval_dict['metadata'] = MetadataObject(document_metadata_dict) - for root in Index.objects.filter(parent=None): - index_warnings = _evaluate_index(eval_dict, document, root) - warnings.extend(index_warnings) + for index in Index.objects.all(): + root_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=index.template_root, parent=None) + for template_node in index.template_root.get_children(): + index_warnings = _evaluate_index(eval_dict, document, template_node, root_instance) + warnings.extend(index_warnings) return warnings @@ -54,14 +56,14 @@ def delete_indexes(document): """ warnings = [] - for index_instance in document.indexinstance_set.all(): + for index_instance in document.indexinstancenode_set.all(): index_warnings = _remove_document_from_index_instance(document, index_instance) warnings.extend(index_warnings) return warnings -def get_instance_link(index_instance=None, text=None, simple=False): +def get_instance_link(index_instance_node=None, text=None, simple=False): """ Return an HTML anchor to an index instance """ @@ -72,15 +74,15 @@ def get_instance_link(index_instance=None, text=None, simple=False): template = u'%(value)s' else: template = u'%(value)s' - if index_instance: + if index_instance_node: return template % { - 'url': index_instance.get_absolute_url(), - 'value': text if text else index_instance + 'url': index_instance_node.get_absolute_url(), + 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index) } else: # Root node return template % { - 'url': reverse('index_instance_list'), + 'url': '#',#reverse('index_instance_node_view', args=[index_instance_node.parent.pk]), 'value': ugettext(u'root') } @@ -95,7 +97,7 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou # Return the entire breadcrumb path as a single HTML anchor simple = True - result.append(get_instance_link(simple=simple)) + #result.append(get_instance_link(index_instance.get_root(), simple=simple)) for instance in index_instance.get_ancestors(): result.append(get_instance_link(instance, simple=simple)) @@ -109,7 +111,7 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou if single_link: # Return the entire breadcrumb path as a single HTML anchor - output.insert(0, get_instance_link(index_instance=index_instance, text=(u' / '.join(result)))) + output.insert(0, get_instance_link(index_instance_node=index_instance, text=(u' / '.join(result)))) return mark_safe(u' '.join(output)) else: output.insert(0, u' / '.join(result)) @@ -118,8 +120,8 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou def do_rebuild_all_indexes(): fs_delete_directory_recusive() - IndexInstance.objects.all().delete() - DocumentRenameCount.objects.all().delete() + IndexInstanceNone.objects.delete() + DocumentRenameCount.objects.delete() for document in Document.objects.all(): update_indexes(document) @@ -129,56 +131,61 @@ def do_rebuild_all_indexes(): # Internal functions def find_lowest_available_suffix(index_instance, document): # TODO: verify extension's role in query - index_instance_documents = DocumentRenameCount.objects.filter(index_instance=index_instance)#.filter(document__file_extension=document.file_extension) + index_instance_documents = DocumentRenameCount.objects.filter(index_instance_node=index_instance)#.filter(document__file_extension=document.file_extension) files_list = [] for index_instance_document in index_instance_documents: - files_list.append(assemble_suffixed_filename(index_instance_document.document.file.name, index_instance_document.suffix)) + files_list.append(assemble_suffixed_filename(index_instance_document.document.file_filename, index_instance_document.suffix)) for suffix in xrange(MAX_SUFFIX_COUNT): - if assemble_suffixed_filename(document.file.name, suffix) not in files_list: + if assemble_suffixed_filename(document.file_filename, suffix) not in files_list: return suffix raise MaxSuffixCountReached(ugettext(u'Maximum suffix (%s) count reached.') % MAX_SUFFIX_COUNT) -def _evaluate_index(eval_dict, document, node, parent_index_instance=None): +def _evaluate_index(eval_dict, document, template_node, parent_index_instance=None): """ Evaluate an enabled index expression and update or create all the related index instances also recursively calling itself to evaluate all the index's children """ warnings = [] - if node.enabled: + if template_node.enabled: try: - result = eval(node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) + result = eval(template_node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) if result: - index_instance, created = IndexInstance.objects.get_or_create(index=node, value=result, parent=parent_index_instance) + index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node) + index_instance.value = result + index_instance.parent = parent_index_instance + index_instance.save() #if created: - fs_create_index_directory(index_instance) - if node.link_documents: + #fs_create_index_directory(index_instance) + if template_node.link_documents: suffix = find_lowest_available_suffix(index_instance, document) document_count = DocumentRenameCount( - index_instance=index_instance, + index_instance_node=index_instance, document=document, suffix=suffix ) document_count.save() - fs_create_document_link(index_instance, document, suffix) + #fs_create_document_link(index_instance, document, suffix) index_instance.documents.add(document) - for children in node.get_children(): + for child in template_node.get_children(): children_warnings = _evaluate_index( - eval_dict, document, children, index_instance + eval_dict, document, child, index_instance ) warnings.extend(children_warnings) except (NameError, AttributeError), exc: + raise warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { - 'expression': node.expression, 'exception': exc}) + 'expression': template_node.expression, 'exception': exc}) except Exception, exc: + raise warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { - 'expression': node.expression, 'exception': exc}) + 'expression': template_node.expression, 'exception': exc}) return warnings @@ -191,15 +198,15 @@ def _remove_document_from_index_instance(document, index_instance): """ warnings = [] try: - document_rename_count = DocumentRenameCount.objects.get(index_instance=index_instance, document=document) - fs_delete_document_link(index_instance, document, document_rename_count.suffix) + document_rename_count = DocumentRenameCount.objects.get(index_instance_node=index_instance, document=document) + #fs_delete_document_link(index_instance, document, document_rename_count.suffix) document_rename_count.delete() index_instance.documents.remove(document) if index_instance.documents.count() == 0 and index_instance.get_children().count() == 0: # if there are no more documents and no children, delete # node and check parent for the same conditions parent = index_instance.parent - fs_delete_index_directory(index_instance) + #fs_delete_index_directory(index_instance) index_instance.delete() parent_warnings = _remove_document_from_index_instance( document, parent @@ -208,6 +215,7 @@ def _remove_document_from_index_instance(document, index_instance): except DocumentRenameCount.DoesNotExist: return warnings except Exception, exc: + raise warnings.append(_(u'Unable to delete document indexing node; %s') % exc) return warnings diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index 274d2b06f3..6a11585aca 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -18,9 +18,22 @@ class Index(models.Model): title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title')) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) + @property + def template_root(self): + # Catch error + return self.indextemplatenode_set.get(parent=None) + + @property + def instance_root(self): + return self.template_root.indexinstancenode_set.get() + def __unicode__(self): return self.title + @models.permalink + def get_absolute_url(self): + return ('index_instance_node_view', [self.instance_root.pk]) + class Meta: verbose_name = _(u'index') verbose_name_plural = _(u'indexes') @@ -60,7 +73,7 @@ class IndexInstanceNode(MPTTModel): @models.permalink def get_absolute_url(self): - return ('index_instance_list', [self.pk]) + return ('index_instance_node_view', [self.pk]) #def get_document_list_display(self): # return u', '.join([d.file_filename for d in self.documents.all()]) diff --git a/apps/document_indexing/os_specifics.py b/apps/document_indexing/os_specifics.py index d57eae409c..d7cbe3e68d 100644 --- a/apps/document_indexing/os_specifics.py +++ b/apps/document_indexing/os_specifics.py @@ -12,7 +12,7 @@ def assemble_suffixed_filename(filename, suffix=0): """ if suffix: - name, extension = filename.split(os.split(os.extsep)) + name, extension = os.path.splitext(filename) return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension]) else: return filename diff --git a/apps/document_indexing/urls.py b/apps/document_indexing/urls.py index 74e7b11aae..ecb7ffbeda 100644 --- a/apps/document_indexing/urls.py +++ b/apps/document_indexing/urls.py @@ -11,12 +11,9 @@ urlpatterns = patterns('document_indexing.views', url(r'^setup/template/node/(?P\d+)/edit/$', 'template_node_edit', (), 'template_node_edit'), url(r'^setup/template/node/(?P\d+)/delete/$', 'template_node_delete', (), 'template_node_delete'), - url(r'^list/$', 'index_list', (), 'index_list'), - - #Broken - url(r'^(?P\d+)/list/$', 'index_instance_list', (), 'index_instance_list'), - url(r'^list/$', 'index_instance_list', (), 'index_instance_list'), + url(r'^index/list/$', 'index_list', (), 'index_list'), + url(r'^instance/node/(?P\d+)/$', 'index_instance_node_view', (), 'index_instance_node_view'), + url(r'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'), - url(r'^list/for/document/(?P\d+)/$', 'document_index_list', (), 'document_index_list'), ) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 758e2ad945..4fdb020425 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -10,12 +10,14 @@ from django.contrib import messages #from django.utils.safestring import mark_safe from django.core.urlresolvers import reverse from django.utils.html import conditional_escape, mark_safe +from django.core.exceptions import PermissionDenied from permissions.models import Permission from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list from common.utils import encapsulate +from acls.utils import apply_default_acls from .forms import IndexForm, IndexTemplateNodeForm from .models import (Index, IndexTemplateNode, IndexInstanceNode) @@ -64,7 +66,7 @@ def index_setup_create(request): form = IndexForm(request.POST) if form.is_valid(): index = form.save() - #apply_default_acls(folder, request.user) + apply_default_acls(index, request.user) messages.success(request, _(u'Index created successfully.')) return HttpResponseRedirect(reverse('index_setup_list')) else: @@ -170,32 +172,6 @@ def index_setup_view(request, index_pk): context_instance=RequestContext(request)) -def index_list(request): - context = { - 'title': _(u'indexes'), - #'hide_object': True, - #'list_object_variable_name': 'index', - #'extra_columns': [ - # {'name': _(u'name'), 'attribute': 'name'}, - # {'name': _(u'title'), 'attribute': 'title'}, - #] - 'overrided_object_links': [{}], - } - - queryset = Index.objects.all() - - try: - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) - except PermissionDenied: - queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, queryset) - - context['object_list'] = queryset - - return render_to_response('generic_list.html', - context, - context_instance=RequestContext(request) - ) - # Node views def template_node_create(request, parent_pk): parent_node = get_object_or_404(IndexTemplateNode, pk=parent_pk) @@ -301,30 +277,56 @@ def template_node_delete(request, node_pk): # User views -def index_instance_list(request, index_id=None): - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) - if index_id: - index_instance = get_object_or_404(IndexInstanceNode, pk=index_id) - index_instance_list = [index for index in index_instance.get_children().order_by('value')] - breadcrumbs = get_breadcrumbs(index_instance) - if index_instance.documents.count(): - for document in index_instance.documents.all().order_by('file_filename'): - index_instance_list.append(document) - else: - index_instance_list = IndexInstanceNode.objects.filter(parent=None) - breadcrumbs = get_instance_link() - index_instance = None +#from . import index_roots as index_roots_link + +def index_list(request): + context = { + 'title': _(u'indexes'), + #'hide_object': True, + #'list_object_variable_name': 'index', + 'extra_columns': [ + {'name': _(u'root'), 'attribute': 'root'}, + # {'name': _(u'name'), 'attribute': 'name'}, + # {'name': _(u'title'), 'attribute': 'title'}, + ], + 'overrided_object_links': [{}], + } + + queryset = Index.objects.all() + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) + except PermissionDenied: + queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_VIEW, request.user, queryset) + + context['object_list'] = queryset + + return render_to_response('generic_list.html', + context, + context_instance=RequestContext(request) + ) + + +def index_instance_node_view(request, index_instance_node_pk): + index_instance = get_object_or_404(IndexInstanceNode, pk=index_instance_node_pk) + index_instance_list = [index for index in index_instance.get_children().order_by('value')] + breadcrumbs = get_breadcrumbs(index_instance) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_VIEW, request.user, index_instance.index) title = mark_safe(_(u'contents for index: %s') % breadcrumbs) if index_instance: - if index_instance.index.link_documents: + if index_instance.index_template_node.link_documents: # Document list, use the document_list view for consistency return document_list( request, title=title, - object_list=index_instance_list, + object_list=index_instance.documents.all(), extra_context={ 'object': index_instance } @@ -334,12 +336,12 @@ def index_instance_list(request, index_id=None): 'object_list': index_instance_list, 'extra_columns_preffixed': [ { - 'name': _(u'index'), + 'name': _(u'node'), 'attribute': encapsulate(lambda x: index_instance_item_link(x)) }, { 'name': _(u'items'), - 'attribute': encapsulate(lambda x: x.documents.count() if x.index.link_documents else x.get_children().count()) + 'attribute': encapsulate(lambda x: x.documents.count() if x.index_template_node.link_documents else x.get_children().count()) } ], 'title': title, @@ -378,12 +380,13 @@ def rebuild_index_instances(request): def document_index_list(request, document_id): + #TODO: add ACL check Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW]) document = get_object_or_404(Document, pk=document_id) object_list = [] - for index_instance in document.indexinstance_set.all(): + for index_instance in document.indexinstancenode_set.all(): object_list.append(get_breadcrumbs(index_instance, single_link=True, include_count=True)) return render_to_response('generic_list.html', { diff --git a/apps/document_indexing/widgets.py b/apps/document_indexing/widgets.py index 6e01a407ed..fd4629564a 100644 --- a/apps/document_indexing/widgets.py +++ b/apps/document_indexing/widgets.py @@ -10,7 +10,7 @@ FOLDER_ICON = u'folder' def index_instance_item_link(index_instance_item): if isinstance(index_instance_item, IndexInstanceNode): - if index_instance_item.index.link_documents: + if index_instance_item.index_template_node.link_documents: icon = FOLDER_W_DOCUMENTS else: icon = FOLDER_ICON From 664eda3d200b89c3e1970014c70a1407e6a9b9e6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:13:04 -0400 Subject: [PATCH 347/484] Add David Herring's monetary donation --- docs/topics/contributors.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/topics/contributors.rst b/docs/topics/contributors.rst index 8a21a722bf..afe08d3d1d 100644 --- a/docs/topics/contributors.rst +++ b/docs/topics/contributors.rst @@ -4,11 +4,13 @@ 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) @@ -17,6 +19,7 @@ Bug fixes * Meurig Freeman (https://github.com/meurig) * David Herring (https://github.com/abadger1406) + Bug reports ----------- * Aziz M. Bookwala (https://github.com/azizmb) @@ -29,11 +32,13 @@ Bug reports * 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) @@ -41,6 +46,7 @@ Suggestions * Barry Rowlingson (http://geospaced.blogspot.com) * Gour (https://github.com/gour) + Translations ------------ * Portuguese @@ -62,6 +68,8 @@ Remote access for debugging * Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * David Herring (https://github.com/abadger1406) + Monetary donations ------------------ -* David Herring (https://github.com/abadger1406) +* David Herring (https://github.com/abadger1406) - $100 +* David Herring (https://github.com/abadger1406) - $250 From af77cdcf63c47c31cf066d5f5924823a4dd4101d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:13:58 -0400 Subject: [PATCH 348/484] =?UTF-8?q?Add=20=D0=A1=D0=B5=D1=80=D0=B3=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=93=D0=BB=D0=B8=D1=82=D0=B0=20(https://github.com/g?= =?UTF-8?q?sv70)=20fix=20for=20issue=20#17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/production.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/production.txt b/requirements/production.txt index f8408ec634..f1431b51db 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -16,3 +16,4 @@ djangorestframework==0.2.3 South==0.7.3 python-gnupg==0.2.8 python-hkp==0.1.3 +kombu==1.4.2 From 1c8fd9e212aa03423b1fda6a34a9c73fdd0d2147 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:16:04 -0400 Subject: [PATCH 349/484] =?UTF-8?q?Revert=20"Add=20=D0=A1=D0=B5=D1=80?= =?UTF-8?q?=D0=B3=D0=B5=D0=B9=20=D0=93=D0=BB=D0=B8=D1=82=D0=B0=20(https://?= =?UTF-8?q?github.com/gsv70)=20fix=20for=20issue=20#17"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit af77cdcf63c47c31cf066d5f5924823a4dd4101d. --- requirements/production.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements/production.txt b/requirements/production.txt index f1431b51db..f8408ec634 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -16,4 +16,3 @@ djangorestframework==0.2.3 South==0.7.3 python-gnupg==0.2.8 python-hkp==0.1.3 -kombu==1.4.2 From c79d1d0c3459866ce50cc05132b0c36836eb94f5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:28:13 -0400 Subject: [PATCH 350/484] Revert "Merge branch 'hotfix/v0.11.2' into development" This reverts commit f8e2341f4f44b71d45b9e7a6c74ca69a329fdb18, reversing changes made to 1c8fd9e212aa03423b1fda6a34a9c73fdd0d2147. --- README.md | 4 +- apps/documents/statistics.py | 7 +- apps/main/__init__.py | 2 +- docs/changelog.rst | 716 ----------------------------------- requirements/production.txt | 1 - 5 files changed, 6 insertions(+), 724 deletions(-) delete mode 100644 docs/changelog.rst diff --git a/README.md b/README.md index 0695d8fa3a..6987954b0c 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,7 @@ Mayan Open source, Django based document manager with custom metadata indexing, file serving integration and OCR capabilities. -[Website](http://www.mayan-edms.com) - -[Mailing list (via Google Groups)](http://groups.google.com/group/mayan-edms) +[Website](http://bit.ly/mayan-edms) [Video demostration](http://bit.ly/pADNXv) diff --git a/apps/documents/statistics.py b/apps/documents/statistics.py index 641790e152..508d699a49 100644 --- a/apps/documents/statistics.py +++ b/apps/documents/statistics.py @@ -1,11 +1,12 @@ +from __future__ import absolute_import + from django.utils.translation import ugettext_lazy as _ from django.db.models import Avg, Count, Min, Max from common.utils import pretty_size, pretty_size_10 -from documents.conf.settings import STORAGE_BACKEND -from documents.models import Document, DocumentType, DocumentPage, DocumentVersion -from django.db.models import Avg, Count, Min, Max +from .conf.settings import STORAGE_BACKEND +from .models import Document, DocumentType, DocumentPage, DocumentVersion def get_used_size(path, file_list): diff --git a/apps/main/__init__.py b/apps/main/__init__.py index f96697af37..80d503ca7e 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -21,7 +21,7 @@ __status__ = 'Production' __version_info__ = { 'major': 0, 'minor': 11, - 'micro': 2, + 'micro': 1, 'releaselevel': 'final', 'serial': 0 } 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/requirements/production.txt b/requirements/production.txt index f1431b51db..f8408ec634 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -16,4 +16,3 @@ djangorestframework==0.2.3 South==0.7.3 python-gnupg==0.2.8 python-hkp==0.1.3 -kombu==1.4.2 From d230dd711013e3e579a2fc6512c204260c3f89b6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:33:47 -0400 Subject: [PATCH 351/484] Revert "Bump version to 0.11.2" This reverts commit f9be37768e97aba7206d8ddb2e08fc50cfdef1e8. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6987954b0c..7e4b8e1203 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Open source, Django based document manager with custom metadata indexing, file s [Translations](https://www.transifex.net/projects/p/mayan-edms/) +[Mailing list (via Google Groups)](http://groups.google.com/group/mayan-edms) License ------- From f4ed105c99af256ffe4d81bd634b18cd76484f64 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 05:35:06 -0400 Subject: [PATCH 352/484] Bump version to 0.12 beta --- apps/main/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 80d503ca7e..7522fc7a27 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -20,9 +20,9 @@ __status__ = 'Production' __version_info__ = { 'major': 0, - 'minor': 11, - 'micro': 1, - 'releaselevel': 'final', + 'minor': 12, + 'micro': 0, + 'releaselevel': 'beta', 'serial': 0 } From 790dad2df4f41d935b9ea891db2f7378d20c2410 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:00:41 -0400 Subject: [PATCH 353/484] Enforce enabled boolean field, silence errors --- apps/document_indexing/api.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index d815e3cec6..f0743cd764 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -41,7 +41,7 @@ def update_indexes(document): eval_dict['document'] = document eval_dict['metadata'] = MetadataObject(document_metadata_dict) - for index in Index.objects.all(): + for index in Index.objects.filter(enabled=True): root_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=index.template_root, parent=None) for template_node in index.template_root.get_children(): index_warnings = _evaluate_index(eval_dict, document, template_node, root_instance) @@ -179,11 +179,9 @@ def _evaluate_index(eval_dict, document, template_node, parent_index_instance=No warnings.extend(children_warnings) except (NameError, AttributeError), exc: - raise warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { 'expression': template_node.expression, 'exception': exc}) except Exception, exc: - raise warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { 'expression': template_node.expression, 'exception': exc}) @@ -215,7 +213,6 @@ def _remove_document_from_index_instance(document, index_instance): except DocumentRenameCount.DoesNotExist: return warnings except Exception, exc: - raise warnings.append(_(u'Unable to delete document indexing node; %s') % exc) return warnings From c6fa070222044172075ddc7901244b82493f9d7f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:12:20 -0400 Subject: [PATCH 354/484] Add ACL checks to document_index_list --- apps/document_indexing/views.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 4fdb020425..bba139670f 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -255,9 +255,6 @@ def template_node_delete(request, node_pk): return HttpResponseRedirect(next) context = { - #'node': node, - #'object_name': _(u'index'), - #'navigation_object_name': 'index', 'delete_view': True, 'previous': previous, 'next': next, @@ -276,24 +273,20 @@ def template_node_delete(request, node_pk): context_instance=RequestContext(request)) -# User views - -#from . import index_roots as index_roots_link - def index_list(request): context = { 'title': _(u'indexes'), #'hide_object': True, #'list_object_variable_name': 'index', - 'extra_columns': [ - {'name': _(u'root'), 'attribute': 'root'}, + #'extra_columns': [ + # {'name': _(u'elements'), 'attribute': 'root'}, # {'name': _(u'name'), 'attribute': 'name'}, # {'name': _(u'title'), 'attribute': 'title'}, - ], + #], 'overrided_object_links': [{}], } - queryset = Index.objects.all() + queryset = Index.objects.filter(enabled=True) try: Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) @@ -380,13 +373,16 @@ def rebuild_index_instances(request): def document_index_list(request, document_id): - #TODO: add ACL check - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW]) document = get_object_or_404(Document, pk=document_id) - object_list = [] - for index_instance in document.indexinstancenode_set.all(): + queryset = document.indexinstancenode_set.all() + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW]) + except PermissionDenied: + queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_VIEW, request.user, queryset) + + for index_instance in queryset: object_list.append(get_breadcrumbs(index_instance, single_link=True, include_count=True)) return render_to_response('generic_list.html', { From 06cde627d25e94fed06939fe98ab92c9fd3a327b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:12:58 -0400 Subject: [PATCH 355/484] Simplify node link generator --- apps/document_indexing/api.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index f0743cd764..b16f065d29 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -63,7 +63,7 @@ def delete_indexes(document): return warnings -def get_instance_link(index_instance_node=None, text=None, simple=False): +def get_instance_link(index_instance_node, text=None, simple=False): """ Return an HTML anchor to an index instance """ @@ -74,17 +74,11 @@ def get_instance_link(index_instance_node=None, text=None, simple=False): template = u'%(value)s' else: template = u'%(value)s' - if index_instance_node: - return template % { - 'url': index_instance_node.get_absolute_url(), - 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index) - } - else: - # Root node - return template % { - 'url': '#',#reverse('index_instance_node_view', args=[index_instance_node.parent.pk]), - 'value': ugettext(u'root') - } + + return template % { + 'url': index_instance_node.get_absolute_url(), + 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index) + } def get_breadcrumbs(index_instance, simple=False, single_link=False, include_count=False): From 2c53c5a2ff4eaf6f92ed4b9071eb263f7d520258 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:13:23 -0400 Subject: [PATCH 356/484] Automatically create root template node on index save, add help texts --- apps/document_indexing/models.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index 6a11585aca..22cea326c7 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -15,12 +15,11 @@ available_indexing_functions_string = (_(u'Available functions: %s') % u','.join class Index(models.Model): name = models.CharField(unique=True, max_length=64, verbose_name=_(u'name'), help_text=_(u'Internal name used to reference this index.')) - title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title')) - enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) + title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title'), help_text=_(u'The name that will be visible to users.')) + enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'), help_text=_(u'Causes this index to be visible and updated when document data changes.')) @property def template_root(self): - # Catch error return self.indextemplatenode_set.get(parent=None) @property @@ -34,6 +33,10 @@ class Index(models.Model): def get_absolute_url(self): return ('index_instance_node_view', [self.instance_root.pk]) + def save(self, *args, **kwargs): + super(Index, self).save(*args, **kwargs) + index_template_node_root, created = IndexTemplateNode.objects.get_or_create(parent=None, index=self) + class Meta: verbose_name = _(u'index') verbose_name_plural = _(u'indexes') @@ -44,8 +47,8 @@ class IndexTemplateNode(MPTTModel): index = models.ForeignKey(Index, verbose_name=_(u'index')) expression = models.CharField(max_length=128, verbose_name=_(u'indexing expression'), help_text=_(u'Enter a python string expression to be evaluated.')) # % available_indexing_functions_string) - enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) - link_documents = models.BooleanField(default=False, verbose_name=_(u'link documents')) + enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'), help_text=_(u'Causes this node to be visible and updated when document data changes.')) + link_documents = models.BooleanField(default=False, verbose_name=_(u'link documents'), help_text=_(u'Check this option to have this node act as a container for documents and not as a parent for further nodes.')) def __unicode__(self): return self.expression if not self.link_documents else u'%s/[document]' % self.expression From 95be7cb417724eeef0d63739efb1822705aca354 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:17:01 -0400 Subject: [PATCH 357/484] Merge os_specify and filesystem module --- apps/document_indexing/api.py | 4 ++-- apps/document_indexing/filesystem.py | 18 ++++++++++++++++++ apps/document_indexing/os_specifics.py | 22 ---------------------- 3 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 apps/document_indexing/os_specifics.py diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index b16f065d29..6837f2f9c7 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -15,8 +15,8 @@ from .conf.settings import (AVAILABLE_INDEXING_FUNCTIONS, MAX_SUFFIX_COUNT, SLUGIFY_PATHS) from .filesystem import (fs_create_index_directory, fs_create_document_link, fs_delete_document_link, - fs_delete_index_directory, fs_delete_directory_recusive) -from .os_specifics import assemble_suffixed_filename + fs_delete_index_directory, fs_delete_directory_recusive, + assemble_suffixed_filename) if SLUGIFY_PATHS == False: # Do not slugify path or filenames and extensions diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py index 7c732007cc..adacc2474c 100644 --- a/apps/document_indexing/filesystem.py +++ b/apps/document_indexing/filesystem.py @@ -8,6 +8,24 @@ from django.utils.translation import ugettext_lazy as _ from .os_specifics import (assemble_suffixed_filename, assemble_path_from_list) from .conf.settings import (FILESERVING_ENABLE, FILESERVING_PATH) +from .conf.settings import SUFFIX_SEPARATOR + + +def assemble_suffixed_filename(filename, suffix=0): + """ + Split document filename, to attach suffix to the name part then + re attacht the extension + """ + + if suffix: + name, extension = os.path.splitext(filename) + return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension]) + else: + return filename + + +def assemble_path_from_list(directory_list): + return os.sep.join(directory_list) def get_instance_path(index_instance): diff --git a/apps/document_indexing/os_specifics.py b/apps/document_indexing/os_specifics.py deleted file mode 100644 index d7cbe3e68d..0000000000 --- a/apps/document_indexing/os_specifics.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import absolute_import - -import os - -from .conf.settings import SUFFIX_SEPARATOR - - -def assemble_suffixed_filename(filename, suffix=0): - """ - Split document filename, to attach suffix to the name part then - re attacht the extension - """ - - if suffix: - name, extension = os.path.splitext(filename) - return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension]) - else: - return filename - - -def assemble_path_from_list(directory_list): - return os.sep.join(directory_list) From 1d3c5241ec62b5fd1d825eb9575658bf3c328bcd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:22:40 -0400 Subject: [PATCH 358/484] Move all widgets code to a single module --- apps/document_indexing/api.py | 56 ++----------------------------- apps/document_indexing/views.py | 6 ++-- apps/document_indexing/widgets.py | 49 +++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 57 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 6837f2f9c7..4b3a40e075 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -3,7 +3,6 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.core.urlresolvers import reverse -from django.utils.safestring import mark_safe from django.template.defaultfilters import slugify from documents.models import Document @@ -17,6 +16,8 @@ from .filesystem import (fs_create_index_directory, fs_create_document_link, fs_delete_document_link, fs_delete_index_directory, fs_delete_directory_recusive, assemble_suffixed_filename) +from .widgets import get_instance_link +from .exceptions import MaxSuffixCountReached if SLUGIFY_PATHS == False: # Do not slugify path or filenames and extensions @@ -25,10 +26,6 @@ else: SLUGIFY_FUNCTION = slugify -class MaxSuffixCountReached(Exception): - pass - - # External functions def update_indexes(document): """ @@ -63,55 +60,6 @@ def delete_indexes(document): return warnings -def get_instance_link(index_instance_node, text=None, simple=False): - """ - Return an HTML anchor to an index instance - """ - - if simple: - # Just display the instance's value or overrided text, no - # HTML anchor - template = u'%(value)s' - else: - template = u'%(value)s' - - return template % { - 'url': index_instance_node.get_absolute_url(), - 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index) - } - - -def get_breadcrumbs(index_instance, simple=False, single_link=False, include_count=False): - """ - Return a joined string of HTML anchors to every index instance's - parent from the root of the tree to the index instance - """ - result = [] - if single_link: - # Return the entire breadcrumb path as a single HTML anchor - simple = True - - #result.append(get_instance_link(index_instance.get_root(), simple=simple)) - - for instance in index_instance.get_ancestors(): - result.append(get_instance_link(instance, simple=simple)) - - result.append(get_instance_link(index_instance, simple=simple)) - - output = [] - - if include_count: - output.append(u'(%d)' % index_instance.documents.count()) - - if single_link: - # Return the entire breadcrumb path as a single HTML anchor - output.insert(0, get_instance_link(index_instance_node=index_instance, text=(u' / '.join(result)))) - return mark_safe(u' '.join(output)) - else: - output.insert(0, u' / '.join(result)) - return mark_safe(u' '.join(output)) - - def do_rebuild_all_indexes(): fs_delete_directory_recusive() IndexInstanceNone.objects.delete() diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index bba139670f..2e3f02a57b 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -21,9 +21,9 @@ from acls.utils import apply_default_acls from .forms import IndexForm, IndexTemplateNodeForm from .models import (Index, IndexTemplateNode, IndexInstanceNode) -from .api import (get_breadcrumbs, get_instance_link, - do_rebuild_all_indexes) -from .widgets import index_instance_item_link +from .api import do_rebuild_all_indexes +from .widgets import (index_instance_item_link, get_instance_link, + get_breadcrumbs) from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES, PERMISSION_DOCUMENT_INDEXING_SETUP, diff --git a/apps/document_indexing/widgets.py b/apps/document_indexing/widgets.py index fd4629564a..4448c63e0b 100644 --- a/apps/document_indexing/widgets.py +++ b/apps/document_indexing/widgets.py @@ -22,3 +22,52 @@ def index_instance_item_link(index_instance_item): 'icon_template': icon_template, 'text': index_instance_item }) + + +def get_instance_link(index_instance_node, text=None, simple=False): + """ + Return an HTML anchor to an index instance + """ + + if simple: + # Just display the instance's value or overrided text, no + # HTML anchor + template = u'%(value)s' + else: + template = u'%(value)s' + + return template % { + 'url': index_instance_node.get_absolute_url(), + 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index) + } + + +def get_breadcrumbs(index_instance, simple=False, single_link=False, include_count=False): + """ + Return a joined string of HTML anchors to every index instance's + parent from the root of the tree to the index instance + """ + result = [] + if single_link: + # Return the entire breadcrumb path as a single HTML anchor + simple = True + + #result.append(get_instance_link(index_instance.get_root(), simple=simple)) + + for instance in index_instance.get_ancestors(): + result.append(get_instance_link(instance, simple=simple)) + + result.append(get_instance_link(index_instance, simple=simple)) + + output = [] + + if include_count: + output.append(u'(%d)' % index_instance.documents.count()) + + if single_link: + # Return the entire breadcrumb path as a single HTML anchor + output.insert(0, get_instance_link(index_instance_node=index_instance, text=(u' / '.join(result)))) + return mark_safe(u' '.join(output)) + else: + output.insert(0, u' / '.join(result)) + return mark_safe(u' '.join(output)) From 2ac625014974e132ffd0dace725fa22b8e349319 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:23:07 -0400 Subject: [PATCH 359/484] Fix imports --- apps/document_indexing/filesystem.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py index adacc2474c..b57b989dde 100644 --- a/apps/document_indexing/filesystem.py +++ b/apps/document_indexing/filesystem.py @@ -5,10 +5,8 @@ import os from django.utils.translation import ugettext_lazy as _ -from .os_specifics import (assemble_suffixed_filename, - assemble_path_from_list) -from .conf.settings import (FILESERVING_ENABLE, FILESERVING_PATH) -from .conf.settings import SUFFIX_SEPARATOR +from .conf.settings import (FILESERVING_ENABLE, FILESERVING_PATH, + SUFFIX_SEPARATOR) def assemble_suffixed_filename(filename, suffix=0): From 1eabbf90cdda890137cd02ea7608b5892ff038c5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:23:20 -0400 Subject: [PATCH 360/484] Move exception to a single module --- apps/document_indexing/exceptions.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 apps/document_indexing/exceptions.py diff --git a/apps/document_indexing/exceptions.py b/apps/document_indexing/exceptions.py new file mode 100644 index 0000000000..9e095fae11 --- /dev/null +++ b/apps/document_indexing/exceptions.py @@ -0,0 +1,6 @@ +class MaxSuffixCountReached(Exception): + """ + Raised when there are too many documents with the same filename in the + same node/directory + """ + pass From 2c6339b56ae2eb6ee13e2d117b1765ddba1dccc2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:33:28 -0400 Subject: [PATCH 361/484] Small updates and fixes --- apps/document_indexing/admin.py | 9 +------- apps/document_indexing/api.py | 38 +++++++++++---------------------- apps/document_indexing/forms.py | 2 +- apps/document_indexing/tools.py | 17 +++++++++++++++ apps/document_indexing/urls.py | 2 +- apps/document_indexing/views.py | 10 ++++----- 6 files changed, 37 insertions(+), 41 deletions(-) create mode 100644 apps/document_indexing/tools.py diff --git a/apps/document_indexing/admin.py b/apps/document_indexing/admin.py index 7ec0de2423..1b9c833754 100644 --- a/apps/document_indexing/admin.py +++ b/apps/document_indexing/admin.py @@ -8,20 +8,13 @@ from .models import (Index, IndexTemplateNode, IndexInstanceNode, DocumentRenameCount) -#class IndexInstanceInline(admin.StackedInline): -# model = IndexInstance -# extra = 1# -# classes = ('collapse-open',) -# allow_add = True - - class IndexTemplateNodeAdmin(MPTTModelAdmin): list_display = ('expression', 'enabled', 'link_documents') class IndexInstanceNodeAdmin(MPTTModelAdmin): model = IndexInstanceNode - list_display = ('value',)# 'get_document_list_display') + list_display = ('value',) admin.site.register(Index) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 4b3a40e075..26c6808ed7 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -5,7 +5,6 @@ from django.utils.translation import ugettext from django.core.urlresolvers import reverse from django.template.defaultfilters import slugify -from documents.models import Document from metadata.classes import MetadataObject from .models import (Index, IndexTemplateNode, IndexInstanceNode, @@ -14,9 +13,7 @@ from .conf.settings import (AVAILABLE_INDEXING_FUNCTIONS, MAX_SUFFIX_COUNT, SLUGIFY_PATHS) from .filesystem import (fs_create_index_directory, fs_create_document_link, fs_delete_document_link, - fs_delete_index_directory, fs_delete_directory_recusive, - assemble_suffixed_filename) -from .widgets import get_instance_link + fs_delete_index_directory, assemble_suffixed_filename) from .exceptions import MaxSuffixCountReached if SLUGIFY_PATHS == False: @@ -41,7 +38,7 @@ def update_indexes(document): for index in Index.objects.filter(enabled=True): root_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=index.template_root, parent=None) for template_node in index.template_root.get_children(): - index_warnings = _evaluate_index(eval_dict, document, template_node, root_instance) + index_warnings = cascade_eval(eval_dict, document, template_node, root_instance) warnings.extend(index_warnings) return warnings @@ -54,26 +51,15 @@ def delete_indexes(document): warnings = [] for index_instance in document.indexinstancenode_set.all(): - index_warnings = _remove_document_from_index_instance(document, index_instance) + index_warnings = cascade_document_remove(document, index_instance) warnings.extend(index_warnings) return warnings -def do_rebuild_all_indexes(): - fs_delete_directory_recusive() - IndexInstanceNone.objects.delete() - DocumentRenameCount.objects.delete() - for document in Document.objects.all(): - update_indexes(document) - - return [] # Warnings - None - - # Internal functions def find_lowest_available_suffix(index_instance, document): - # TODO: verify extension's role in query - index_instance_documents = DocumentRenameCount.objects.filter(index_instance_node=index_instance)#.filter(document__file_extension=document.file_extension) + index_instance_documents = DocumentRenameCount.objects.filter(index_instance_node=index_instance) files_list = [] for index_instance_document in index_instance_documents: files_list.append(assemble_suffixed_filename(index_instance_document.document.file_filename, index_instance_document.suffix)) @@ -85,7 +71,7 @@ def find_lowest_available_suffix(index_instance, document): raise MaxSuffixCountReached(ugettext(u'Maximum suffix (%s) count reached.') % MAX_SUFFIX_COUNT) -def _evaluate_index(eval_dict, document, template_node, parent_index_instance=None): +def cascade_eval(eval_dict, document, template_node, parent_index_instance=None): """ Evaluate an enabled index expression and update or create all the related index instances also recursively calling itself to evaluate @@ -101,7 +87,7 @@ def _evaluate_index(eval_dict, document, template_node, parent_index_instance=No index_instance.parent = parent_index_instance index_instance.save() #if created: - #fs_create_index_directory(index_instance) + fs_create_index_directory(index_instance) if template_node.link_documents: suffix = find_lowest_available_suffix(index_instance, document) document_count = DocumentRenameCount( @@ -111,11 +97,11 @@ def _evaluate_index(eval_dict, document, template_node, parent_index_instance=No ) document_count.save() - #fs_create_document_link(index_instance, document, suffix) + fs_create_document_link(index_instance, document, suffix) index_instance.documents.add(document) for child in template_node.get_children(): - children_warnings = _evaluate_index( + children_warnings = cascade_eval( eval_dict, document, child, index_instance ) warnings.extend(children_warnings) @@ -130,7 +116,7 @@ def _evaluate_index(eval_dict, document, template_node, parent_index_instance=No return warnings -def _remove_document_from_index_instance(document, index_instance): +def cascade_document_remove(document, index_instance): """ Delete a documents reference from an index instance and call itself recusively deleting documents and empty index instances up to the @@ -139,16 +125,16 @@ def _remove_document_from_index_instance(document, index_instance): warnings = [] try: document_rename_count = DocumentRenameCount.objects.get(index_instance_node=index_instance, document=document) - #fs_delete_document_link(index_instance, document, document_rename_count.suffix) + fs_delete_document_link(index_instance, document, document_rename_count.suffix) document_rename_count.delete() index_instance.documents.remove(document) if index_instance.documents.count() == 0 and index_instance.get_children().count() == 0: # if there are no more documents and no children, delete # node and check parent for the same conditions parent = index_instance.parent - #fs_delete_index_directory(index_instance) + fs_delete_index_directory(index_instance) index_instance.delete() - parent_warnings = _remove_document_from_index_instance( + parent_warnings = cascade_document_remove( document, parent ) warnings.extend(parent_warnings) diff --git a/apps/document_indexing/forms.py b/apps/document_indexing/forms.py index e9224b9ab0..ae42376d6f 100644 --- a/apps/document_indexing/forms.py +++ b/apps/document_indexing/forms.py @@ -22,6 +22,6 @@ class IndexTemplateNodeForm(forms.ModelForm): super(IndexTemplateNodeForm, self).__init__(*args, **kwargs) self.fields['index'].widget = forms.widgets.HiddenInput() self.fields['parent'].widget = forms.widgets.HiddenInput() - + class Meta: model = IndexTemplateNode diff --git a/apps/document_indexing/tools.py b/apps/document_indexing/tools.py new file mode 100644 index 0000000000..07e62c83ce --- /dev/null +++ b/apps/document_indexing/tools.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import + +from documents.models import Document + +from .models import IndexInstanceNode, DocumentRenameCount +from .filesystem import fs_delete_directory_recusive +from .api import update_indexes + + +def do_rebuild_all_indexes(): + fs_delete_directory_recusive() + IndexInstanceNode.objects.delete() + DocumentRenameCount.objects.delete() + for document in Document.objects.all(): + update_indexes(document) + + return [] # Warnings - None diff --git a/apps/document_indexing/urls.py b/apps/document_indexing/urls.py index ecb7ffbeda..099f0f3afe 100644 --- a/apps/document_indexing/urls.py +++ b/apps/document_indexing/urls.py @@ -13,7 +13,7 @@ urlpatterns = patterns('document_indexing.views', url(r'^index/list/$', 'index_list', (), 'index_list'), url(r'^instance/node/(?P\d+)/$', 'index_instance_node_view', (), 'index_instance_node_view'), - + url(r'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'), url(r'^list/for/document/(?P\d+)/$', 'document_index_list', (), 'document_index_list'), ) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 2e3f02a57b..d44c5d105e 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -7,7 +7,6 @@ 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.utils.safestring import mark_safe from django.core.urlresolvers import reverse from django.utils.html import conditional_escape, mark_safe from django.core.exceptions import PermissionDenied @@ -18,12 +17,12 @@ from documents.models import Document from documents.views import document_list from common.utils import encapsulate from acls.utils import apply_default_acls +from acls.models import AccessEntry from .forms import IndexForm, IndexTemplateNodeForm from .models import (Index, IndexTemplateNode, IndexInstanceNode) -from .api import do_rebuild_all_indexes -from .widgets import (index_instance_item_link, get_instance_link, - get_breadcrumbs) +from .tools import do_rebuild_all_indexes +from .widgets import (index_instance_item_link, get_breadcrumbs) from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES, PERMISSION_DOCUMENT_INDEXING_SETUP, @@ -32,6 +31,7 @@ from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_DELETE ) + # Setup views def index_setup_list(request): context = { @@ -41,7 +41,7 @@ def index_setup_list(request): 'extra_columns': [ {'name': _(u'name'), 'attribute': 'name'}, {'name': _(u'title'), 'attribute': 'title'}, - ] + ] } queryset = Index.objects.all() From ac7a3806eca69b19932eeb3dfb5caa5269d4155e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:37:13 -0400 Subject: [PATCH 362/484] Use proper try/exception format --- apps/document_indexing/api.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 26c6808ed7..3a338cbcf1 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -81,6 +81,13 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) if template_node.enabled: try: result = eval(template_node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) + except (NameError, AttributeError), exc: + warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { + 'expression': template_node.expression, 'exception': exc}) + except Exception, exc: + warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { + 'expression': template_node.expression, 'exception': exc}) + else: if result: index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node) index_instance.value = result @@ -106,13 +113,6 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) ) warnings.extend(children_warnings) - except (NameError, AttributeError), exc: - warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exc}) - except Exception, exc: - warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exc}) - return warnings From cc3632dcfe796d2f65c7d339a20ba5f5e1c81753 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:37:31 -0400 Subject: [PATCH 363/484] Remove remarked code --- apps/document_indexing/models.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index 22cea326c7..ce3863ef7e 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -53,13 +53,6 @@ class IndexTemplateNode(MPTTModel): def __unicode__(self): return self.expression if not self.link_documents else u'%s/[document]' % self.expression - #@models.permalink - #def get_absolute_url(self): - # return ('index_instance_list', [self.pk]) - - #def get_document_list_display(self): - # return u', '.join([d.file_filename for d in self.documents.all()]) - class Meta: verbose_name = _(u'index template node') verbose_name_plural = _(u'indexes template nodes') @@ -78,9 +71,6 @@ class IndexInstanceNode(MPTTModel): def get_absolute_url(self): return ('index_instance_node_view', [self.pk]) - #def get_document_list_display(self): - # return u', '.join([d.file_filename for d in self.documents.all()]) - class Meta: verbose_name = _(u'index instance node') verbose_name_plural = _(u'indexes instance nodes') From 7331a87c893a687f848ed1961e4def843dd366ef Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 09:42:37 -0400 Subject: [PATCH 364/484] Rename MetadataObject class to MetadataClass --- apps/document_indexing/api.py | 4 ++-- apps/linking/managers.py | 4 ++-- apps/metadata/classes.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 3a338cbcf1..36dd513202 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext from django.core.urlresolvers import reverse from django.template.defaultfilters import slugify -from metadata.classes import MetadataObject +from metadata.classes import MetadataClass from .models import (Index, IndexTemplateNode, IndexInstanceNode, DocumentRenameCount) @@ -33,7 +33,7 @@ def update_indexes(document): eval_dict = {} document_metadata_dict = dict([(metadata.metadata_type.name, metadata.value) for metadata in document.documentmetadata_set.all() if metadata.value]) eval_dict['document'] = document - eval_dict['metadata'] = MetadataObject(document_metadata_dict) + eval_dict['metadata'] = MetadataClass(document_metadata_dict) for index in Index.objects.filter(enabled=True): root_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=index.template_root, parent=None) diff --git a/apps/linking/managers.py b/apps/linking/managers.py index 4583b646ad..41d4275e15 100644 --- a/apps/linking/managers.py +++ b/apps/linking/managers.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django.db import models from django.db.models import Q -from metadata.classes import MetadataObject +from metadata.classes import MetadataClass from documents.models import Document from .literals import INCLUSION_AND, INCLUSION_OR @@ -18,7 +18,7 @@ class SmartLinkManager(models.Manager): metadata_dict[document_metadata.metadata_type.name] = document_metadata.value eval_dict = {} eval_dict['document'] = document - eval_dict['metadata'] = MetadataObject(metadata_dict) + eval_dict['metadata'] = MetadataClass(metadata_dict) if smart_link_obj: smart_link_qs = self.model.objects.filter(Q(enabled=True) & Q(pk=smart_link_obj.pk)) diff --git a/apps/metadata/classes.py b/apps/metadata/classes.py index b8476a744f..b370dcae21 100644 --- a/apps/metadata/classes.py +++ b/apps/metadata/classes.py @@ -1,7 +1,7 @@ from django.utils.translation import ugettext_lazy as _ -class MetadataObject(object): +class MetadataClass(object): def __init__(self, dictionary): self.dictionary = dictionary From 063d2fca40b1c089acfe45e6f2f3fe3e44231e9c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 10:26:39 -0400 Subject: [PATCH 365/484] Smarted exception catching --- apps/document_indexing/api.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 36dd513202..0e68bb623b 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -84,9 +84,6 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) except (NameError, AttributeError), exc: warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { 'expression': template_node.expression, 'exception': exc}) - except Exception, exc: - warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exc}) else: if result: index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node) @@ -94,7 +91,12 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) index_instance.parent = parent_index_instance index_instance.save() #if created: - fs_create_index_directory(index_instance) + try: + fs_create_index_directory(index_instance) + except Exception, exc: + warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { + 'expression': template_node.expression, 'exception': exc}) + if template_node.link_documents: suffix = find_lowest_available_suffix(index_instance, document) document_count = DocumentRenameCount( @@ -104,7 +106,12 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) ) document_count.save() - fs_create_document_link(index_instance, document, suffix) + try: + fs_create_document_link(index_instance, document, suffix) + except Exception, exc: + warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { + 'expression': template_node.expression, 'exception': exc}) + index_instance.documents.add(document) for child in template_node.get_children(): From 02a762cf73f36f116d4364b835057a35e5dc1bb3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 10:26:58 -0400 Subject: [PATCH 366/484] Remove obsolete indexing config settings and add new FILESYSTEM_SERVING --- apps/document_indexing/conf/settings.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/document_indexing/conf/settings.py b/apps/document_indexing/conf/settings.py index b313035a8d..beb66ca3dd 100644 --- a/apps/document_indexing/conf/settings.py +++ b/apps/document_indexing/conf/settings.py @@ -1,5 +1,7 @@ """Configuration options for the document_indexing app""" +from django.utils.translation import ugettext_lazy as _ + from common.utils import proper_name from smart_settings.api import register_settings @@ -17,7 +19,6 @@ register_settings( # Filesystem serving {'name': u'SLUGIFY_PATHS', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS', 'default': False}, {'name': u'MAX_SUFFIX_COUNT', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT', 'default': 1000}, - {'name': u'FILESERVING_PATH', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH', 'default': u'/tmp/mayan/documents', 'exists': True}, - {'name': u'FILESERVING_ENABLE', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE', 'default': True} + {'name': u'FILESYSTEM_SERVING', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_SERVING', 'default': {}, 'description': _(u'A dictionary that maps the index name and where on the filesystem that index will be mirrored.')} ] ) From cc78b7d25afee256603009e9670ec34bc2acf39d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 10:27:46 -0400 Subject: [PATCH 367/484] Update filesystem mirroring functions --- apps/document_indexing/filesystem.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py index b57b989dde..b29f63fb74 100644 --- a/apps/document_indexing/filesystem.py +++ b/apps/document_indexing/filesystem.py @@ -5,8 +5,7 @@ import os from django.utils.translation import ugettext_lazy as _ -from .conf.settings import (FILESERVING_ENABLE, FILESERVING_PATH, - SUFFIX_SEPARATOR) +from .conf.settings import (FILESYSTEM_SERVING, SUFFIX_SEPARATOR) def assemble_suffixed_filename(filename, suffix=0): @@ -41,8 +40,8 @@ def get_instance_path(index_instance): def fs_create_index_directory(index_instance): - if FILESERVING_ENABLE: - target_directory = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance)]) + if index_instance.index_template_node.index.name in FILESYSTEM_SERVING: + target_directory = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance)]) try: os.mkdir(target_directory) except OSError, exc: @@ -53,9 +52,9 @@ def fs_create_index_directory(index_instance): def fs_create_document_link(index_instance, document, suffix=0): - if FILESERVING_ENABLE: - filename = assemble_suffixed_filename(document.file.name, suffix) - filepath = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance), filename]) + if index_instance.index_template_node.index.name in FILESYSTEM_SERVING: + filename = assemble_suffixed_filename(document.file_filename, suffix) + filepath = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance), filename]) try: os.symlink(document.file.path, filepath) @@ -73,9 +72,9 @@ def fs_create_document_link(index_instance, document, suffix=0): def fs_delete_document_link(index_instance, document, suffix=0): - if FILESERVING_ENABLE: - filename = assemble_suffixed_filename(document.file.name, suffix) - filepath = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance), filename]) + if index_instance.index_template_node.index.name in FILESYSTEM_SERVING: + filename = assemble_suffixed_filename(document.file_filename, suffix) + filepath = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance), filename]) try: os.unlink(filepath) @@ -86,8 +85,8 @@ def fs_delete_document_link(index_instance, document, suffix=0): def fs_delete_index_directory(index_instance): - if FILESERVING_ENABLE: - target_directory = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance)]) + if index_instance.index_template_node.index.name in FILESYSTEM_SERVING: + target_directory = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance)]) try: os.removedirs(target_directory) except OSError, exc: @@ -97,8 +96,9 @@ def fs_delete_index_directory(index_instance): raise Exception(_(u'Unable to delete indexing directory; %s') % exc) -def fs_delete_directory_recusive(path=FILESERVING_PATH): - if FILESERVING_ENABLE: +def fs_delete_directory_recusive(index): + if index.name in FILESYSTEM_SERVING: + path = FILESYSTEM_SERVING[index.name] for dirpath, dirnames, filenames in os.walk(path, topdown=False): for filename in filenames: os.unlink(os.path.join(dirpath, filename)) From 6b8dcb7240cde47c3a07ada8edfbf621fd14aa1a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 10:28:25 -0400 Subject: [PATCH 368/484] Update the index mirroring rebuild tool --- apps/document_indexing/tools.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/document_indexing/tools.py b/apps/document_indexing/tools.py index 07e62c83ce..71837b0930 100644 --- a/apps/document_indexing/tools.py +++ b/apps/document_indexing/tools.py @@ -2,15 +2,17 @@ from __future__ import absolute_import from documents.models import Document -from .models import IndexInstanceNode, DocumentRenameCount +from .models import Index, IndexInstanceNode, DocumentRenameCount from .filesystem import fs_delete_directory_recusive from .api import update_indexes def do_rebuild_all_indexes(): - fs_delete_directory_recusive() - IndexInstanceNode.objects.delete() - DocumentRenameCount.objects.delete() + for index in Index.objects.all(): + fs_delete_directory_recusive(index) + + IndexInstanceNode.objects.all().delete() + DocumentRenameCount.objects.all().delete() for document in Document.objects.all(): update_indexes(document) From 48922d58efb932f6d5a48ef4ae2622adbc06d871 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 10:44:00 -0400 Subject: [PATCH 369/484] Documentation update for the document indexing --- docs/releases/0.12.rst | 23 +++++++++++++++++++++-- docs/topics/settings.rst | 20 +++++++------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index dd198d13ed..748520b87c 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -122,6 +122,19 @@ column after those is ignored. * The ``--skip-repeated`` tells the importedr to not stop when finding that a user already exists in the database. +Refactored document indexing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The document indexing 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 a skeleton tree that will +be populated with document links depending on their metadata and properties. +This populated tree 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. Upgrading from a previous version ================================= @@ -191,15 +204,21 @@ 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. + 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 ============= -* Removal of the OCR_CACHE_URI configuration option. * 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/topics/settings.rst b/docs/topics/settings.rst index 9989752a7d..d01de8049d 100644 --- a/docs/topics/settings.rst +++ b/docs/topics/settings.rst @@ -297,21 +297,15 @@ DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT Default: ``1000`` -.. setting:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH +.. setting:: DOCUMENT_INDEXING_FILESYSTEM_SERVING -DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH ---------------------------------------------- - -Default: ``/tmp/mayan/documents`` - - -.. setting:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE +DOCUMENT_INDEXING_FILESYSTEM_SERVING +------------------------------------ + +Default: ``{}`` + +A dictionary that maps the index name and where on the filesystem that index will be mirrored. -DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE ------------------------------------------------ - -Default: ``True`` - OCR === From a9d02e08bc6e2f5ce3140f4c38ef96fea92c7a43 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 11:07:28 -0400 Subject: [PATCH 370/484] Update top menu icon --- apps/document_indexing/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 7b1b921442..8db3c1d54e 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_top_menu, register_sidebar_template, \ - register_links +from navigation.api import (register_top_menu, register_sidebar_template, + register_links) from main.api import register_maintenance_links from documents.permissions import PERMISSION_DOCUMENT_VIEW @@ -39,12 +39,12 @@ template_node_create = {'text': _(u'new child node'), 'view': 'template_node_cre template_node_edit = {'text': _(u'edit'), 'view': 'template_node_edit', 'args': 'node.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} template_node_delete = {'text': _(u'delete'), 'view': 'template_node_delete', 'args': 'node.pk', 'famfam': 'textfield_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} -index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} +index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_node_view', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True, 'condition': is_not_instance_root_node} document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} -register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'folder_page', 'view': 'index_list'}) +register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'tab', 'view': 'index_list'}) rebuild_index_instances = {'text': _('rebuild indexes'), 'view': 'rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _(u'Deletes and creates from scratch all the document indexes.')} From 57846a758a2701f939af1034914c732b521672f0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 11:20:08 -0400 Subject: [PATCH 371/484] Show index child node count --- apps/document_indexing/views.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index d44c5d105e..3f2e7f3c6e 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -273,17 +273,17 @@ def template_node_delete(request, node_pk): context_instance=RequestContext(request)) +# User views def index_list(request): + """ + Show a list of enabled indexes + """ context = { 'title': _(u'indexes'), - #'hide_object': True, - #'list_object_variable_name': 'index', - #'extra_columns': [ - # {'name': _(u'elements'), 'attribute': 'root'}, - # {'name': _(u'name'), 'attribute': 'name'}, - # {'name': _(u'title'), 'attribute': 'title'}, - #], - 'overrided_object_links': [{}], + 'hide_links': True, + 'extra_columns': [ + {'name': _(u'nodes'), 'attribute': encapsulate(lambda x: x.instance_root.get_descendant_count())}, + ], } queryset = Index.objects.filter(enabled=True) @@ -302,6 +302,10 @@ def index_list(request): def index_instance_node_view(request, index_instance_node_pk): + """ + Show an instance node and it's content, whether is other child nodes + of documents + """ index_instance = get_object_or_404(IndexInstanceNode, pk=index_instance_node_pk) index_instance_list = [index for index in index_instance.get_children().order_by('value')] breadcrumbs = get_breadcrumbs(index_instance) @@ -346,6 +350,9 @@ def index_instance_node_view(request, index_instance_node_pk): def rebuild_index_instances(request): + """ + Confirmation view to execute the tool: do_rebuild_all_indexes + """ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES]) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None))) @@ -373,6 +380,9 @@ def rebuild_index_instances(request): def document_index_list(request, document_id): + """ + Show a list of indexes where the current document can be found + """ document = get_object_or_404(Document, pk=document_id) object_list = [] From 67f3377916a8d4e47ed2587c47d9eca073c32aa2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 12:48:56 -0400 Subject: [PATCH 372/484] Add feedback app --- apps/feedback/__init__.py | 12 ++ apps/feedback/api.py | 12 ++ apps/feedback/forms.py | 92 +++++++++++++++ apps/feedback/locale/en/LC_MESSAGES/django.po | 103 +++++++++++++++++ apps/feedback/locale/es/LC_MESSAGES/django.po | 104 +++++++++++++++++ apps/feedback/locale/it/LC_MESSAGES/django.po | 104 +++++++++++++++++ apps/feedback/locale/pt/LC_MESSAGES/django.po | 104 +++++++++++++++++ apps/feedback/locale/ru/LC_MESSAGES/django.po | 105 ++++++++++++++++++ apps/feedback/models.py | 3 + apps/feedback/tests.py | 16 +++ apps/feedback/urls.py | 5 + apps/feedback/views.py | 31 ++++++ requirements/production.txt | 1 + settings.py | 1 + urls.py | 1 + 15 files changed, 694 insertions(+) create mode 100644 apps/feedback/__init__.py create mode 100644 apps/feedback/api.py create mode 100644 apps/feedback/forms.py create mode 100644 apps/feedback/locale/en/LC_MESSAGES/django.po create mode 100644 apps/feedback/locale/es/LC_MESSAGES/django.po create mode 100644 apps/feedback/locale/it/LC_MESSAGES/django.po create mode 100644 apps/feedback/locale/pt/LC_MESSAGES/django.po create mode 100644 apps/feedback/locale/ru/LC_MESSAGES/django.po create mode 100644 apps/feedback/models.py create mode 100644 apps/feedback/tests.py create mode 100644 apps/feedback/urls.py create mode 100644 apps/feedback/views.py diff --git a/apps/feedback/__init__.py b/apps/feedback/__init__.py new file mode 100644 index 0000000000..1a6a97716c --- /dev/null +++ b/apps/feedback/__init__.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from navigation.api import (register_links, register_top_menu, + register_multi_item_links, register_sidebar_template) +from common import about_view, license_view + +form_view = {'text': _('Feedback'), 'view': 'form_view', 'famfam': 'telephone'} + +register_links(['form_view'], [about_view, license_view], menu_name='secondary_menu') +register_links(['form_view', 'about_view', 'license_view'], [form_view], menu_name='secondary_menu') diff --git a/apps/feedback/api.py b/apps/feedback/api.py new file mode 100644 index 0000000000..b373f74408 --- /dev/null +++ b/apps/feedback/api.py @@ -0,0 +1,12 @@ +import requests + +from django.utils.simplejson import dumps + +FORM_SUBMIT_URL = 'https://docs.google.com/spreadsheet/formResponse' +FORM_KEY = 'dGZrYkw3SDl5OENMTG15emp1UFFEUWc6MQ' +FORM_RECEIVER_FIELD = 'entry.0.single' +TIMEOUT = 10 + + +def submit_form(form): + r = requests.post(FORM_SUBMIT_URL, data={'formkey': FORM_KEY, FORM_RECEIVER_FIELD: dumps(form.cleaned_data)}, timeout=TIMEOUT) diff --git a/apps/feedback/forms.py b/apps/feedback/forms.py new file mode 100644 index 0000000000..afee457dbc --- /dev/null +++ b/apps/feedback/forms.py @@ -0,0 +1,92 @@ +from __future__ import absolute_import + +import logging + +from django import forms +from django.utils.translation import ugettext_lazy as _ + +logger = logging.getLogger(__name__) + + +class FeedbackForm(forms.Form): + attract = forms.CharField( + widget=forms.widgets.Textarea( + attrs={'rows': 2}, + ), + label=_(u'What features of Mayan EDMS attracted you to start using it or consider using it?'), + required=False + ) + + future = forms.CharField( + widget=forms.widgets.Textarea( + attrs={'rows': 2}, + ), + label=_(u'What features would you like to see implemented in Mayan EDMS?'), + required=False + ) + + deploy = forms.CharField( + widget=forms.widgets.Textarea( + attrs={'rows': 2}, + ), + label=_(u'Could you tell us a bit about how you are deploying or plan to deploy Mayan EDMS (OS, webserver, cloud/local, hardware specs)?'), + required=False + ) + + hardest = forms.CharField( + widget=forms.widgets.Textarea( + attrs={'rows': 2}, + ), + label=_(u'What features of Mayan EDMS did you find hardest to understand or implement?'), + required=False + ) + + support = forms.BooleanField( + label=_(u'Would you be interested in purchasing paid support for Mayan EDMS?'), + required=False + ) + + sell_support = forms.BooleanField( + label=_(u'Are currently providing or planning to provide paid support for Mayan EDMS?'), + required=False + ) + + hosted = forms.BooleanField( + label=_(u'Would you be interested in a cloud hosted solution for Mayan EDMS?'), + required=False + ) + + turn_key = forms.BooleanField( + label=_(u'Would you be interested in a turn-key solution for Mayan EDMS that included a physical server appliance?'), + required=False + ) + + name = forms.CharField( + label=_(u'Your name:'), + required=False + ) + + email = forms.CharField( + label=_(u'Your email:'), + required=False + ) + + company = forms.CharField( + label=_(u'Company name:'), + required=False + ) + + website = forms.CharField( + label=_(u'Company website:'), + required=False + ) + + use_info = forms.BooleanField( + label=_(u'May we display your company name & logo in our website as a user of Mayan EDMS with a link back to your website?'), + required=False + ) + + mailing_list = forms.BooleanField( + label=_(u'May we keep your contact information to keep you up to date with developments or oferings related to Mayan EDMS?'), + required=False + ) diff --git a/apps/feedback/locale/en/LC_MESSAGES/django.po b/apps/feedback/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000000..81ae2b76c0 --- /dev/null +++ b/apps/feedback/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,103 @@ +# 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: 2012-02-02 12:46-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: __init__.py:9 +msgid "Feedback" +msgstr "" + +#: forms.py:16 +msgid "" +"What features of Mayan EDMS attracted you to start using it or consider " +"using it?" +msgstr "" + +#: forms.py:24 +msgid "What features would you like to see implemented in Mayan EDMS?" +msgstr "" + +#: forms.py:32 +msgid "" +"Could you tell us a bit about how you are deploying or plan to deploy Mayan " +"EDMS (OS, webserver, cloud/local, hardware specs)?" +msgstr "" + +#: forms.py:40 +msgid "" +"What features of Mayan EDMS did you find hardest to understand or implement?" +msgstr "" + +#: forms.py:45 +msgid "Would you be interested in purchasing paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:50 +msgid "" +"Are currently providing or planning to provide paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:55 +msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" +msgstr "" + +#: forms.py:60 +msgid "" +"Would you be interested in a turn-key solution for Mayan EDMS that included " +"a physical server appliance?" +msgstr "" + +#: forms.py:65 +msgid "Your name:" +msgstr "" + +#: forms.py:70 +msgid "Your email:" +msgstr "" + +#: forms.py:75 +msgid "Company name:" +msgstr "" + +#: forms.py:80 +msgid "Company website:" +msgstr "" + +#: forms.py:85 +msgid "" +"May we display your company name & logo in our website as a user of Mayan " +"EDMS with a link back to your website?" +msgstr "" + +#: forms.py:90 +msgid "" +"May we keep your contact information to keep you up to date with " +"developments or oferings related to Mayan EDMS?" +msgstr "" + +#: views.py:20 +msgid "Thank you for submiting your feedback." +msgstr "" + +#: views.py:23 +#, python-format +msgid "Error submiting form; %s." +msgstr "" + +#: views.py:28 +msgid "feedback form" +msgstr "" diff --git a/apps/feedback/locale/es/LC_MESSAGES/django.po b/apps/feedback/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000000..364afdffd9 --- /dev/null +++ b/apps/feedback/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,104 @@ +# 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: 2012-02-02 12:46-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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 +msgid "Feedback" +msgstr "" + +#: forms.py:16 +msgid "" +"What features of Mayan EDMS attracted you to start using it or consider " +"using it?" +msgstr "" + +#: forms.py:24 +msgid "What features would you like to see implemented in Mayan EDMS?" +msgstr "" + +#: forms.py:32 +msgid "" +"Could you tell us a bit about how you are deploying or plan to deploy Mayan " +"EDMS (OS, webserver, cloud/local, hardware specs)?" +msgstr "" + +#: forms.py:40 +msgid "" +"What features of Mayan EDMS did you find hardest to understand or implement?" +msgstr "" + +#: forms.py:45 +msgid "Would you be interested in purchasing paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:50 +msgid "" +"Are currently providing or planning to provide paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:55 +msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" +msgstr "" + +#: forms.py:60 +msgid "" +"Would you be interested in a turn-key solution for Mayan EDMS that included " +"a physical server appliance?" +msgstr "" + +#: forms.py:65 +msgid "Your name:" +msgstr "" + +#: forms.py:70 +msgid "Your email:" +msgstr "" + +#: forms.py:75 +msgid "Company name:" +msgstr "" + +#: forms.py:80 +msgid "Company website:" +msgstr "" + +#: forms.py:85 +msgid "" +"May we display your company name & logo in our website as a user of Mayan " +"EDMS with a link back to your website?" +msgstr "" + +#: forms.py:90 +msgid "" +"May we keep your contact information to keep you up to date with " +"developments or oferings related to Mayan EDMS?" +msgstr "" + +#: views.py:20 +msgid "Thank you for submiting your feedback." +msgstr "" + +#: views.py:23 +#, python-format +msgid "Error submiting form; %s." +msgstr "" + +#: views.py:28 +msgid "feedback form" +msgstr "" diff --git a/apps/feedback/locale/it/LC_MESSAGES/django.po b/apps/feedback/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000000..364afdffd9 --- /dev/null +++ b/apps/feedback/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,104 @@ +# 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: 2012-02-02 12:46-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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 +msgid "Feedback" +msgstr "" + +#: forms.py:16 +msgid "" +"What features of Mayan EDMS attracted you to start using it or consider " +"using it?" +msgstr "" + +#: forms.py:24 +msgid "What features would you like to see implemented in Mayan EDMS?" +msgstr "" + +#: forms.py:32 +msgid "" +"Could you tell us a bit about how you are deploying or plan to deploy Mayan " +"EDMS (OS, webserver, cloud/local, hardware specs)?" +msgstr "" + +#: forms.py:40 +msgid "" +"What features of Mayan EDMS did you find hardest to understand or implement?" +msgstr "" + +#: forms.py:45 +msgid "Would you be interested in purchasing paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:50 +msgid "" +"Are currently providing or planning to provide paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:55 +msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" +msgstr "" + +#: forms.py:60 +msgid "" +"Would you be interested in a turn-key solution for Mayan EDMS that included " +"a physical server appliance?" +msgstr "" + +#: forms.py:65 +msgid "Your name:" +msgstr "" + +#: forms.py:70 +msgid "Your email:" +msgstr "" + +#: forms.py:75 +msgid "Company name:" +msgstr "" + +#: forms.py:80 +msgid "Company website:" +msgstr "" + +#: forms.py:85 +msgid "" +"May we display your company name & logo in our website as a user of Mayan " +"EDMS with a link back to your website?" +msgstr "" + +#: forms.py:90 +msgid "" +"May we keep your contact information to keep you up to date with " +"developments or oferings related to Mayan EDMS?" +msgstr "" + +#: views.py:20 +msgid "Thank you for submiting your feedback." +msgstr "" + +#: views.py:23 +#, python-format +msgid "Error submiting form; %s." +msgstr "" + +#: views.py:28 +msgid "feedback form" +msgstr "" diff --git a/apps/feedback/locale/pt/LC_MESSAGES/django.po b/apps/feedback/locale/pt/LC_MESSAGES/django.po new file mode 100644 index 0000000000..364afdffd9 --- /dev/null +++ b/apps/feedback/locale/pt/LC_MESSAGES/django.po @@ -0,0 +1,104 @@ +# 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: 2012-02-02 12:46-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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 +msgid "Feedback" +msgstr "" + +#: forms.py:16 +msgid "" +"What features of Mayan EDMS attracted you to start using it or consider " +"using it?" +msgstr "" + +#: forms.py:24 +msgid "What features would you like to see implemented in Mayan EDMS?" +msgstr "" + +#: forms.py:32 +msgid "" +"Could you tell us a bit about how you are deploying or plan to deploy Mayan " +"EDMS (OS, webserver, cloud/local, hardware specs)?" +msgstr "" + +#: forms.py:40 +msgid "" +"What features of Mayan EDMS did you find hardest to understand or implement?" +msgstr "" + +#: forms.py:45 +msgid "Would you be interested in purchasing paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:50 +msgid "" +"Are currently providing or planning to provide paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:55 +msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" +msgstr "" + +#: forms.py:60 +msgid "" +"Would you be interested in a turn-key solution for Mayan EDMS that included " +"a physical server appliance?" +msgstr "" + +#: forms.py:65 +msgid "Your name:" +msgstr "" + +#: forms.py:70 +msgid "Your email:" +msgstr "" + +#: forms.py:75 +msgid "Company name:" +msgstr "" + +#: forms.py:80 +msgid "Company website:" +msgstr "" + +#: forms.py:85 +msgid "" +"May we display your company name & logo in our website as a user of Mayan " +"EDMS with a link back to your website?" +msgstr "" + +#: forms.py:90 +msgid "" +"May we keep your contact information to keep you up to date with " +"developments or oferings related to Mayan EDMS?" +msgstr "" + +#: views.py:20 +msgid "Thank you for submiting your feedback." +msgstr "" + +#: views.py:23 +#, python-format +msgid "Error submiting form; %s." +msgstr "" + +#: views.py:28 +msgid "feedback form" +msgstr "" diff --git a/apps/feedback/locale/ru/LC_MESSAGES/django.po b/apps/feedback/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000000..a53b9861e5 --- /dev/null +++ b/apps/feedback/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,105 @@ +# 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: 2012-02-02 12:46-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \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:9 +msgid "Feedback" +msgstr "" + +#: forms.py:16 +msgid "" +"What features of Mayan EDMS attracted you to start using it or consider " +"using it?" +msgstr "" + +#: forms.py:24 +msgid "What features would you like to see implemented in Mayan EDMS?" +msgstr "" + +#: forms.py:32 +msgid "" +"Could you tell us a bit about how you are deploying or plan to deploy Mayan " +"EDMS (OS, webserver, cloud/local, hardware specs)?" +msgstr "" + +#: forms.py:40 +msgid "" +"What features of Mayan EDMS did you find hardest to understand or implement?" +msgstr "" + +#: forms.py:45 +msgid "Would you be interested in purchasing paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:50 +msgid "" +"Are currently providing or planning to provide paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:55 +msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" +msgstr "" + +#: forms.py:60 +msgid "" +"Would you be interested in a turn-key solution for Mayan EDMS that included " +"a physical server appliance?" +msgstr "" + +#: forms.py:65 +msgid "Your name:" +msgstr "" + +#: forms.py:70 +msgid "Your email:" +msgstr "" + +#: forms.py:75 +msgid "Company name:" +msgstr "" + +#: forms.py:80 +msgid "Company website:" +msgstr "" + +#: forms.py:85 +msgid "" +"May we display your company name & logo in our website as a user of Mayan " +"EDMS with a link back to your website?" +msgstr "" + +#: forms.py:90 +msgid "" +"May we keep your contact information to keep you up to date with " +"developments or oferings related to Mayan EDMS?" +msgstr "" + +#: views.py:20 +msgid "Thank you for submiting your feedback." +msgstr "" + +#: views.py:23 +#, python-format +msgid "Error submiting form; %s." +msgstr "" + +#: views.py:28 +msgid "feedback form" +msgstr "" diff --git a/apps/feedback/models.py b/apps/feedback/models.py new file mode 100644 index 0000000000..71a8362390 --- /dev/null +++ b/apps/feedback/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/feedback/tests.py b/apps/feedback/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/apps/feedback/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/feedback/urls.py b/apps/feedback/urls.py new file mode 100644 index 0000000000..53380a2d92 --- /dev/null +++ b/apps/feedback/urls.py @@ -0,0 +1,5 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('feedback.views', + url(r'^form/$', 'form_view', (), 'form_view'), +) diff --git a/apps/feedback/views.py b/apps/feedback/views.py new file mode 100644 index 0000000000..b6c9d2b5b3 --- /dev/null +++ b/apps/feedback/views.py @@ -0,0 +1,31 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ +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 .forms import FeedbackForm +from .api import submit_form + + +def form_view(request): + if request.method == 'POST': + form = FeedbackForm(request.POST) + if form.is_valid(): + try: + submit_form(form) + messages.success(request, _(u'Thank you for submiting your feedback.')) + return HttpResponseRedirect('/') + except Exception, e: + messages.error(request, _(u'Error submiting form; %s.') % e) + else: + form = FeedbackForm() + + return render_to_response('generic_form.html', { + 'title': _(u'feedback form'), + 'form': form, + }, + context_instance=RequestContext(request)) diff --git a/requirements/production.txt b/requirements/production.txt index f8408ec634..41ab10ed77 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -16,3 +16,4 @@ djangorestframework==0.2.3 South==0.7.3 python-gnupg==0.2.8 python-hkp==0.1.3 +requests==0.10.1 diff --git a/settings.py b/settings.py index fb3ed62f47..ef68252deb 100644 --- a/settings.py +++ b/settings.py @@ -156,6 +156,7 @@ INSTALLED_APPS = ( 'mimetype', 'scheduler', 'job_processor', + 'feedback', # Mayan EDMS 'storage', 'folders', diff --git a/urls.py b/urls.py index c125b3676d..a6ae677f51 100644 --- a/urls.py +++ b/urls.py @@ -31,6 +31,7 @@ urlpatterns = patterns('', (r'^api/', include('rest_api.urls')), (r'^gpg/', include('django_gpg.urls')), (r'^documents/signatures/', include('document_signatures.urls')), + (r'^feedback/', include('feedback.urls')), ) From b3c917a9de8b4068b099e6637fdcd39a94c081a7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 12:49:10 -0400 Subject: [PATCH 373/484] Update language related config files for new feedback app --- .tx/config | 8 ++++++++ misc/compilemessages_all.sh | 6 ++++++ misc/makemessages_all.sh | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/.tx/config b/.tx/config index 59fd72f84b..64a8261443 100644 --- a/.tx/config +++ b/.tx/config @@ -192,3 +192,11 @@ trans.es = apps/acls/locale/es/LC_MESSAGES/django.po trans.pt = apps/acls/locale/pt/LC_MESSAGES/django.po trans.ru = apps/acls/locale/ru/LC_MESSAGES/django.po trans.it = apps/acls/locale/it/LC_MESSAGES/django.po + +[mayan-edms.apps-feedback] +source_file = apps/feedback/locale/en/LC_MESSAGES/django.po +source_lang = en +trans.es = apps/feedback/locale/es/LC_MESSAGES/django.po +trans.pt = apps/feedback/locale/pt/LC_MESSAGES/django.po +trans.ru = apps/feedback/locale/ru/LC_MESSAGES/django.po +trans.it = apps/feedback/locale/it/LC_MESSAGES/django.po diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index a58cb01188..e0f3f7a7f1 100755 --- a/misc/compilemessages_all.sh +++ b/misc/compilemessages_all.sh @@ -146,3 +146,9 @@ $COMPILEMESSAGES -l pt $COMPILEMESSAGES -l ru $COMPILEMESSAGES -l es $COMPILEMESSAGES -l it + +cd $BASE/apps/feedback +$COMPILEMESSAGES -l pt +$COMPILEMESSAGES -l ru +$COMPILEMESSAGES -l es +$COMPILEMESSAGES -l it diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh index 3a91f8de95..509b06d6b9 100755 --- a/misc/makemessages_all.sh +++ b/misc/makemessages_all.sh @@ -170,3 +170,10 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it + +cd $BASE/apps/feedback +$MAKEMESSAGES -l en +$MAKEMESSAGES -l pt +$MAKEMESSAGES -l ru +$MAKEMESSAGES -l es +$MAKEMESSAGES -l it From 5891a39e4177a00713b7a1329c78de09f9248123 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 12:50:20 -0400 Subject: [PATCH 374/484] Added transifex client to the development requirements --- requirements/development.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/development.txt b/requirements/development.txt index 3f7ac40b11..427ff2cf00 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -1,3 +1,4 @@ Werkzeug==0.6.2 django-extensions==0.7.1 django-rosetta==0.6.2 +transifex-client==0.6.1 From e870f4ee5a7a91eb0b90cbed45e732c9913c3ead Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 13:03:10 -0400 Subject: [PATCH 375/484] Fix translation scripts --- misc/compilemessages_all.sh | 2 +- misc/makemessages_all.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index e0f3f7a7f1..f22eff7f29 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 diff --git a/misc/makemessages_all.sh b/misc/makemessages_all.sh index 509b06d6b9..d8f685c5e2 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 From 2dfad128e216d5b8761fadc505014c8fe155cacd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 14:56:15 -0400 Subject: [PATCH 376/484] Language source and translations updates --- apps/acls/locale/en/LC_MESSAGES/django.po | 139 ++-- apps/acls/locale/es/LC_MESSAGES/django.mo | Bin 2725 -> 2658 bytes apps/acls/locale/es/LC_MESSAGES/django.po | 158 ++-- apps/acls/locale/it/LC_MESSAGES/django.mo | Bin 378 -> 528 bytes apps/acls/locale/it/LC_MESSAGES/django.po | 154 ++-- apps/acls/locale/pt/LC_MESSAGES/django.mo | Bin 378 -> 531 bytes apps/acls/locale/pt/LC_MESSAGES/django.po | 154 ++-- apps/acls/locale/ru/LC_MESSAGES/django.mo | Bin 378 -> 4126 bytes apps/acls/locale/ru/LC_MESSAGES/django.po | 225 +++--- apps/common/locale/en/LC_MESSAGES/django.po | 68 +- apps/common/locale/es/LC_MESSAGES/django.mo | Bin 5505 -> 5935 bytes apps/common/locale/es/LC_MESSAGES/django.po | 100 +-- apps/common/locale/it/LC_MESSAGES/django.mo | Bin 5242 -> 5136 bytes apps/common/locale/it/LC_MESSAGES/django.po | 97 +-- apps/common/locale/pt/LC_MESSAGES/django.mo | Bin 5282 -> 5190 bytes apps/common/locale/pt/LC_MESSAGES/django.po | 98 +-- apps/common/locale/ru/LC_MESSAGES/django.mo | Bin 6328 -> 6208 bytes apps/common/locale/ru/LC_MESSAGES/django.po | 97 +-- .../converter/locale/en/LC_MESSAGES/django.po | 10 +- .../converter/locale/es/LC_MESSAGES/django.mo | Bin 5886 -> 19258 bytes .../converter/locale/es/LC_MESSAGES/django.po | 363 ++++----- .../converter/locale/it/LC_MESSAGES/django.mo | Bin 19010 -> 18971 bytes .../converter/locale/it/LC_MESSAGES/django.po | 39 +- .../converter/locale/pt/LC_MESSAGES/django.mo | Bin 18828 -> 18843 bytes .../converter/locale/pt/LC_MESSAGES/django.po | 17 +- .../converter/locale/ru/LC_MESSAGES/django.mo | Bin 19659 -> 19627 bytes .../converter/locale/ru/LC_MESSAGES/django.po | 43 +- .../locale/en/LC_MESSAGES/django.po | 168 ++-- .../locale/es/LC_MESSAGES/django.mo | Bin 4842 -> 3954 bytes .../locale/es/LC_MESSAGES/django.po | 180 ++--- .../locale/it/LC_MESSAGES/django.mo | Bin 4723 -> 3383 bytes .../locale/it/LC_MESSAGES/django.po | 176 ++--- .../locale/pt/LC_MESSAGES/django.mo | Bin 2445 -> 2026 bytes .../locale/pt/LC_MESSAGES/django.po | 172 ++-- .../locale/ru/LC_MESSAGES/django.mo | Bin 556 -> 3930 bytes .../locale/ru/LC_MESSAGES/django.po | 265 +++---- .../locale/en/LC_MESSAGES/django.po | 66 +- .../locale/es/LC_MESSAGES/django.mo | Bin 1799 -> 1792 bytes .../locale/es/LC_MESSAGES/django.po | 81 +- .../locale/it/LC_MESSAGES/django.mo | Bin 1791 -> 1750 bytes .../locale/it/LC_MESSAGES/django.po | 70 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 1788 -> 1792 bytes .../locale/pt/LC_MESSAGES/django.po | 81 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 2189 -> 2179 bytes .../locale/ru/LC_MESSAGES/django.po | 84 +- .../locale/en/LC_MESSAGES/django.po | 283 +++++-- .../locale/es/LC_MESSAGES/django.mo | Bin 4152 -> 6325 bytes .../locale/es/LC_MESSAGES/django.po | 317 ++++++-- .../locale/it/LC_MESSAGES/django.mo | Bin 4162 -> 4094 bytes .../locale/it/LC_MESSAGES/django.po | 294 +++++-- .../locale/pt/LC_MESSAGES/django.mo | Bin 4153 -> 4126 bytes .../locale/pt/LC_MESSAGES/django.po | 308 ++++++-- .../locale/ru/LC_MESSAGES/django.mo | Bin 5159 -> 5125 bytes .../locale/ru/LC_MESSAGES/django.po | 308 ++++++-- .../locale/en/LC_MESSAGES/django.po | 36 +- .../locale/es/LC_MESSAGES/django.mo | Bin 1920 -> 2092 bytes .../locale/es/LC_MESSAGES/django.po | 56 +- .../locale/it/LC_MESSAGES/django.mo | Bin 1568 -> 1718 bytes .../locale/it/LC_MESSAGES/django.po | 55 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 2002 -> 2102 bytes .../locale/pt/LC_MESSAGES/django.po | 55 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 1679 -> 2402 bytes .../locale/ru/LC_MESSAGES/django.po | 64 +- .../documents/locale/en/LC_MESSAGES/django.po | 677 ++++++++++------ .../documents/locale/es/LC_MESSAGES/django.mo | Bin 19503 -> 19709 bytes .../documents/locale/es/LC_MESSAGES/django.po | 685 ++++++++++------ .../documents/locale/it/LC_MESSAGES/django.mo | Bin 18570 -> 18034 bytes .../documents/locale/it/LC_MESSAGES/django.po | 683 ++++++++++------ .../documents/locale/pt/LC_MESSAGES/django.mo | Bin 18083 -> 17598 bytes .../documents/locale/pt/LC_MESSAGES/django.po | 741 +++++++++++------- .../documents/locale/ru/LC_MESSAGES/django.mo | Bin 23407 -> 22801 bytes .../documents/locale/ru/LC_MESSAGES/django.po | 687 +++++++++------- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 2182 -> 2189 bytes .../locale/es/LC_MESSAGES/django.po | 4 +- .../locale/it/LC_MESSAGES/django.mo | Bin 2118 -> 2079 bytes .../locale/it/LC_MESSAGES/django.po | 16 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 2134 -> 2134 bytes .../locale/pt/LC_MESSAGES/django.po | 2 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 2598 -> 2605 bytes .../locale/ru/LC_MESSAGES/django.po | 4 +- apps/feedback/locale/en/LC_MESSAGES/django.po | 2 +- apps/feedback/locale/es/LC_MESSAGES/django.mo | Bin 0 -> 3198 bytes apps/feedback/locale/es/LC_MESSAGES/django.po | 59 +- apps/feedback/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 528 bytes apps/feedback/locale/it/LC_MESSAGES/django.po | 21 +- apps/feedback/locale/pt/LC_MESSAGES/django.mo | Bin 0 -> 531 bytes apps/feedback/locale/pt/LC_MESSAGES/django.po | 21 +- apps/feedback/locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 602 bytes apps/feedback/locale/ru/LC_MESSAGES/django.po | 24 +- apps/folders/locale/en/LC_MESSAGES/django.po | 111 +-- apps/folders/locale/es/LC_MESSAGES/django.mo | Bin 4317 -> 4046 bytes apps/folders/locale/es/LC_MESSAGES/django.po | 134 ++-- apps/folders/locale/it/LC_MESSAGES/django.mo | Bin 4333 -> 4023 bytes apps/folders/locale/it/LC_MESSAGES/django.po | 119 +-- apps/folders/locale/pt/LC_MESSAGES/django.mo | Bin 4215 -> 3962 bytes apps/folders/locale/pt/LC_MESSAGES/django.po | 138 ++-- apps/folders/locale/ru/LC_MESSAGES/django.mo | Bin 4998 -> 4693 bytes apps/folders/locale/ru/LC_MESSAGES/django.po | 141 ++-- apps/history/locale/en/LC_MESSAGES/django.po | 56 +- apps/history/locale/es/LC_MESSAGES/django.mo | Bin 1486 -> 1455 bytes apps/history/locale/es/LC_MESSAGES/django.po | 71 +- apps/history/locale/it/LC_MESSAGES/django.mo | Bin 1478 -> 1406 bytes apps/history/locale/it/LC_MESSAGES/django.po | 60 +- apps/history/locale/pt/LC_MESSAGES/django.mo | Bin 1436 -> 1424 bytes apps/history/locale/pt/LC_MESSAGES/django.po | 71 +- apps/history/locale/ru/LC_MESSAGES/django.mo | Bin 1639 -> 1618 bytes apps/history/locale/ru/LC_MESSAGES/django.po | 74 +- apps/linking/locale/en/LC_MESSAGES/django.po | 138 ++-- apps/linking/locale/es/LC_MESSAGES/django.mo | Bin 7304 -> 7337 bytes apps/linking/locale/es/LC_MESSAGES/django.po | 144 ++-- apps/linking/locale/it/LC_MESSAGES/django.mo | Bin 7140 -> 7147 bytes apps/linking/locale/it/LC_MESSAGES/django.po | 142 ++-- apps/linking/locale/pt/LC_MESSAGES/django.mo | Bin 4333 -> 4333 bytes apps/linking/locale/pt/LC_MESSAGES/django.po | 140 ++-- apps/linking/locale/ru/LC_MESSAGES/django.mo | Bin 8255 -> 8286 bytes apps/linking/locale/ru/LC_MESSAGES/django.po | 142 ++-- apps/main/locale/en/LC_MESSAGES/django.po | 44 +- apps/main/locale/es/LC_MESSAGES/django.mo | Bin 2759 -> 2720 bytes apps/main/locale/es/LC_MESSAGES/django.po | 59 +- apps/main/locale/it/LC_MESSAGES/django.mo | Bin 2538 -> 2499 bytes apps/main/locale/it/LC_MESSAGES/django.po | 65 +- apps/main/locale/pt/LC_MESSAGES/django.mo | Bin 2579 -> 2540 bytes apps/main/locale/pt/LC_MESSAGES/django.po | 59 +- apps/main/locale/ru/LC_MESSAGES/django.mo | Bin 3227 -> 3341 bytes apps/main/locale/ru/LC_MESSAGES/django.po | 70 +- apps/metadata/locale/en/LC_MESSAGES/django.po | 252 +++--- apps/metadata/locale/es/LC_MESSAGES/django.mo | Bin 9967 -> 9974 bytes apps/metadata/locale/es/LC_MESSAGES/django.po | 252 +++--- apps/metadata/locale/it/LC_MESSAGES/django.mo | Bin 9782 -> 9743 bytes apps/metadata/locale/it/LC_MESSAGES/django.po | 290 ++++--- apps/metadata/locale/pt/LC_MESSAGES/django.mo | Bin 9803 -> 9803 bytes apps/metadata/locale/pt/LC_MESSAGES/django.po | 250 +++--- apps/metadata/locale/ru/LC_MESSAGES/django.mo | Bin 12179 -> 12186 bytes apps/metadata/locale/ru/LC_MESSAGES/django.po | 252 +++--- .../locale/en/LC_MESSAGES/django.po | 6 +- .../locale/es/LC_MESSAGES/django.mo | Bin 678 -> 685 bytes .../locale/es/LC_MESSAGES/django.po | 8 +- .../locale/it/LC_MESSAGES/django.mo | Bin 682 -> 643 bytes .../locale/it/LC_MESSAGES/django.po | 17 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 640 -> 640 bytes .../locale/pt/LC_MESSAGES/django.po | 6 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 741 -> 748 bytes .../locale/ru/LC_MESSAGES/django.po | 8 +- apps/ocr/locale/en/LC_MESSAGES/django.po | 230 +++--- apps/ocr/locale/es/LC_MESSAGES/django.mo | Bin 9264 -> 8290 bytes apps/ocr/locale/es/LC_MESSAGES/django.po | 259 +++--- apps/ocr/locale/it/LC_MESSAGES/django.mo | Bin 9009 -> 8068 bytes apps/ocr/locale/it/LC_MESSAGES/django.po | 240 +++--- apps/ocr/locale/pt/LC_MESSAGES/django.mo | Bin 9048 -> 8119 bytes apps/ocr/locale/pt/LC_MESSAGES/django.po | 257 +++--- apps/ocr/locale/ru/LC_MESSAGES/django.mo | Bin 11852 -> 10558 bytes apps/ocr/locale/ru/LC_MESSAGES/django.po | 264 +++---- .../locale/en/LC_MESSAGES/django.po | 138 ++-- .../locale/es/LC_MESSAGES/django.mo | Bin 3297 -> 3304 bytes .../locale/es/LC_MESSAGES/django.po | 142 ++-- .../locale/it/LC_MESSAGES/django.mo | Bin 3264 -> 3271 bytes .../locale/it/LC_MESSAGES/django.po | 142 ++-- .../locale/pt/LC_MESSAGES/django.mo | Bin 2057 -> 2111 bytes .../locale/pt/LC_MESSAGES/django.po | 192 ++--- .../locale/ru/LC_MESSAGES/django.mo | Bin 3721 -> 3752 bytes .../locale/ru/LC_MESSAGES/django.po | 142 ++-- .../locale/en/LC_MESSAGES/django.po | 4 +- .../locale/es/LC_MESSAGES/django.mo | Bin 595 -> 602 bytes .../locale/es/LC_MESSAGES/django.po | 6 +- .../locale/it/LC_MESSAGES/django.mo | Bin 617 -> 578 bytes .../locale/it/LC_MESSAGES/django.po | 15 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 572 -> 572 bytes .../locale/pt/LC_MESSAGES/django.po | 4 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 626 -> 633 bytes .../locale/ru/LC_MESSAGES/django.po | 6 +- .../locale/en/LC_MESSAGES/django.po | 4 +- .../locale/es/LC_MESSAGES/django.mo | Bin 537 -> 544 bytes .../locale/es/LC_MESSAGES/django.po | 6 +- .../locale/it/LC_MESSAGES/django.mo | Bin 561 -> 522 bytes .../locale/it/LC_MESSAGES/django.po | 15 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 519 -> 519 bytes .../locale/pt/LC_MESSAGES/django.po | 4 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 494 -> 592 bytes .../locale/ru/LC_MESSAGES/django.po | 21 +- .../locale/en/LC_MESSAGES/django.po | 10 +- .../locale/es/LC_MESSAGES/django.mo | Bin 642 -> 649 bytes .../locale/es/LC_MESSAGES/django.po | 12 +- .../locale/it/LC_MESSAGES/django.mo | Bin 664 -> 625 bytes .../locale/it/LC_MESSAGES/django.po | 21 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 620 -> 620 bytes .../locale/pt/LC_MESSAGES/django.po | 10 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 707 -> 714 bytes .../locale/ru/LC_MESSAGES/django.po | 12 +- apps/sources/locale/en/LC_MESSAGES/django.po | 259 +++--- apps/sources/locale/es/LC_MESSAGES/django.mo | Bin 8603 -> 8518 bytes apps/sources/locale/es/LC_MESSAGES/django.po | 266 ++++--- apps/sources/locale/it/LC_MESSAGES/django.mo | Bin 8598 -> 8517 bytes apps/sources/locale/it/LC_MESSAGES/django.po | 266 ++++--- apps/sources/locale/pt/LC_MESSAGES/django.mo | Bin 8226 -> 8193 bytes apps/sources/locale/pt/LC_MESSAGES/django.po | 283 ++++--- apps/sources/locale/ru/LC_MESSAGES/django.mo | Bin 10465 -> 10429 bytes apps/sources/locale/ru/LC_MESSAGES/django.po | 289 ++++--- apps/tags/locale/en/LC_MESSAGES/django.po | 182 ++--- apps/tags/locale/es/LC_MESSAGES/django.mo | Bin 4200 -> 3540 bytes apps/tags/locale/es/LC_MESSAGES/django.po | 199 +++-- apps/tags/locale/it/LC_MESSAGES/django.mo | Bin 4271 -> 3549 bytes apps/tags/locale/it/LC_MESSAGES/django.po | 188 ++--- apps/tags/locale/pt/LC_MESSAGES/django.mo | Bin 4144 -> 3496 bytes apps/tags/locale/pt/LC_MESSAGES/django.po | 199 +++-- apps/tags/locale/ru/LC_MESSAGES/django.mo | Bin 4814 -> 4046 bytes apps/tags/locale/ru/LC_MESSAGES/django.po | 202 +++-- .../locale/en/LC_MESSAGES/django.po | 152 ++-- .../locale/es/LC_MESSAGES/django.mo | Bin 4795 -> 4918 bytes .../locale/es/LC_MESSAGES/django.po | 172 ++-- .../locale/it/LC_MESSAGES/django.mo | Bin 4746 -> 4753 bytes .../locale/it/LC_MESSAGES/django.po | 156 ++-- .../locale/pt/LC_MESSAGES/django.mo | Bin 4683 -> 4737 bytes .../locale/pt/LC_MESSAGES/django.po | 167 ++-- .../locale/ru/LC_MESSAGES/django.mo | Bin 6047 -> 6117 bytes .../locale/ru/LC_MESSAGES/django.po | 174 ++-- .../web_theme/locale/en/LC_MESSAGES/django.po | 10 +- .../web_theme/locale/es/LC_MESSAGES/django.mo | Bin 1722 -> 1729 bytes .../web_theme/locale/es/LC_MESSAGES/django.po | 12 +- .../web_theme/locale/it/LC_MESSAGES/django.mo | Bin 1740 -> 1701 bytes .../web_theme/locale/it/LC_MESSAGES/django.po | 21 +- .../web_theme/locale/pt/LC_MESSAGES/django.mo | Bin 1688 -> 1688 bytes .../web_theme/locale/pt/LC_MESSAGES/django.po | 10 +- .../web_theme/locale/ru/LC_MESSAGES/django.mo | Bin 1930 -> 1937 bytes .../web_theme/locale/ru/LC_MESSAGES/django.po | 12 +- 225 files changed, 9360 insertions(+), 7843 deletions(-) create mode 100644 apps/feedback/locale/es/LC_MESSAGES/django.mo create mode 100644 apps/feedback/locale/it/LC_MESSAGES/django.mo create mode 100644 apps/feedback/locale/pt/LC_MESSAGES/django.mo create mode 100644 apps/feedback/locale/ru/LC_MESSAGES/django.mo diff --git a/apps/acls/locale/en/LC_MESSAGES/django.po b/apps/acls/locale/en/LC_MESSAGES/django.po index ac92777769..983294f283 100644 --- a/apps/acls/locale/en/LC_MESSAGES/django.po +++ b/apps/acls/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: 2012-01-02 05:42-0400\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,78 +17,86 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:13 +#: __init__.py:14 msgid "ACLs" msgstr "" -#: __init__.py:14 +#: __init__.py:15 __init__.py:23 msgid "details" msgstr "" -#: __init__.py:15 __init__.py:23 +#: __init__.py:16 __init__.py:25 msgid "grant" msgstr "" -#: __init__.py:16 __init__.py:24 +#: __init__.py:17 __init__.py:26 msgid "revoke" msgstr "" -#: __init__.py:18 -msgid "Default ACLs" -msgstr "" - -#: __init__.py:19 -msgid "List of classes" -msgstr "" - -#: __init__.py:20 -msgid "ACLs for class" -msgstr "" - -#: __init__.py:21 -msgid "edit" -msgstr "" - -#: __init__.py:22 forms.py:18 +#: __init__.py:18 __init__.py:24 forms.py:21 msgid "New holder" msgstr "" -#: forms.py:34 +#: __init__.py:20 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:21 +msgid "List of classes" +msgstr "" + +#: __init__.py:22 +msgid "ACLs for class" +msgstr "" + +#: forms.py:38 msgid "Users" msgstr "" -#: forms.py:37 +#: forms.py:41 msgid "Groups" msgstr "" -#: forms.py:40 +#: forms.py:44 msgid "Roles" msgstr "" -#: models.py:221 models.py:230 +#: forms.py:47 +msgid "Special" +msgstr "" + +#: managers.py:116 managers.py:128 msgid "Insufficient access." msgstr "" -#: models.py:296 models.py:400 +#: models.py:27 models.py:69 msgid "permission" msgstr "" -#: models.py:322 +#: models.py:53 msgid "access entry" msgstr "" -#: models.py:323 +#: models.py:54 msgid "access entries" msgstr "" -#: models.py:421 +#: models.py:90 msgid "default access entry" msgstr "" -#: models.py:422 +#: models.py:91 msgid "default access entries" msgstr "" +#: models.py:109 +msgid "Creator" +msgstr "" + +#: models.py:112 models.py:113 +msgid "creator" +msgstr "" + #: permissions.py:7 permissions.py:8 msgid "Access control lists" msgstr "" @@ -109,126 +117,125 @@ msgstr "" msgid "View class default ACLs" msgstr "" -#: views.py:50 +#: views.py:47 #, python-format msgid "access control lists for: %s" msgstr "" -#: views.py:54 views.py:397 +#: views.py:49 views.py:412 msgid "holder" msgstr "" -#: views.py:55 views.py:398 +#: views.py:50 views.py:413 msgid "permissions" msgstr "" -#: views.py:100 +#: views.py:97 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" msgstr "" -#: views.py:107 views.py:429 +#: views.py:104 views.py:445 msgid "namespace" msgstr "" -#: views.py:108 views.py:430 +#: views.py:105 views.py:446 msgid "label" msgstr "" -#: views.py:110 views.py:432 +#: views.py:107 views.py:448 msgid "has permission" msgstr "" -#: views.py:191 views.py:285 views.py:514 views.py:594 -msgid " and " +#: views.py:185 views.py:279 views.py:529 views.py:609 +msgid ", " msgstr "" -#: views.py:192 views.py:286 views.py:515 views.py:595 +#: views.py:186 views.py:280 views.py:530 views.py:610 #, python-format msgid " for %s" msgstr "" -#: views.py:193 views.py:516 +#: views.py:187 views.py:531 #, python-format msgid " to %s" msgstr "" -#: views.py:196 views.py:519 +#: views.py:190 views.py:534 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "" -#: views.py:198 views.py:521 +#: views.py:192 views.py:536 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "" -#: views.py:205 views.py:528 +#: views.py:199 views.py:543 #, python-format -msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:211 views.py:534 +#: views.py:205 views.py:549 #, python-format msgid "" -"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:287 views.py:596 +#: views.py:281 views.py:611 #, python-format msgid " from %s" msgstr "" -#: views.py:290 views.py:599 +#: views.py:284 views.py:614 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:292 views.py:601 +#: views.py:286 views.py:616 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:299 views.py:608 +#: views.py:293 views.py:623 #, python-format -msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:305 views.py:614 +#: views.py:299 views.py:629 #, python-format -msgid "" -"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" -#: views.py:361 +#: views.py:355 #, python-format msgid "add new holder for: %s" msgstr "" -#: views.py:378 +#: views.py:356 views.py:489 +msgid "Select" +msgstr "" + +#: views.py:389 msgid "classes" msgstr "" -#: views.py:380 +#: views.py:391 msgid "class" msgstr "" -#: views.py:395 +#: views.py:410 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:422 +#: views.py:438 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:472 +#: views.py:487 #, python-format msgid "add new holder for class: %s" msgstr "" - -#: views.py:474 -msgid "Select" -msgstr "" diff --git a/apps/acls/locale/es/LC_MESSAGES/django.mo b/apps/acls/locale/es/LC_MESSAGES/django.mo index f542cabb062b968eb8d89a551139925f99dc14ee..c53034197c9f4f7dfa2b5441b3b2af41ff0c9c59 100644 GIT binary patch delta 1213 zcmYk)U1-x#6u|LY=T@!X+tj)FkxiZJBu!fswYm@HCJGzOtq3Xz*%rHKo0KGVDoR1| zNl{qYgCM@h@MR!O5PcLxd{sf;oD4yH6?_o}{!f>Ihu-{>+vJ>cZ!)`ev9bKEe)WtZ z+8H|;gAt_;R3h~XNgqIee9;CZaWF>4 z>Z>E1@KZe;B+&rM3bWz-MU=uON@G`X9bQ8N@1Wd2kBjWy8CX;y_CE8~5N} z+=tEFRF6GamQF@EIe-%=ojyP*G>yCQG48_GD2czIBwj!%{4>1%6aK%1QlO6R<-Q## z&$XiLSZ6qYA;$i*V`?))ZjffAAg`<%(u}-g>0W}o)h%pAd6%+!X-tYp$gaq%X<^7p zcQ7ROGN@VoZZuqpCUs6J`Osy1<=sncWypsl(azY4NusiTz_bxq}TG9@$B$)lNc@?esP4Vr$S zXFb#L^Jd_B8EwQJv%J8?YF_Pxw>*&u3ng-{bJNUQH+yph)6Po|-DGicB{OH~S<5VB zw9%sJ*#4x}agywI-Zq`McB~`peQIhd5lBJ%vUNS-SbTD!DVJoa)X+8=q=vNlp_ Hi{1SPccQQr delta 1322 zcmZY7Piz!r7{~EZuE6tGPErHHF`Z|%zL=<0t4-8hcR9FJ@()-Zo*%&8?R$0-o!0<8~bq`kKzL? zpk>i!^spCOxWkx5bAgFAx`=x43U0*}Oyg}V;uByREHXDkOxW9u;2U@t-@=pFhhL%+`Udym&!~idM+N*7 zU&p(+8~;J=+edb~KZx2tgG%J>aT?bE-27sa^o}9^*XAQ^U3uekxI7T>oDrQ z57CvhPOL`kb})SlYWj|M()ZAHD781~yV^7AuR#B|?a4%^RiAQG^ zuGh9LxuFWFsS;}Xmh>9Pz5SY0kta>r5771Dr~)cumag~SZq{qn?do(#HdUPV!}(?u zHG`JT3=N-s@-G`@Y$Nnqv0t}wV26f7|J;Hf#eSHL?5QB+O7QtJ9Y5|)lFMgMGamY0OlYU* z#eUw7<_?ZJxr0t_)aKsFA7Xwemt&z*^UpVxVzTa&l3Q~sRj26MW7T|Ra{s5*sZzS^ zMX@s*PI#^8j28!C-hObRT((ngrDTtkD(+;t;1-Lu(#*^lYg>&4ui-nhzBiw@Wp`@g zgmOMoE*H);M}n|1w$$6>ccqQ}!mj?%Q%t%46)JeXN^?PLj>Fdj>pfGZy8m>QRyQ`K OQr#+(7cOn|e*GA5HMisd diff --git a/apps/acls/locale/es/LC_MESSAGES/django.po b/apps/acls/locale/es/LC_MESSAGES/django.po index ab43d0be66..724cbd44ca 100644 --- a/apps/acls/locale/es/LC_MESSAGES/django.po +++ b/apps/acls/locale/es/LC_MESSAGES/django.po @@ -1,94 +1,102 @@ # 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: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-02 05:42-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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: \n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:13 +#: __init__.py:14 msgid "ACLs" msgstr "LCA" -#: __init__.py:14 +#: __init__.py:15 __init__.py:23 msgid "details" msgstr "detalles" -#: __init__.py:15 __init__.py:23 +#: __init__.py:16 __init__.py:25 msgid "grant" msgstr "otorgar" -#: __init__.py:16 __init__.py:24 +#: __init__.py:17 __init__.py:26 msgid "revoke" msgstr "revocar" -#: __init__.py:18 -msgid "Default ACLs" -msgstr "LCA por defecto" - -#: __init__.py:19 -msgid "List of classes" -msgstr "Lista de clases" - -#: __init__.py:20 -msgid "ACLs for class" -msgstr "LCA para la clase" - -#: __init__.py:21 -msgid "edit" -msgstr "editar" - -#: __init__.py:22 forms.py:18 +#: __init__.py:18 __init__.py:24 forms.py:21 msgid "New holder" msgstr "Nuevo titular" -#: forms.py:34 +#: __init__.py:20 +msgid "Default ACLs" +msgstr "LCA por defecto" + +#: __init__.py:21 +msgid "List of classes" +msgstr "Lista de clases" + +#: __init__.py:22 +msgid "ACLs for class" +msgstr "LCA para la clase" + +#: forms.py:38 msgid "Users" msgstr "Usuarios" -#: forms.py:37 +#: forms.py:41 msgid "Groups" msgstr "Grupos" -#: forms.py:40 +#: forms.py:44 msgid "Roles" msgstr "Funciones" -#: models.py:221 models.py:230 +#: forms.py:47 +msgid "Special" +msgstr "" + +#: managers.py:116 managers.py:128 msgid "Insufficient access." msgstr "Acceso insuficiente." -#: models.py:296 models.py:400 +#: models.py:27 models.py:69 msgid "permission" msgstr "permiso" -#: models.py:322 +#: models.py:53 msgid "access entry" msgstr "entrada de acceso" -#: models.py:323 +#: models.py:54 msgid "access entries" msgstr "entradas de acceso" -#: models.py:421 +#: models.py:90 msgid "default access entry" msgstr "entrada de acceso por defecto" -#: models.py:422 +#: models.py:91 msgid "default access entries" msgstr "entradas de acceso por defecto" +#: models.py:109 +msgid "Creator" +msgstr "" + +#: models.py:112 models.py:113 +msgid "creator" +msgstr "" + #: permissions.py:7 permissions.py:8 msgid "Access control lists" msgstr "Listas de control de acceso" @@ -109,127 +117,127 @@ msgstr "Editar LCA por defecto de la clase" msgid "View class default ACLs" msgstr "Ver LCA por defecto de la clase" -#: views.py:50 +#: views.py:47 #, python-format msgid "access control lists for: %s" msgstr "listas de control de acceso para: %s" -#: views.py:54 views.py:397 +#: views.py:49 views.py:412 msgid "holder" msgstr "titular" -#: views.py:55 views.py:398 +#: views.py:50 views.py:413 msgid "permissions" msgstr "permisos" -#: views.py:100 +#: views.py:97 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" msgstr "permisos disponibles a: %(actor)s para %(obj)s " -#: views.py:107 views.py:429 +#: views.py:104 views.py:445 msgid "namespace" msgstr "espacio de nombres" -#: views.py:108 views.py:430 +#: views.py:105 views.py:446 msgid "label" msgstr "etiqueta" -#: views.py:110 views.py:432 +#: views.py:107 views.py:448 msgid "has permission" msgstr "tiene permiso" -#: views.py:191 views.py:285 views.py:514 views.py:594 -msgid " and " -msgstr " y " +#: views.py:185 views.py:279 views.py:529 views.py:609 +msgid ", " +msgstr "" -#: views.py:192 views.py:286 views.py:515 views.py:595 +#: views.py:186 views.py:280 views.py:530 views.py:610 #, python-format msgid " for %s" msgstr " para %s" -#: views.py:193 views.py:516 +#: views.py:187 views.py:531 #, python-format msgid " to %s" msgstr " a %s" -#: views.py:196 views.py:519 +#: views.py:190 views.py:534 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "¿Está seguro que desea conceder el permiso %(title_suffix)s?" -#: views.py:198 views.py:521 +#: views.py:192 views.py:536 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "¿Está seguro que desea conceder los permisos de %(title_suffix)s?" -#: views.py:205 views.py:528 +#: views.py:199 views.py:543 #, python-format -msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." -msgstr "Permiso \"%(permission)s\" concedido a %(requester)s de %(object)s." +msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." +msgstr "" -#: views.py:211 views.py:534 +#: views.py:205 views.py:549 #, python-format msgid "" -"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:287 views.py:596 +#: views.py:281 views.py:611 #, python-format msgid " from %s" msgstr " de %s" -#: views.py:290 views.py:599 +#: views.py:284 views.py:614 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:292 views.py:601 +#: views.py:286 views.py:616 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:299 views.py:608 +#: views.py:293 views.py:623 #, python-format -msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:305 views.py:614 +#: views.py:299 views.py:629 #, python-format -msgid "" -"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" -#: views.py:361 +#: views.py:355 #, python-format msgid "add new holder for: %s" msgstr "" -#: views.py:378 +#: views.py:356 views.py:489 +msgid "Select" +msgstr "" + +#: views.py:389 msgid "classes" msgstr "clases" -#: views.py:380 +#: views.py:391 msgid "class" msgstr "clase" -#: views.py:395 +#: views.py:410 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:422 +#: views.py:438 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:472 +#: views.py:487 #, python-format msgid "add new holder for class: %s" msgstr "añadir nuevo titular para la clase: %s" -#: views.py:474 -msgid "Select" -msgstr "" diff --git a/apps/acls/locale/it/LC_MESSAGES/django.mo b/apps/acls/locale/it/LC_MESSAGES/django.mo index 96ba9bff70db90ca7580704965d08d185be4417e..f82535c3d4ab2d41a6bbcad433ccc44cb2fa62a2 100644 GIT binary patch literal 528 zcmZut!A`?43>|_~kDNIKi31a)X)6vTFof8KG>M976z6VZeO{7pIa?b$`vx=Qqd9*8=e0GGW$Hs2 zHXLM6!31jSkY~QobAHzpp66Dw1!66QC^RmbX*jc$aMmlQtrJz7E423w_+b2)^S%Rx zRF)4Ef@Db)Cp>Boi!WrH^5`Oph{z}KuG{wi@KTvXXAxQOpgi*2DdS6p)=4(8Q*da> z|Mh3rZv7B$1cik)pQ?n<+oDpsY_;A{6;m{-0G@-YBpabBH4S{a8Ed&*hS>JdudoUY zps3eN@}geP$6;Q1fs`#Yif)jNvf*xhaTo=CYY+@+{itbZgcTJjl{QywwouLk_MY>5 zp6+;UzgKX4Xl8bU3IQ~!m&mt3*+wRdXRagW8_pz{k8 C$DphL delta 218 zcmYMuK}*9h7=U3nJoQ(62L(Ys$;!NhF`BKh7L#VAouIeCLMY5elFXa<7bgB&PwP&* zy@%)U93r-tAtOX>zxsG_Z=7kA3QGphipu)_T{S!tCMN7cWrnyn$p;Eg zTOpuflEZ>aR*Qm_rRHtB9PQu^##!vF`Jf, YEAR. # -#, fuzzy +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-02 05:42-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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: \n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:13 +#: __init__.py:14 msgid "ACLs" msgstr "" -#: __init__.py:14 +#: __init__.py:15 __init__.py:23 msgid "details" msgstr "" -#: __init__.py:15 __init__.py:23 +#: __init__.py:16 __init__.py:25 msgid "grant" msgstr "" -#: __init__.py:16 __init__.py:24 +#: __init__.py:17 __init__.py:26 msgid "revoke" msgstr "" -#: __init__.py:18 -msgid "Default ACLs" -msgstr "" - -#: __init__.py:19 -msgid "List of classes" -msgstr "" - -#: __init__.py:20 -msgid "ACLs for class" -msgstr "" - -#: __init__.py:21 -msgid "edit" -msgstr "" - -#: __init__.py:22 forms.py:18 +#: __init__.py:18 __init__.py:24 forms.py:21 msgid "New holder" msgstr "" -#: forms.py:34 +#: __init__.py:20 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:21 +msgid "List of classes" +msgstr "" + +#: __init__.py:22 +msgid "ACLs for class" +msgstr "" + +#: forms.py:38 msgid "Users" msgstr "" -#: forms.py:37 +#: forms.py:41 msgid "Groups" msgstr "" -#: forms.py:40 +#: forms.py:44 msgid "Roles" msgstr "" -#: models.py:221 models.py:230 +#: forms.py:47 +msgid "Special" +msgstr "" + +#: managers.py:116 managers.py:128 msgid "Insufficient access." msgstr "" -#: models.py:296 models.py:400 +#: models.py:27 models.py:69 msgid "permission" msgstr "" -#: models.py:322 +#: models.py:53 msgid "access entry" msgstr "" -#: models.py:323 +#: models.py:54 msgid "access entries" msgstr "" -#: models.py:421 +#: models.py:90 msgid "default access entry" msgstr "" -#: models.py:422 +#: models.py:91 msgid "default access entries" msgstr "" +#: models.py:109 +msgid "Creator" +msgstr "" + +#: models.py:112 models.py:113 +msgid "creator" +msgstr "" + #: permissions.py:7 permissions.py:8 msgid "Access control lists" msgstr "" @@ -109,127 +117,127 @@ msgstr "" msgid "View class default ACLs" msgstr "" -#: views.py:50 +#: views.py:47 #, python-format msgid "access control lists for: %s" msgstr "" -#: views.py:54 views.py:397 +#: views.py:49 views.py:412 msgid "holder" msgstr "" -#: views.py:55 views.py:398 +#: views.py:50 views.py:413 msgid "permissions" msgstr "" -#: views.py:100 +#: views.py:97 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" msgstr "" -#: views.py:107 views.py:429 +#: views.py:104 views.py:445 msgid "namespace" msgstr "" -#: views.py:108 views.py:430 +#: views.py:105 views.py:446 msgid "label" msgstr "" -#: views.py:110 views.py:432 +#: views.py:107 views.py:448 msgid "has permission" msgstr "" -#: views.py:191 views.py:285 views.py:514 views.py:594 -msgid " and " +#: views.py:185 views.py:279 views.py:529 views.py:609 +msgid ", " msgstr "" -#: views.py:192 views.py:286 views.py:515 views.py:595 +#: views.py:186 views.py:280 views.py:530 views.py:610 #, python-format msgid " for %s" msgstr "" -#: views.py:193 views.py:516 +#: views.py:187 views.py:531 #, python-format msgid " to %s" msgstr "" -#: views.py:196 views.py:519 +#: views.py:190 views.py:534 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "" -#: views.py:198 views.py:521 +#: views.py:192 views.py:536 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "" -#: views.py:205 views.py:528 +#: views.py:199 views.py:543 #, python-format -msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:211 views.py:534 +#: views.py:205 views.py:549 #, python-format msgid "" -"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:287 views.py:596 +#: views.py:281 views.py:611 #, python-format msgid " from %s" msgstr "" -#: views.py:290 views.py:599 +#: views.py:284 views.py:614 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:292 views.py:601 +#: views.py:286 views.py:616 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:299 views.py:608 +#: views.py:293 views.py:623 #, python-format -msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:305 views.py:614 +#: views.py:299 views.py:629 #, python-format -msgid "" -"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" -#: views.py:361 +#: views.py:355 #, python-format msgid "add new holder for: %s" msgstr "" -#: views.py:378 +#: views.py:356 views.py:489 +msgid "Select" +msgstr "" + +#: views.py:389 msgid "classes" msgstr "" -#: views.py:380 +#: views.py:391 msgid "class" msgstr "" -#: views.py:395 +#: views.py:410 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:422 +#: views.py:438 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:472 +#: views.py:487 #, python-format msgid "add new holder for class: %s" msgstr "" -#: views.py:474 -msgid "Select" -msgstr "" diff --git a/apps/acls/locale/pt/LC_MESSAGES/django.mo b/apps/acls/locale/pt/LC_MESSAGES/django.mo index 96ba9bff70db90ca7580704965d08d185be4417e..c80761c957eaaaf30ce0dcad0c90e81d4f554c66 100644 GIT binary patch literal 531 zcmZutJx{|h5G{f!BQt}M7(n1SsThJw5uzU#ObeZfXrwJjtQvrG5l?|mr=OvrE8F+LQ zH}%=2-(JK&hGOmPyDH)RT35=Ht=B8cVs)c5@B&mN*@QZ5H2DQ~{L|Tby^gUhW0vq5 zTR>57=M+S}ZIQ#G3IZvCs8O6m`8Xf_O)!mfj=FoR6BBl!GDF;(, YEAR. # -#, fuzzy +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-02 05:42-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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: \n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:13 +#: __init__.py:14 msgid "ACLs" msgstr "" -#: __init__.py:14 +#: __init__.py:15 __init__.py:23 msgid "details" msgstr "" -#: __init__.py:15 __init__.py:23 +#: __init__.py:16 __init__.py:25 msgid "grant" msgstr "" -#: __init__.py:16 __init__.py:24 +#: __init__.py:17 __init__.py:26 msgid "revoke" msgstr "" -#: __init__.py:18 -msgid "Default ACLs" -msgstr "" - -#: __init__.py:19 -msgid "List of classes" -msgstr "" - -#: __init__.py:20 -msgid "ACLs for class" -msgstr "" - -#: __init__.py:21 -msgid "edit" -msgstr "" - -#: __init__.py:22 forms.py:18 +#: __init__.py:18 __init__.py:24 forms.py:21 msgid "New holder" msgstr "" -#: forms.py:34 +#: __init__.py:20 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:21 +msgid "List of classes" +msgstr "" + +#: __init__.py:22 +msgid "ACLs for class" +msgstr "" + +#: forms.py:38 msgid "Users" msgstr "" -#: forms.py:37 +#: forms.py:41 msgid "Groups" msgstr "" -#: forms.py:40 +#: forms.py:44 msgid "Roles" msgstr "" -#: models.py:221 models.py:230 +#: forms.py:47 +msgid "Special" +msgstr "" + +#: managers.py:116 managers.py:128 msgid "Insufficient access." msgstr "" -#: models.py:296 models.py:400 +#: models.py:27 models.py:69 msgid "permission" msgstr "" -#: models.py:322 +#: models.py:53 msgid "access entry" msgstr "" -#: models.py:323 +#: models.py:54 msgid "access entries" msgstr "" -#: models.py:421 +#: models.py:90 msgid "default access entry" msgstr "" -#: models.py:422 +#: models.py:91 msgid "default access entries" msgstr "" +#: models.py:109 +msgid "Creator" +msgstr "" + +#: models.py:112 models.py:113 +msgid "creator" +msgstr "" + #: permissions.py:7 permissions.py:8 msgid "Access control lists" msgstr "" @@ -109,127 +117,127 @@ msgstr "" msgid "View class default ACLs" msgstr "" -#: views.py:50 +#: views.py:47 #, python-format msgid "access control lists for: %s" msgstr "" -#: views.py:54 views.py:397 +#: views.py:49 views.py:412 msgid "holder" msgstr "" -#: views.py:55 views.py:398 +#: views.py:50 views.py:413 msgid "permissions" msgstr "" -#: views.py:100 +#: views.py:97 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" msgstr "" -#: views.py:107 views.py:429 +#: views.py:104 views.py:445 msgid "namespace" msgstr "" -#: views.py:108 views.py:430 +#: views.py:105 views.py:446 msgid "label" msgstr "" -#: views.py:110 views.py:432 +#: views.py:107 views.py:448 msgid "has permission" msgstr "" -#: views.py:191 views.py:285 views.py:514 views.py:594 -msgid " and " +#: views.py:185 views.py:279 views.py:529 views.py:609 +msgid ", " msgstr "" -#: views.py:192 views.py:286 views.py:515 views.py:595 +#: views.py:186 views.py:280 views.py:530 views.py:610 #, python-format msgid " for %s" msgstr "" -#: views.py:193 views.py:516 +#: views.py:187 views.py:531 #, python-format msgid " to %s" msgstr "" -#: views.py:196 views.py:519 +#: views.py:190 views.py:534 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "" -#: views.py:198 views.py:521 +#: views.py:192 views.py:536 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "" -#: views.py:205 views.py:528 +#: views.py:199 views.py:543 #, python-format -msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:211 views.py:534 +#: views.py:205 views.py:549 #, python-format msgid "" -"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:287 views.py:596 +#: views.py:281 views.py:611 #, python-format msgid " from %s" msgstr "" -#: views.py:290 views.py:599 +#: views.py:284 views.py:614 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:292 views.py:601 +#: views.py:286 views.py:616 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:299 views.py:608 +#: views.py:293 views.py:623 #, python-format -msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:305 views.py:614 +#: views.py:299 views.py:629 #, python-format -msgid "" -"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" -#: views.py:361 +#: views.py:355 #, python-format msgid "add new holder for: %s" msgstr "" -#: views.py:378 +#: views.py:356 views.py:489 +msgid "Select" +msgstr "" + +#: views.py:389 msgid "classes" msgstr "" -#: views.py:380 +#: views.py:391 msgid "class" msgstr "" -#: views.py:395 +#: views.py:410 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:422 +#: views.py:438 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:472 +#: views.py:487 #, python-format msgid "add new holder for class: %s" msgstr "" -#: views.py:474 -msgid "Select" -msgstr "" diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.mo b/apps/acls/locale/ru/LC_MESSAGES/django.mo index 96ba9bff70db90ca7580704965d08d185be4417e..2521c4c589b9de3d5082daa93541951b0f41beda 100644 GIT binary patch literal 4126 zcmcJRU2GIp6vwZEimUj6iXR|elwvEL{V1T#!tx<4ABIXPrHKy)rn`5ygR?uExwEtd z9@-MArd5K(gv1#1fd`+gm8PY&?USg94>O6r7-OOjzM1$UFBxBX$&@^=|pJ^EVoGq*9e4gCIgJkY*e#@JopSKtcJ1MdXC1DAt8g7<+x zgAaqhfjhwvCU=1^1sno*13n7YfTTA8lAb2;e()7A1R5ZI%)x`? zP6glnAn6$dNzVn4_VE!&eq9I2-nYT{PvB~N{{`a5Rzn%>Z!P#7xB;a3Lm>H)4(3mT zB!3npy>Ei}u}i`DWsv;10+PQUgZF@wU?$;bFd3+fU)D?djbCd*WmkA7~cf;g00{ckm7IytOb|hgXHQ1?guHq zDUkfnf{%ec;4|O_a6dQ(J`es0()z6{eI5q);X4b)Ne(1Ezk(2Dzk?m%3IuO6cr4&W zkmkPt$=)~MQ{XQk?SCbTfVd7^4@N-B%i(}&km~9*cnF*Z)jB*-$_!>zUP+x>bP1jpcGi&6 zuyVYn)-fDY9Fv7~+UTj1JD0XzE=7SYPFk;t|KLGI1(jTA5^23)I$Q;N#J~|@iloDiN?}XZ zVPINWRc{q+`FiK)j8Yn>BnOkQZyQiu_SwtyREp>3jF+mwU$|&e4f|zMbiKIeYA*PD zR0|h~79FZE+{;qJ(G62FRbQ-2mu24=yr!ZMg&kC8>lY*5hu^kY6k6NqqMBUBH`+2CTRm3{KkXWm2oj~ri11YTo*~58=^A^2V&++D_ zmLs7yk+*C|YmpfvrM+0lNUa^7bU98w9*JZOr>oEzPFmTBZAslWEIX2=wGo`Gf{>xs zL+#ogTj&ndYE8N$;=CamYtW+f83cfE0aYm$=4mwlFJnIjL_PJo`sGA z?g4DLHrQ5ocX!w!8%A36gmc1)!!BXva>SIb9wbC6Pvej|20vYtBFMui5TCwk<)8*eIgd)J9(5t9N#+<4aKSL zi7oW1Rz$bQqWsJme+guwbyyR_nufX%bFaEn-g!Ei?u<7;xa!WR&kx;Mcf#v;C*27; z?{q!$KpJCH?ugfq*%9WJ3u0!*o%RO2K9CfXItUJUXQ2+l?|4HrHs)TVQFjz32JkiI z4ZG7Y?7dEI_=DV?g_^OV26x1l_J%ozN8E9m^xlBLv^(LBRk)^=F&G|&94VUihU&RD z2>rKih+?(q56aCOqRoBgyNsCp4?DR<11h<*6qmE`k5V^?5F@bO+syqyC1J#!RGFd7 zjw1WY{r&|-vIJRPUPZ`t72_AZK2Q_8aYQ>#opZsRj2MJ(BH@0%PJnj?s#$Ia6-vkMpeNV3K&&9$7}J( zz=Aq7?!U{F`!`ZG4rRJ0XvIIBvf?qN(>#v-`A%Wkg0na`heBL92T|<5bmZuCBJDHo zr^pjt=HliJd*@vE?cXEwavIzwx1xuZ&RsHPuPA~gMPhL|SM_u*8o2M~N26*|O3_^u z!Rl*p`Jr-0{1U2i!!g`wbWK3A;$_FmGoUKhdy5VyVn)g*>82&s{?$vj<#ce}B6+^* zX@>blw`hey?|j9<`uRbkQ%HAk@qd`09%_PrV;0+5__v{of>ITr$V&g-(1}Aaju&qt F_BR^S6oqRQDp|O2?cy%n>6KV2=uk?=W^99#ACk17yTJ}2QZq7{3aKANcKW_oqi+J>q~oBhSf0@{;VhB?AiY=ysidGHYJ-i^FJzOKscQ zGz>C6edIF%OOY2*ns~W>H`Za?R`m++H&u(JVc=zHiBqeUtIh6vaI(Ede+d2!8x7GP z`99^C>yNtI#85fS;7RZt;}k;<^OVKW#dDenPpZ~oX;ss%l{1#X!$L|(cr0KnVjjtW phhZ*?VnWrX+Nernsnr_;$&=Zl`*bX2Fj&`D##WQv=dtd4y+568MhE}^ diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.po b/apps/acls/locale/ru/LC_MESSAGES/django.po index 5f517980e5..9da4d973c0 100644 --- a/apps/acls/locale/ru/LC_MESSAGES/django.po +++ b/apps/acls/locale/ru/LC_MESSAGES/django.po @@ -1,235 +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. -# FIRST AUTHOR , YEAR. # -#, fuzzy +# Translators: +# Sergey Glita , 2012. msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-02 05:42-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: \n" - -#: __init__.py:13 -msgid "ACLs" -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:14 -msgid "details" -msgstr "" +msgid "ACLs" +msgstr "Списки ACL" #: __init__.py:15 __init__.py:23 +msgid "details" +msgstr "детали" + +#: __init__.py:16 __init__.py:25 msgid "grant" -msgstr "" +msgstr "предоставить" -#: __init__.py:16 __init__.py:24 +#: __init__.py:17 __init__.py:26 msgid "revoke" -msgstr "" +msgstr "отозвать" -#: __init__.py:18 -msgid "Default ACLs" -msgstr "" - -#: __init__.py:19 -msgid "List of classes" -msgstr "" +#: __init__.py:18 __init__.py:24 forms.py:21 +msgid "New holder" +msgstr "Новый владелец" #: __init__.py:20 -msgid "ACLs for class" -msgstr "" +msgid "Default ACLs" +msgstr "ACL по умолчанию" #: __init__.py:21 -msgid "edit" -msgstr "" +msgid "List of classes" +msgstr "Список классов" -#: __init__.py:22 forms.py:18 -msgid "New holder" -msgstr "" +#: __init__.py:22 +msgid "ACLs for class" +msgstr "ACL для класса" -#: forms.py:34 +#: forms.py:38 msgid "Users" -msgstr "" +msgstr "Пользователи" -#: forms.py:37 +#: forms.py:41 msgid "Groups" -msgstr "" +msgstr "Группы" -#: forms.py:40 +#: forms.py:44 msgid "Roles" +msgstr "Роли" + +#: forms.py:47 +msgid "Special" msgstr "" -#: models.py:221 models.py:230 +#: managers.py:116 managers.py:128 msgid "Insufficient access." -msgstr "" +msgstr "Недостаточный доступ." -#: models.py:296 models.py:400 +#: models.py:27 models.py:69 msgid "permission" -msgstr "" +msgstr "разрешение" -#: models.py:322 +#: models.py:53 msgid "access entry" -msgstr "" +msgstr "запись доступа" -#: models.py:323 +#: models.py:54 msgid "access entries" -msgstr "" +msgstr "записи доступа" -#: models.py:421 +#: models.py:90 msgid "default access entry" +msgstr "запись доступа по умолчанию" + +#: models.py:91 +msgid "default access entries" +msgstr "записи доступа по умолчанию" + +#: models.py:109 +msgid "Creator" msgstr "" -#: models.py:422 -msgid "default access entries" +#: models.py:112 models.py:113 +msgid "creator" msgstr "" #: permissions.py:7 permissions.py:8 msgid "Access control lists" -msgstr "" +msgstr "Списки контроля доступа" #: permissions.py:10 msgid "Edit ACLs" -msgstr "" +msgstr "Редактировать списки ACL" #: permissions.py:11 msgid "View ACLs" -msgstr "" +msgstr "Просмотр списков ACL" #: permissions.py:13 msgid "Edit class default ACLs" -msgstr "" +msgstr "Редактировать списки ACL класса по умолчанию" #: permissions.py:14 msgid "View class default ACLs" -msgstr "" +msgstr "Просмотр списков ACL класса по умолчанию" -#: views.py:50 +#: views.py:47 #, python-format msgid "access control lists for: %s" -msgstr "" +msgstr "списки контроля доступа для %s" -#: views.py:54 views.py:397 +#: views.py:49 views.py:412 msgid "holder" -msgstr "" +msgstr "владелец" -#: views.py:55 views.py:398 +#: views.py:50 views.py:413 msgid "permissions" -msgstr "" +msgstr "разрешения" -#: views.py:100 +#: views.py:97 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" -msgstr "" +msgstr "разрешения, доступные %(actor)s для %(obj)s" -#: views.py:107 views.py:429 +#: views.py:104 views.py:445 msgid "namespace" -msgstr "" +msgstr "пространство имен" -#: views.py:108 views.py:430 +#: views.py:105 views.py:446 msgid "label" -msgstr "" +msgstr "этикетка" -#: views.py:110 views.py:432 +#: views.py:107 views.py:448 msgid "has permission" +msgstr "имеет разрешение" + +#: views.py:185 views.py:279 views.py:529 views.py:609 +msgid ", " msgstr "" -#: views.py:191 views.py:285 views.py:514 views.py:594 -msgid " and " -msgstr "" - -#: views.py:192 views.py:286 views.py:515 views.py:595 +#: views.py:186 views.py:280 views.py:530 views.py:610 #, python-format msgid " for %s" -msgstr "" +msgstr "для %s" -#: views.py:193 views.py:516 +#: views.py:187 views.py:531 #, python-format msgid " to %s" -msgstr "" +msgstr "до %s" -#: views.py:196 views.py:519 +#: views.py:190 views.py:534 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" -msgstr "" +msgstr "Вы действительно хотите предоставить разрешение %(title_suffix)s?" -#: views.py:198 views.py:521 +#: views.py:192 views.py:536 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" -msgstr "" +msgstr "Вы уверены, что хотите предоставить разрешения %(title_suffix)s?" -#: views.py:205 views.py:528 +#: views.py:199 views.py:543 #, python-format -msgid "Permission \"%(permission)s\" granted to %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:211 views.py:534 +#: views.py:205 views.py:549 #, python-format msgid "" -"%(requester)s, already had the permission \"%(permission)s\" granted for " +"%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:287 views.py:596 +#: views.py:281 views.py:611 #, python-format msgid " from %s" -msgstr "" +msgstr "от%s" -#: views.py:290 views.py:599 +#: views.py:284 views.py:614 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" -msgstr "" +msgstr "Вы уверены, что хотите отменить разрешение %(title_suffix)s?" -#: views.py:292 views.py:601 +#: views.py:286 views.py:616 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" -msgstr "" +msgstr "Вы уверены, что хотите отменить разрешение %(title_suffix)s?" -#: views.py:299 views.py:608 +#: views.py:293 views.py:623 #, python-format -msgid "Permission \"%(permission)s\" revoked of %(requester)s for %(object)s." +msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:305 views.py:614 +#: views.py:299 views.py:629 #, python-format -msgid "" -"%(requester)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" -#: views.py:361 +#: views.py:355 #, python-format msgid "add new holder for: %s" -msgstr "" +msgstr "добавить нового владельца для %s" -#: views.py:378 +#: views.py:356 views.py:489 +msgid "Select" +msgstr "Выбор" + +#: views.py:389 msgid "classes" -msgstr "" +msgstr "классы" -#: views.py:380 +#: views.py:391 msgid "class" -msgstr "" +msgstr "класс" -#: views.py:395 +#: views.py:410 #, python-format msgid "default access control lists for class: %s" -msgstr "" +msgstr "списки контроля доступа умолчанию для класса %s" -#: views.py:422 +#: views.py:438 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" -msgstr "" +msgstr "разрешения доступные %(actor)s для класса %(class)s" -#: views.py:472 +#: views.py:487 #, python-format msgid "add new holder for class: %s" -msgstr "" +msgstr "добавить нового владельца для класса %s" -#: views.py:474 -msgid "Select" -msgstr "" diff --git a/apps/common/locale/en/LC_MESSAGES/django.po b/apps/common/locale/en/LC_MESSAGES/django.po index 42ca56215d..e0d5d55e53 100644 --- a/apps/common/locale/en/LC_MESSAGES/django.po +++ b/apps/common/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: 2012-01-08 07:39-0400\n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,27 +17,23 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:21 +#: __init__.py:20 msgid "change password" msgstr "" -#: __init__.py:22 +#: __init__.py:21 msgid "user details" msgstr "" -#: __init__.py:23 +#: __init__.py:22 msgid "edit details" msgstr "" -#: __init__.py:27 __init__.py:33 +#: __init__.py:26 __init__.py:31 msgid "about" msgstr "" -#: __init__.py:28 -msgid "changelog" -msgstr "" - -#: __init__.py:29 +#: __init__.py:27 msgid "license" msgstr "" @@ -115,15 +111,11 @@ msgstr "" msgid "function found" msgstr "" -#: views.py:25 templates/password_change_done.html:5 -msgid "Your password has been successfully changed." -msgstr "" - -#: views.py:42 +#: views.py:35 msgid "No action selected." msgstr "" -#: views.py:46 +#: views.py:39 msgid "Must select at least one item." msgstr "" @@ -132,42 +124,50 @@ msgstr "" msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "" -#: views.py:90 views.py:107 +#: views.py:90 views.py:114 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "" -#: views.py:104 +#: views.py:111 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." msgstr "" -#: views.py:122 +#: views.py:129 msgid "Add" msgstr "" -#: views.py:133 +#: views.py:140 msgid "Remove" msgstr "" -#: views.py:156 +#: views.py:163 msgid "current user details" msgstr "" -#: views.py:173 +#: views.py:180 +msgid "E-mail conflict, another user has that same email." +msgstr "" + +#: views.py:183 msgid "Current user's details updated." msgstr "" -#: views.py:182 +#: views.py:192 msgid "edit current user details" msgstr "" -#: views.py:213 -msgid "Changelog" +#: views.py:223 +msgid "License" msgstr "" -#: views.py:226 -msgid "License" +#: views.py:232 +msgid "Current user password change" +msgstr "" + +#: views.py:247 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." msgstr "" #: widgets.py:58 @@ -271,12 +271,12 @@ msgid "No" msgstr "" #: templates/generic_form_instance.html:37 -#: templates/generic_form_subtemplate.html:52 +#: templates/generic_form_subtemplate.html:56 msgid "required" msgstr "" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -284,8 +284,8 @@ msgstr "" msgid "Save" msgstr "" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -293,6 +293,10 @@ msgstr "" msgid "Submit" msgstr "" +#: templates/generic_form_subtemplate.html:87 +msgid "Cancel" +msgstr "" + #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format msgid "List of %(stripped_title)s" diff --git a/apps/common/locale/es/LC_MESSAGES/django.mo b/apps/common/locale/es/LC_MESSAGES/django.mo index c250fe7658811434632ba9244155a58c7867e6d4..af532bd9417dbba8eb6739b29f922aba600978ec 100644 GIT binary patch delta 2147 zcmZwGTWl0n9LMofffh^4wpi}B0WYX@ySt@Ws0d1_`a-NrO`w; zMnW_gL!6+1!4MO#52BEuQGVHS@<-`tHf95M;vjBEnwZ0>M^azLDcpYrd+}AA zi5GAk{)FAQti_mxcn{J~%{r&c-u14bNdKZuf;!51L;ByTTs{S$e5-JHGxGqiv744 zkD=OsfJ^W!DpQkq9bQCD0BgEcBTEWaX)Gwqxd z&1^B&GlM!@n^6Odp-!=%x*y->`dIpWi2YN$t*N_ETl5fW3(BYky@_97?Iabgc!FM) znip^_zJoeEmvI&TjM@T=g=xL%g=znsvgGg!aVNNHNFZ;$F68FK@%R2P&xh#^8*TuG>Ci&S*zZmQRe zxjR+oqP`$~0awZ}l}*IW$>g*b3!WEDSbpGJb~P?Le(V?T$)VD;t;z1h5eR-td8 z(4WosiYiyg(;oykXSGcr4ZQ70q=I~pS=U$;G->~6om zZ41k-+ItwviIVr*KO7!$!ipQ)mTh@K#9FJGXhd?A+eT_j0ZDbdMqas3W=o{QBgSn% zCdqb`jL&?nS^2fYWI^Vu$6R>h4fLGo^uQ@e(blzTxB3#qsTU$ni&|}3ySA)0EYZP0 z2;D%(@XEvH#%>ny!WTsA8;CHdD54?=YQYOd@j|8`y_z6i`29V3iiiI5IXRr?Ip_aB zCq36Z-k5(n&-1&XrHCq`>l0(rxZA@A?OCZY-S`~WVU5=qrkFw3Vb||*7UN?W#4L8< zI5y$GSc$Ju&zF@s=8d1uYz6|zpQ+$OFQ~>X*o-`5^0*ieV>K4A9w)H^|3mG$#AnPx z^dfsURp`fBT!b;ydh5|^@+?9}6L&ZR#`GfZGW$>qj$%I^!O!p&YQB%REWscuqZrP| zIBFv)R3hKtTTFHo5;Wcz<%6)N*9_$f|dD^8I3Kn1 zN{nC~{)%0wOmCtt*`_UjqjjVDsh>>czjI7Azn|FsD!p zTz0*Ns>CE}!*{SBU!v~B#&EIJBUsP(pHPVuPiyUAbaY$qxIV+veE;8_P?%So zc*=DGIc{?myYU7p0S`Ct7S2Is`T$jlH`sxG&RKUPg)4Cbs^a-Wbd=c{q*`VIdB#kl zcK8UD(G#r0_o#Wb>{|0yxUNT4WGCu~2Hf%e$Q5zU8=R(%tIDmc?<}ITh!Hvh-G>CR zoS11}x*e5JO}}HcMnYNX*P|p<31zJe<3t;=j8LXJhM7hVPL;I2(^OL3Xl2kzv=B|i zS42Cpn$SIn65LJaaw&T?ou}HGBF=HD`?>pF)vG3S3^T2ErZY@umHUMwH#LMVlv=Wg z;fT!_ZeOKW)6aFO(<}a4R##>Qn(Re)B*4`MW`8TI? z2V&c@>9O2s`amX|jAk>rbao_@wPyprly7FKgXy8cWOOiRTY|gn@!(ba=iC#e`};>S sIlDG=&y(UYJ07X9Tf^Hfz6, 2011. +# Roberto Rosario , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-08 07:39-0400\n" -"PO-Revision-Date: 2011-11-04 00:58+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:39+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:21 +#: __init__.py:20 msgid "change password" msgstr "cambiar contraseña" -#: __init__.py:22 +#: __init__.py:21 msgid "user details" msgstr "detalles de usuario" -#: __init__.py:23 +#: __init__.py:22 msgid "edit details" msgstr "editar detalles" -#: __init__.py:27 __init__.py:33 +#: __init__.py:26 __init__.py:31 msgid "about" msgstr "sobre" -#: __init__.py:28 -msgid "changelog" -msgstr "cambios" - -#: __init__.py:29 +#: __init__.py:27 msgid "license" msgstr "licencia" @@ -106,7 +101,7 @@ msgstr "Paisaje" #: models.py:16 msgid "lock field" -msgstr "" +msgstr "campo de bloqueo" #: models.py:43 msgid "Anonymous user" @@ -114,21 +109,17 @@ msgstr "Usuario anónimo" #: models.py:46 models.py:47 msgid "anonymous user" -msgstr "usario anónimo" +msgstr "usuario anónimo" #: utils.py:295 msgid "function found" msgstr "función encontrada" -#: views.py:25 templates/password_change_done.html:5 -msgid "Your password has been successfully changed." -msgstr "Su contraseña se ha modificado correctamente." - -#: views.py:42 +#: views.py:35 msgid "No action selected." msgstr "Ninguna acción seleccionada." -#: views.py:46 +#: views.py:39 msgid "Must select at least one item." msgstr "Debe seleccionar al menos un artículo." @@ -137,44 +128,54 @@ msgstr "Debe seleccionar al menos un artículo." msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "Se agrego exitosamente %(selection)s a %(right_list_title)s." -#: views.py:90 views.py:107 +#: views.py:90 views.py:114 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "No se puede agregar %(selection)s a %(right_list_title)s." -#: views.py:104 +#: views.py:111 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." msgstr "Se removió exitosamente %(selection)s de %(right_list_title)s." -#: views.py:122 +#: views.py:129 msgid "Add" msgstr "Agregar" -#: views.py:133 +#: views.py:140 msgid "Remove" msgstr "Remover" -#: views.py:156 +#: views.py:163 msgid "current user details" msgstr "detalles del usuario corriente" -#: views.py:173 +#: views.py:180 +msgid "E-mail conflict, another user has that same email." +msgstr "" +"Conflicto de correo electrónica, otro usuario tiene ese mismo correo " +"electrónico." + +#: views.py:183 msgid "Current user's details updated." msgstr "Datos del usuario corriente actualizados." -#: views.py:182 +#: views.py:192 msgid "edit current user details" msgstr "editar detalles del usuario corriente" -#: views.py:213 -msgid "Changelog" -msgstr "Cambios" - -#: views.py:226 +#: views.py:223 msgid "License" msgstr "Licencia" +#: views.py:232 +msgid "Current user password change" +msgstr "Cambio de contraseña de usuario actual" + +#: views.py:247 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." +msgstr "Su contraseña se ha modificado correctamente." + #: widgets.py:58 msgid "None" msgstr "Ninguno" @@ -182,8 +183,8 @@ msgstr "Ninguno" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using tempfile." -"mkdtemp()" +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" msgstr "" "Directorio temporal utilizado por todo el sitio para almacenar imágenes en " "miniatura, vistas previas y los archivos temporales. Si no se especifica " @@ -200,6 +201,7 @@ msgstr "" #: conf/settings.py:74 msgid "Allow non authenticated users, access to all views" msgstr "" +"Permita a los usuarios no autenticados, el acceso a todas las pantallas" #: templates/403.html:3 templates/403.html.py:7 msgid "Insufficient permissions" @@ -281,12 +283,12 @@ msgid "No" msgstr "No" #: templates/generic_form_instance.html:37 -#: templates/generic_form_subtemplate.html:52 +#: templates/generic_form_subtemplate.html:56 msgid "required" msgstr "requerido" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -294,8 +296,8 @@ msgstr "requerido" msgid "Save" msgstr "Guardar" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -303,6 +305,10 @@ msgstr "Guardar" msgid "Submit" msgstr "Enviar" +#: templates/generic_form_subtemplate.html:87 +msgid "Cancel" +msgstr "Cancelar" + #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format msgid "List of %(stripped_title)s" @@ -342,8 +348,4 @@ msgstr "Iniciar sesión" msgid "Password change" msgstr "Cambio de contraseña" -#~ msgid "class found: %s" -#~ msgstr "clase encontrada: %s" -#~ msgid "Cancel" -#~ msgstr "Cancelar" diff --git a/apps/common/locale/it/LC_MESSAGES/django.mo b/apps/common/locale/it/LC_MESSAGES/django.mo index 5ac939ecbbde5403e8fe6dec4eedccd50892a41d..ac9bbfed478c7f5b070bb3d867ab819c1b727b00 100644 GIT binary patch delta 1526 zcmYk*T}V_x7{>8YS5sHlbSpFaF#GT;%{5IkQ=y2Uq9`v630gs-5Z87W0ui@vB+5`) zj70H9h=ihGmFgzwCIk`crU*m{%$q2QN+<;TKj$2yVP}7H=FH4_&pUJe6b=+d=CWLa zhSEsgsv2+11?l3CawE~02E2(!@ij8UBqrG=JGwD}eh=1R7Vg6{n2X)0c@G?iah)*{ zGfKn5jfZ#^Cy}2?;_enq#~oOR1$Y9pu@e>JE!>EAk=V=_rs6nm#tBTp8PvKTP~+yT z>xeN6H29e>{ON%|uoXSY#%#lDs0sbJ9S2cwGJ#%vjtXQN^&)RE1Lv^?myn-1NfZj8 z2{pb2Q+U3)M8k(yodF{_#Pt~J&5!UpId~B(@j5EikFg4$p;Enw3e@Yi1IWP*To<9{ z*JBzsBTJh$j40v&4P~GQ6=^SOU_ZW(GiC%2a~(=I<~Tk@WnkIyx8n+G{wivGGK&}E zG1S=#pyu^C_IucWO}IygA{@phoJ6H4l{{)oGO!Sf9nYiowi`8n5H)`km4O$?66O_d z!WkqvW&yPYOQ>PDS`0@R-0Mokz;J@_f=O{P!*PNU{8VitZw zmNaph_BxrUl!wvEG-|!xh;yS4_tSA773mv%gzr!Rbg`-)G=%!RCQt!5i96**dFOe8cWZG%Wq9Xf>THu${zlt0Ivy-ZcjZ_sKK#k9%Dj?0# zUYAgH7*%}KYAUgrJ=A<^DOG_hC<2OD`>a%G8&vd`2d$R`(0oeO1Y7q!B1{YMmQO+geeIRI~;E7Y?}bM*WG|RrR!V z)bt^$?6$FvT>>Lw4@v#GWMP$HhJ--El>G+@I4cO3U@j^HtXRs-vB0xu^g2 z)YSTFO3Epzr~ILCX;aYO5o-5`1Hsz7bAi^jU^svwfAC5muP$hJlm+dMvde*vE`NJl TS8OURBR=-YGw+JddPn~P^0Ad6 delta 1629 zcmY+^e`t+S9LMpq?cSN0F&j3+9%jss%bx3Q=GtsVNE5PRNqROj%e8y$&X0d|OO$^I zOQIwt34hT3kpD#aF+ylbCYp%kNB&Ssd4KLb!fD^V&U2pgobx^BInO;({7hmIQ{DS3contf@30a-qPE-_mP&LbDuK1g z5T?~$Z^r_z_hLc=9;1?jmr)(BqgHSWwIfeZnZH2w8^qgb#(c#ETwfb*%u@W0+L161 z%UWwa>iNZ}{*5>T59YG}I&{6Z<74YnR3iPT2VbKS{eVrF!Lqc~>rt<2BbMVH>si!0 z??XL5hJ?^=Of4{HB>O*xhGH7nJrhK2eJ!fv5_`P@wG(Slr@0w*Hg=-U!gEyr zAE=3cp>|+QUMj&N)bk-6g*8YnW>tcU2HJ#L@l9062dDv`+4dJWhwHbfL<<<@0+yf> zxQp6}_o&Y=ofD}9>QHB;0cYcG)I8@=2_&xAh8xJ(rVn-6U!u13r)@9g#IPt+XdwBI2@N7W(f2|g(^ zu6M70a$43_ud}@^5^e82oq5Pt_~**BM!b03*%IB^xjF2V#e2$!y&vudTsII5I<6ZI zR`ra}DXyg@7^s-%xYglcaApN1yU~kx2b#LP&UnP@j&_BeSVt@ttqM6cv5vN`m=}#i pXSaBf&0c5k{+to%f9F4%`^Hz?`hNm#PIp&ym)GruNnuC+ncw0ps6_w( diff --git a/apps/common/locale/it/LC_MESSAGES/django.po b/apps/common/locale/it/LC_MESSAGES/django.po index a1a9e229e4..dea31d3245 100644 --- a/apps/common/locale/it/LC_MESSAGES/django.po +++ b/apps/common/locale/it/LC_MESSAGES/django.po @@ -1,45 +1,40 @@ # 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-01-08 07:39-0400\n" -"PO-Revision-Date: 2011-12-07 18:22+0000\n" -"Last-Translator: pippo64 \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:17-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" "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:20 msgid "change password" msgstr "cambia password" -#: __init__.py:22 +#: __init__.py:21 msgid "user details" msgstr "dettaglio utente" -#: __init__.py:23 +#: __init__.py:22 msgid "edit details" msgstr "modifica dettagli" -#: __init__.py:27 __init__.py:33 +#: __init__.py:26 __init__.py:31 msgid "about" msgstr "a rigurdo" -#: __init__.py:28 -msgid "changelog" -msgstr "changelog" - -#: __init__.py:29 +#: __init__.py:27 msgid "license" msgstr "licenza" @@ -119,15 +114,11 @@ msgstr "" msgid "function found" msgstr "trovata funzione" -#: views.py:25 templates/password_change_done.html:5 -msgid "Your password has been successfully changed." -msgstr "La tua password è stata cambiata con successo" - -#: views.py:42 +#: views.py:35 msgid "No action selected." msgstr "Nessuna azione selezionata" -#: views.py:46 +#: views.py:39 msgid "Must select at least one item." msgstr "Devi selezionare un item" @@ -136,44 +127,53 @@ msgstr "Devi selezionare un item" msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "%(selection)s aggiunto con successo a %(right_list_title)s." -#: views.py:90 views.py:107 +#: views.py:90 views.py:114 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "Impossibile aggiungere %(selection)s a %(right_list_title)s." -#: views.py:104 +#: views.py:111 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." -msgstr "%(selection)s aggiunto correttamente rimosso dal %(right_list_title)s." +msgstr "" +"%(selection)s aggiunto correttamente rimosso dal %(right_list_title)s." -#: views.py:122 +#: views.py:129 msgid "Add" msgstr "Aggiungi" -#: views.py:133 +#: views.py:140 msgid "Remove" msgstr "Rimuovi" -#: views.py:156 +#: views.py:163 msgid "current user details" msgstr "dettagli dell'utente corrente" -#: views.py:173 +#: views.py:180 +msgid "E-mail conflict, another user has that same email." +msgstr "" + +#: views.py:183 msgid "Current user's details updated." msgstr "Dettagli dell'utente corrente aggiornati" -#: views.py:182 +#: views.py:192 msgid "edit current user details" msgstr "modifica i dettagli dell'utente corrente" -#: views.py:213 -msgid "Changelog" -msgstr "Changelog" - -#: views.py:226 +#: views.py:223 msgid "License" msgstr "Licenza" +#: views.py:232 +msgid "Current user password change" +msgstr "" + +#: views.py:247 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." +msgstr "La tua password è stata cambiata con successo" + #: widgets.py:58 msgid "None" msgstr "Nessuno" @@ -181,8 +181,8 @@ msgstr "Nessuno" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using tempfile." -"mkdtemp()" +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" msgstr "" "Directory temporanea utilizzata a livello di sito per thumbnails, anteprime " "e file temporanei. Se non viene specificato, ne verrà creata utilizzando " @@ -193,8 +193,8 @@ msgid "" "Controls the mechanism used to authenticated user. Options are: username, " "email" msgstr "" -"Controllo del meccanismo di autenticazione. Le opzioni possibili sono:" -"username,email" +"Controllo del meccanismo di autenticazione. Le opzioni possibili " +"sono:username,email" #: conf/settings.py:74 msgid "Allow non authenticated users, access to all views" @@ -280,12 +280,12 @@ msgid "No" msgstr "No" #: templates/generic_form_instance.html:37 -#: templates/generic_form_subtemplate.html:52 +#: templates/generic_form_subtemplate.html:56 msgid "required" msgstr "richiesto" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -293,8 +293,8 @@ msgstr "richiesto" msgid "Save" msgstr "Salva" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -302,6 +302,10 @@ msgstr "Salva" msgid "Submit" msgstr "Sottometti" +#: templates/generic_form_subtemplate.html:87 +msgid "Cancel" +msgstr "" + #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format msgid "List of %(stripped_title)s" @@ -341,5 +345,4 @@ msgstr "Login" msgid "Password change" msgstr "Cambia password" -#~ msgid "class found: %s" -#~ msgstr "classe trovata:%s" + diff --git a/apps/common/locale/pt/LC_MESSAGES/django.mo b/apps/common/locale/pt/LC_MESSAGES/django.mo index ade5e888b5b5e372a85ecfa0aa0cfed0cfa0fcca..070eb0b939834f0920dc84e90b0f71cc0d30155c 100644 GIT binary patch delta 1586 zcmYk+OGs2v9LMovIi}9T(q3kdv6oJ!M}pwS`-Bnl#gASha7i^5Hd7C~)-`u=8a(c%8*bME!rd;jNu&UM)LvOGCc zm_2A{yNKnAImR58+5FHhI*e(+OSl`SkRisAlQGxUiF3K`!Fnvjjo6GOcpi1%b=#Xb z&zPjSMaRP*?qLf)Mh=t1Uzed9S7AApVG}OFK2(lZa1mZZax){Cj}LGuPGTNTqn`U7 zHEt$-o;2nQ9S-xAAHDE9cA_WOm=$;mb;AIz#6i?dCb0;gpb~kFn#db0z)#qY-;l%X zCkrLeh8o|FdA#2orxU=F_JAS0!TAVk<~x{9F&@QQJcBCr7;eT#s8Y|O5-oCO5-7%n zocmDs??e|KLLO~Gm{i75I;y}0RHm0v0|)R!mN7%Plk?MVWA@@>R0V$7{k53o7M9wD37jh{@?Q3amj4t#-1WNsm4LKiBbG1N?6VIzJ+5mF;#y zNp2;o2sJ;!{!DM!ZK&D)ZK~XQ`=l1NbT#(54;#`?q@$Sz?LVk&e;do1Zu;*3Z`xc% zDa)~Bv%U*VotB{;ou#FX;D& zyAxggomD5Iz5ZA>n((|1dzb#3Cf7mPWU|^=NGG%-x~U zNG>ta&V;G3{$g?y>I02f5yZ z-8g_xU>>*PdDQQ|wSJEeaoa3VS<8)|unKSD5Z*@))5py)9>7O%44d#>+>D>2a{U@> z@hXy|xq%h9jCFVq8PKdPFFki71{vSf*$dl{KBf^hU=+vjAU5C^s0V+C+wcd}jP79# zuA&kNGKwZrf$MP#j$j1oVy00Odmqaf-<+nxVa{-h;T)>NB7TfFP&0p%>1@G|unjMw zmi!jB;~mtJJC&tG51|q`f;_^E+x8T0qJ0wcdf*3CLUbFfS=1|BK&|9$)LvP!?eY!AkgHk0f%Vr4G;l#P>_pA54>iCc z>k)f@7&YJ+zKnU)1b#vF{|k3uaARpNL{PiG1(nFNs6-AUxtNJOm19)iLM`>8bqV!@ zTc{Pdi%;Vps6^YVjrkONPzf!eCh{j9z*?41dt(&4(Z%if2`bUAPzmI(QsFSyIqCEH z4V7_#9kLS}P#p(Q_g_HuKaNV|9aQ4e$YD-#Vr%$=k&FMI0e&*-_bAazXi~hYyuV|k zG*sfm9zp{=MrbKp2yG^PauLG+#89i#MJU-$VlSZ*BlNvLOlWf|$)||jgi0&HzV%;o zw|T9!e7d2c@4U&cl|Cu0z>~JU3kPgnE1}n+!Ylu`@OJ#7J@Mbdel?p4vEb(Rerj6J z4tu-Ns$J1cv=Mrd4$((wn}&-ggWCh;$K6!Yn@lH*Giy$j)&0{l%5vikxFzq zjoCtT<++^|L(d#!a|>&T}=he*>{-yXF7@ diff --git a/apps/common/locale/pt/LC_MESSAGES/django.po b/apps/common/locale/pt/LC_MESSAGES/django.po index c9a99ce181..75a44cd6b5 100644 --- a/apps/common/locale/pt/LC_MESSAGES/django.po +++ b/apps/common/locale/pt/LC_MESSAGES/django.po @@ -1,45 +1,40 @@ # 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-01-08 07:39-0400\n" -"PO-Revision-Date: 2011-11-02 02:18+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-02 14:17-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" "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:21 +#: __init__.py:20 msgid "change password" msgstr "alterar a senha" -#: __init__.py:22 +#: __init__.py:21 msgid "user details" msgstr "detalhes do usuário" -#: __init__.py:23 +#: __init__.py:22 msgid "edit details" msgstr "editar detalhes" -#: __init__.py:27 __init__.py:33 +#: __init__.py:26 __init__.py:31 msgid "about" msgstr "sobre" -#: __init__.py:28 -msgid "changelog" -msgstr "log de alterações" - -#: __init__.py:29 +#: __init__.py:27 msgid "license" msgstr "licença" @@ -119,15 +114,11 @@ msgstr "" msgid "function found" msgstr "função encontrada" -#: views.py:25 templates/password_change_done.html:5 -msgid "Your password has been successfully changed." -msgstr "Sua senha foi alterada com êxito." - -#: views.py:42 +#: views.py:35 msgid "No action selected." msgstr "Nenhuma ação selecionada." -#: views.py:46 +#: views.py:39 msgid "Must select at least one item." msgstr "Deve selecionar pelo menos um item." @@ -136,44 +127,53 @@ msgstr "Deve selecionar pelo menos um item." msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "%(selection)s adicionadas com sucesso a %(right_list_title)s ." -#: views.py:90 views.py:107 +#: views.py:90 views.py:114 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "Não foi possível adicionar %(selection)s para %(right_list_title)s ." -#: views.py:104 +#: views.py:111 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." -msgstr " %(selection)s adicionado com sucesso removidos %(right_list_title)s." +msgstr "" +" %(selection)s adicionado com sucesso removidos %(right_list_title)s." -#: views.py:122 +#: views.py:129 msgid "Add" msgstr "Adicionar" -#: views.py:133 +#: views.py:140 msgid "Remove" msgstr "Remover" -#: views.py:156 +#: views.py:163 msgid "current user details" msgstr "detalhes atuais do usuário" -#: views.py:173 +#: views.py:180 +msgid "E-mail conflict, another user has that same email." +msgstr "" + +#: views.py:183 msgid "Current user's details updated." msgstr "Detalhes do usuário atual atualizados." -#: views.py:182 +#: views.py:192 msgid "edit current user details" msgstr "editar os detalhes do usuário atual" -#: views.py:213 -msgid "Changelog" -msgstr "Log de alterações" - -#: views.py:226 +#: views.py:223 msgid "License" msgstr "Licença" +#: views.py:232 +msgid "Current user password change" +msgstr "" + +#: views.py:247 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." +msgstr "Sua senha foi alterada com êxito." + #: widgets.py:58 msgid "None" msgstr "Nenhum" @@ -181,12 +181,12 @@ msgstr "Nenhum" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using tempfile." -"mkdtemp()" +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" msgstr "" "Diretório temporário usado para armazenar miniaturas, previews e arquivos " -"temporários. Se nenhum for especificado, um será criado usando tempfile." -"mkdtemp()" +"temporários. Se nenhum for especificado, um será criado usando " +"tempfile.mkdtemp()" #: conf/settings.py:65 msgid "" @@ -280,12 +280,12 @@ msgid "No" msgstr "Não" #: templates/generic_form_instance.html:37 -#: templates/generic_form_subtemplate.html:52 +#: templates/generic_form_subtemplate.html:56 msgid "required" msgstr "exigido" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -293,8 +293,8 @@ msgstr "exigido" msgid "Save" msgstr "Salvar" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -302,6 +302,10 @@ msgstr "Salvar" msgid "Submit" msgstr "Submeter" +#: templates/generic_form_subtemplate.html:87 +msgid "Cancel" +msgstr "" + #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format msgid "List of %(stripped_title)s" @@ -341,8 +345,4 @@ msgstr "Login" msgid "Password change" msgstr "Alterar a senha" -#~ msgid "class found: %s" -#~ msgstr "classe encontrada: %s" -#~ msgid "Cancel" -#~ msgstr "Cancelar" diff --git a/apps/common/locale/ru/LC_MESSAGES/django.mo b/apps/common/locale/ru/LC_MESSAGES/django.mo index a8f3d3b9e8592f138c6a59e218a6810b03bf2d87..3f4e402873275d720824a874acb4342ff8a6ecb9 100644 GIT binary patch delta 1540 zcmYk+TS!zv9LMp|TrYV`&CIT=-Mr+wYu?&SrJyA3f*2Vhw1rBguB}oa;nqv{uvi2o z=|za5f@Xk+%v7(OVcT*lPkY21p>kVlLw);8WT5$DmLf>oG~>v1@F1qd8?zjbp#}`%3LHZ1WCAmA619*QsExeBRD6#uIEP%Oo>gc8 zO{nKvFoEAU2Wa^4i1WZGj&MJQ+WBU-lZ~xdiYHK^zJq0W4;AXqsD)-E+6&0Wh1}<( z##dt!HX~D;HVkXUK^ls{0BWUYP!A5Go2`!GcJ3b~8?y~v3{nId9Ctf5;sW~jVl%d5 z9X`Re7*ALd)faU+gkJ-)$QT$yI4Yzry^t*8iG zaQd%c4)?cF8=69;U>fz@hcx1^j#)aG(|kt__>CQylWzaec_g~#4(`B7)VOF4fKrlx z1jkh4YHUEI?idc^Rn&$G$cNmBOkwK6G&FGw?!$KHi^rH5Wz1_-?q)gS!i688=n$yAG5VP)OA{6(6;Ns`<1CrL2e=P1SGa>HXI(lnaGZMXzAF)v`alz?!Ug zd=qMSl~fN^rI^b3wDPMnqCcCzMSo~(otskB&P$y8e5^5=kwTP>-)h;fj?=UvqP7m< z|3$gZhy+|&W!1ElQN4&N%DxJDu#WTwB!u>hj4IjVcU`$r}cX|#5yT+d<-HaX|Nc|NT`I5CJ@-pk&A9gpCW&i*H delta 1646 zcmYk+e@vBC9LMnkasl}vLed2xdc;tOF7Vty@d`+`iKw_*t{>~KE7*TX=>}QeypW)u&WbNThl+%>EgMrHEYAw*lKf)qWG^r^8I=4L+k8*@9RA0p65L0 ze9w9AHx1Kv>|RmE2}60BC?^`zjd=<8Wbj3q^ck}ar%-(skuIhwGi9^qR$M`Q8@Awf zd;()whUZZC-SE7HEBV=cMMXhK7AHqe{ zM0`9&3(3I(EX9|x2I*qnKrQSTX7GG-f(jpVhA$gGMRoWAPvabF<*&1xQv47baSE04 zU$F`Aqf&0=rY72jn!t0&5T@I^?#DG;k6}y$zE33&&!IZbpjL1lm61EBng4|9H;-v7 z{ZH)R`mcOrc3_B`l#y}Iqn>Z!YT768Mf?bN;?gSezky0C)6|VUo)IkK`Zd(vjp0T- ziA(r3GKNVos0F^h#;3p40_J>D%tsQhzk9UR_yOE*vAbD7F7D+R`;~ z+vjh3iW;Za-7NJ`u2q!VYNCt<8 diff --git a/apps/common/locale/ru/LC_MESSAGES/django.po b/apps/common/locale/ru/LC_MESSAGES/django.po index e551ef4f57..0701d9e19b 100644 --- a/apps/common/locale/ru/LC_MESSAGES/django.po +++ b/apps/common/locale/ru/LC_MESSAGES/django.po @@ -1,46 +1,40 @@ # 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: \n" -"POT-Creation-Date: 2012-01-08 07:39-0400\n" -"PO-Revision-Date: 2011-11-22 19:21+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-02 14:17-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" "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:21 +#: __init__.py:20 msgid "change password" msgstr "Изменение пароля" -#: __init__.py:22 +#: __init__.py:21 msgid "user details" msgstr "сведения о пользователе" -#: __init__.py:23 +#: __init__.py:22 msgid "edit details" msgstr "изменение сведений" -#: __init__.py:27 __init__.py:33 +#: __init__.py:26 __init__.py:31 msgid "about" msgstr "инфо" -#: __init__.py:28 -msgid "changelog" -msgstr "изменения" - -#: __init__.py:29 +#: __init__.py:27 msgid "license" msgstr "лицензия" @@ -120,15 +114,11 @@ msgstr "" msgid "function found" msgstr "функция найдена" -#: views.py:25 templates/password_change_done.html:5 -msgid "Your password has been successfully changed." -msgstr "Ваш пароль был изменен." - -#: views.py:42 +#: views.py:35 msgid "No action selected." msgstr "Никаких действий не выбрано." -#: views.py:46 +#: views.py:39 msgid "Must select at least one item." msgstr "Необходимо выбрать хотя бы один элемент." @@ -137,44 +127,52 @@ msgstr "Необходимо выбрать хотя бы один элемен msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "%(selection)s успешно добавлен в %(right_list_title)s ." -#: views.py:90 views.py:107 +#: views.py:90 views.py:114 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "Не удалось добавить %(selection)s до %(right_list_title)s ." -#: views.py:104 +#: views.py:111 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." msgstr "%(selection)s успешно удален из %(right_list_title)s ." -#: views.py:122 +#: views.py:129 msgid "Add" msgstr "Добавить" -#: views.py:133 +#: views.py:140 msgid "Remove" msgstr "Удалить" -#: views.py:156 +#: views.py:163 msgid "current user details" msgstr "данные пользователя" -#: views.py:173 +#: views.py:180 +msgid "E-mail conflict, another user has that same email." +msgstr "" + +#: views.py:183 msgid "Current user's details updated." msgstr "Данные пользователя обновлены." -#: views.py:182 +#: views.py:192 msgid "edit current user details" msgstr "редактировать данные пользователя" -#: views.py:213 -msgid "Changelog" -msgstr "Изменения" - -#: views.py:226 +#: views.py:223 msgid "License" msgstr "Лицензия" +#: views.py:232 +msgid "Current user password change" +msgstr "" + +#: views.py:247 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." +msgstr "Ваш пароль был изменен." + #: widgets.py:58 msgid "None" msgstr "Ни один" @@ -182,8 +180,8 @@ msgstr "Ни один" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using tempfile." -"mkdtemp()" +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" msgstr "" "Временный каталог, используемый сайтом для хранения миниатюр, превью и " "временных файлов. Если он не указан, он будет создан с использованием " @@ -281,12 +279,12 @@ msgid "No" msgstr "Нет" #: templates/generic_form_instance.html:37 -#: templates/generic_form_subtemplate.html:52 +#: templates/generic_form_subtemplate.html:56 msgid "required" msgstr "требуется" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -294,8 +292,8 @@ msgstr "требуется" msgid "Save" msgstr "Сохранить" -#: templates/generic_form_subtemplate.html:76 -#: templates/generic_form_subtemplate.html:78 +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 #: templates/generic_list_horizontal_subtemplate.html:51 #: templates/generic_list_horizontal_subtemplate.html:90 #: templates/generic_list_subtemplate.html:52 @@ -303,6 +301,10 @@ msgstr "Сохранить" msgid "Submit" msgstr "Выполнить" +#: templates/generic_form_subtemplate.html:87 +msgid "Cancel" +msgstr "" + #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format msgid "List of %(stripped_title)s" @@ -315,8 +317,8 @@ msgid "" "List of %(title)s (%(start)s - %(end)s out of %(total)s) (Page " "%(page_number)s of %(total_pages)s)" msgstr "" -"Список %(title)s (%(start)s - %(end)s из %(total)s) (Page %(page_number)s из " -"%(total_pages)s)" +"Список %(title)s (%(start)s - %(end)s из %(total)s) (Page %(page_number)s из" +" %(total_pages)s)" #: templates/generic_list_horizontal_subtemplate.html:25 #: templates/generic_list_subtemplate.html:26 @@ -342,5 +344,4 @@ msgstr "Войти" msgid "Password change" msgstr "Изменение пароля" -#~ msgid "class found: %s" -#~ msgstr "класс найден: %s." + diff --git a/apps/converter/locale/en/LC_MESSAGES/django.po b/apps/converter/locale/en/LC_MESSAGES/django.po index ec3951acca..0618b2b086 100644 --- a/apps/converter/locale/en/LC_MESSAGES/django.po +++ b/apps/converter/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:10 +#: __init__.py:15 msgid "file formats" msgstr "" @@ -879,15 +879,15 @@ msgstr "" msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" msgstr "" -#: views.py:15 +#: views.py:17 msgid "suported file formats" msgstr "" -#: views.py:20 +#: views.py:22 msgid "name" msgstr "" -#: views.py:24 +#: views.py:26 msgid "description" msgstr "" diff --git a/apps/converter/locale/es/LC_MESSAGES/django.mo b/apps/converter/locale/es/LC_MESSAGES/django.mo index e0c200c67c9f68f7d13db4d933c27e8886e2c3eb..c66d22def849717549815eee3279082d30ce216b 100644 GIT binary patch literal 19258 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 AxBvhE delta 1882 zcmYM!T}+!*9LMnk<7H#8!GQ5T9$>8HrL={$Y#lG73?>8;!ZdMemK4@O6 z9C~G{f2Zt1+%D00VO(}WoMduiywD3xTy(lDBujjYCPuRxjo*JM@ua7p^E`c?bDr}% z=jr;}S^qkcKOV@rYA6HLTI%6!W6olG4qud1t}%P@4LpeNVmaQ#O8f%dxP>KHo@Y!A z+R%rCn2#4TF5@1KU&kZHB+UwqHco6{JN|+NSjk;)ViWGhTiAdbsL%EQ_v1q>!oTq_ z=5TQ%wxB-f7#_kYwBx0W?_&+)o3Cl;g}uq=ZKxd#VH2K53tvM`U=7Rg zGt>mWMNQx*EXG`BW8pz$#-=-Sd=85l-y~`1%v0#W+js!~M8Yt6?x5$bU{>VUOq zp&P?Ei7~u`nvkb(yB{Cw{o}|_<_Y9u0(>R4!!QlKA%S|~B5EQ_$g-Lh{65Q=Rpet9 z_igWmS5dE9MNR4^_TrbQ$rQ3at=NqHIDy)K3N_)C{p3$d<_0J1_yHcpZ%~uiLw-77 zKc;XD^~N92!iT62m{0E9Vv0~VX&tuUQPe$g4s}T`qb}up=*3S<$X^?OaiR^|$z5mk zB2{|UM|-a;Femu~;wi`5)IjSaYvaV7KnIyyLi7d5H8Bnzo0PN5DE z#ZF9N4{oA9xjq$RnOfvt<3yeLAnMFVP!l|h30%S}_y{%fi^QV$FQYE`HPmF2*J)^n zA7*~Ilksz8|Cz5)AM88S0Use-A)T5Itb^(rYdJ>MPPOQ@C#c%DmS(CZs^$1LI?<%* z%N%GNU75CptVnuO>W!(HEaouD(D=qqGqYtcUYSI6MdTIq#U)!D1K|>SK zWpnHMuj{2zYe`3q`aj^J>Yf;&YGfy=Z0z&~b)s%8_FuYmXWT*ejA!Q{<1W-qsYUmO zz7cggpuPbtQ~I4IUBf?cx`?x^RqmD*m-;7%t${OxBO{hS8VJqJ1+5D*P%$eXRgUi7 zTzhu&y0wsyjjBrpr$@#otk8U5CMZ8wU)!}1T9kik?D9wLA-Ph2MDEr5<(5?@OV%0r zt)Wit_f^PjW38+;UXY=t67e+IWp8tpc$!`ELi4ZkmhFUW*)6%>5|MkYajAE#+GgYN z=Y3A+Oej8^nCh60%sZozSRfjTM4j`2mjYpDC>BcuV{+S3QRH^G-Hy&q%kB1cdgXz` zvbnsL%j4j?D$)k*Lqw=}Md(mt~{lslu^9cqYMgd=_0+I@{$r zS2_~O?y8nox|U?0XY&6D#=Uhi;C-=hWPbC;OfYO|91`q)CmqDXF}sA0+a$lIO{RNB z(?OK, 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-12-06 06:17+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-02 14:17-0400\n" +"PO-Revision-Date: 2011-12-14 14:37+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:10 +#: __init__.py:15 msgid "file formats" msgstr "formatos de archivo" @@ -188,7 +189,7 @@ msgstr "Muestras crudas de cian, magenta, amarillo, negro y opacidad" #: literals.py:85 literals.py:86 msgid "Canon Digital Camera Raw Image Format" -msgstr "" +msgstr "Canon Digital Camera Raw Image Format" #: literals.py:87 msgid "Microsoft Cursor Icon" @@ -200,23 +201,23 @@ msgstr "DR Halo" #: literals.py:90 msgid "Digital Imaging and Communications in Medicine image" -msgstr "" +msgstr "Digital Imaging and Communications in Medicine image" #: literals.py:91 msgid "Kodak Digital Camera Raw Image File" -msgstr "" +msgstr "Kodak Digital Camera Raw Image File" #: literals.py:92 msgid "ZSoft IBM PC multi-page Paintbrush" -msgstr "" +msgstr "ZSoft IBM PC multi-page Paintbrush" #: literals.py:93 msgid "Microsoft DirectDraw Surface" -msgstr "" +msgstr "Microsoft DirectDraw Surface" #: literals.py:94 msgid "Multi-face font package (Freetype 2.4.2)" -msgstr "" +msgstr "Multi-face font package (Freetype 2.4.2)" #: literals.py:95 msgid "Déjà vu" @@ -232,328 +233,329 @@ msgstr "Graphviz" #: literals.py:98 msgid "SMPTE 268M-2003 (DPX 2.0)" -msgstr "" +msgstr "SMPTE 268M-2003 (DPX 2.0)" #: literals.py:100 msgid "Encapsulated Portable Document Format" -msgstr "" +msgstr "Encapsulated Portable Document Format" #: literals.py:101 literals.py:106 msgid "Adobe Encapsulated PostScript Interchange format" -msgstr "" +msgstr "Adobe Encapsulated PostScript Interchange format" #: literals.py:102 literals.py:105 msgid "Adobe Encapsulated PostScript" -msgstr "" +msgstr "Adobe Encapsulated PostScript" #: literals.py:103 msgid "Adobe Level II Encapsulated PostScript" -msgstr "" +msgstr "Adobe Level II Encapsulated PostScript" #: literals.py:104 msgid "Adobe Level III Encapsulated PostScript" -msgstr "" +msgstr "Adobe Level III Encapsulated PostScript" #: literals.py:107 msgid "Adobe Encapsulated PostScript with TIFF preview" -msgstr "" +msgstr "Adobe Encapsulated PostScript with TIFF preview" #: literals.py:108 msgid "Adobe Level II Encapsulated PostScript with TIFF preview" -msgstr "" +msgstr "Adobe Level II Encapsulated PostScript with TIFF preview" #: literals.py:109 msgid "Adobe Level III Encapsulated PostScript with TIFF preview" -msgstr "" +msgstr "Adobe Level III Encapsulated PostScript with TIFF preview" #: literals.py:110 msgid "Epson RAW Format" -msgstr "" +msgstr "Epson RAW Format" #: literals.py:111 msgid "Exif digital camera binary data" -msgstr "" +msgstr "Exif digital camera binary data" #: literals.py:112 msgid "High Dynamic-range (HDR)" -msgstr "" +msgstr "High Dynamic-range (HDR)" #: literals.py:114 msgid "Group 3 FAX (Not TIFF Group3 FAX)" -msgstr "" +msgstr "Group 3 FAX (Not TIFF Group3 FAX)" #: literals.py:115 msgid "Autodesk FLI animations file" -msgstr "" +msgstr "Autodesk FLI animations file" #: literals.py:116 msgid "Autodesk FLC animations file" -msgstr "" +msgstr "Autodesk FLC animations file" #: literals.py:117 literals.py:120 msgid "Flexible Image Transport System" -msgstr "" +msgstr "Flexible Image Transport System" #: literals.py:118 msgid "Kodak FlashPix file" -msgstr "" +msgstr "Kodak FlashPix file" #: literals.py:119 literals.py:225 msgid "Plasma fractal image" -msgstr "" +msgstr "Plasma fractal image" #: literals.py:122 msgid "Raw green samples" -msgstr "" +msgstr "Raw green samples" #: literals.py:123 msgid "Group 3 FAX" -msgstr "" +msgstr "Group 3 FAX" #: literals.py:124 msgid "Raw green, blue, and red samples" -msgstr "" +msgstr "Raw green, blue, and red samples" #: literals.py:125 msgid "GIMP brush file" -msgstr "" +msgstr "GIMP brush file" #: literals.py:126 msgid "CompuServe graphics interchange format (version 89a)" -msgstr "" +msgstr "CompuServe graphics interchange format (version 89a)" #: literals.py:127 msgid "CompuServe graphics interchange format (version 87a)" -msgstr "" +msgstr "CompuServe graphics interchange format (version 87a)" #: literals.py:128 msgid "Gradual passing from one shade to another" -msgstr "" +msgstr "Gradual passing from one shade to another" #: literals.py:129 msgid "Raw gray samples" -msgstr "" +msgstr "Raw gray samples" #: literals.py:130 msgid "Raw green, red, and blue samples" -msgstr "" +msgstr "Raw green, red, and blue samples" #: literals.py:131 msgid "Raw CCITT Group4" -msgstr "" +msgstr "Raw CCITT Group4" #: literals.py:133 msgid "Histogram of the image" -msgstr "" +msgstr "Histogram of the image" #: literals.py:134 msgid "HRZ: Slow scan TV" -msgstr "" +msgstr "HRZ: Slow scan TV" #: literals.py:135 literals.py:136 literals.py:255 msgid "Hypertext Markup Language and a client-side image map" -msgstr "" +msgstr "Hypertext Markup Language and a client-side image map" #: literals.py:138 literals.py:264 literals.py:279 literals.py:283 msgid "Truevision Targa image" -msgstr "" +msgstr "Truevision Targa image" #: literals.py:139 literals.py:140 msgid "ICC Color Profile" -msgstr "" +msgstr "ICC Color Profile" #: literals.py:141 literals.py:142 msgid "Microsoft Icon" -msgstr "" +msgstr "Microsoft Icon" #: literals.py:143 msgid "Hald CLUT identity image" -msgstr "" +msgstr "Hald CLUT identity image" #: literals.py:144 msgid "LabEye image format" -msgstr "" +msgstr "LabEye image format" #: literals.py:145 msgid "GraphicsMagick Embedded Image" -msgstr "" +msgstr "GraphicsMagick Embedded Image" #: literals.py:146 msgid "The image format and characteristics" -msgstr "" +msgstr "The image format and characteristics" #: literals.py:147 msgid "Base64-encoded inline images" -msgstr "" +msgstr "Base64-encoded inline images" #: literals.py:148 msgid "IPL Image Sequence" -msgstr "" +msgstr "IPL Image Sequence" #: literals.py:149 msgid "IPTC Newsphoto" -msgstr "" +msgstr "IPTC Newsphoto" #: literals.py:150 literals.py:151 msgid "IPTC Newsphoto text format" -msgstr "" +msgstr "IPTC Newsphoto text format" #: literals.py:152 msgid "ISO/TR 11548-1 format" -msgstr "" +msgstr "ISO/TR 11548-1 format" #: literals.py:154 literals.py:157 msgid "JPEG-2000 Code Stream Syntax" -msgstr "" +msgstr "JPEG-2000 Code Stream Syntax" #: literals.py:155 msgid "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" -msgstr "" +msgstr "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:156 msgid "JPEG-2000 JP2 File Format Syntax" -msgstr "" +msgstr "JPEG-2000 JP2 File Format Syntax" #: literals.py:158 literals.py:159 msgid "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" -msgstr "" +msgstr "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" #: literals.py:160 msgid "JPEG-2000 File Format Syntax" -msgstr "" +msgstr "JPEG-2000 File Format Syntax" #: literals.py:162 msgid "Raw black samples" -msgstr "" +msgstr "Raw black samples" #: literals.py:163 literals.py:164 msgid "Kodak Digital Camera Raw Image Format" -msgstr "" +msgstr "Kodak Digital Camera Raw Image Format" #: literals.py:166 msgid "Image label" -msgstr "" +msgstr "Image label" #: literals.py:168 msgid "Raw magenta samples" -msgstr "" +msgstr "Raw magenta samples" #: literals.py:169 literals.py:179 literals.py:182 literals.py:183 msgid "MPEG Video Stream" -msgstr "" +msgstr "MPEG Video Stream" #: literals.py:170 msgid "Raw MPEG-4 Video" -msgstr "" +msgstr "Raw MPEG-4 Video" #: literals.py:171 msgid "Colormap intensities and indices" -msgstr "" +msgstr "Colormap intensities and indices" #: literals.py:172 msgid "MATLAB image format" -msgstr "" +msgstr "MATLAB image format" #: literals.py:173 msgid "MATTE raw opacity format" -msgstr "" +msgstr "MATTE raw opacity format" #: literals.py:174 msgid "8-bit McIdas area file" -msgstr "" +msgstr "8-bit McIdas area file" #: literals.py:175 msgid "Microsoft Image Composer (MIC) file" -msgstr "" +msgstr "Microsoft Image Composer (MIC) file" #: literals.py:176 msgid "Magick Image File Format" -msgstr "" +msgstr "Magick Image File Format" #: literals.py:177 msgid "" "Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" msgstr "" +"Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:178 msgid "Raw Bi-level bitmap in least-significant-byte first order" -msgstr "" +msgstr "Raw Bi-level bitmap in least-significant-byte first order" #: literals.py:180 msgid "MPEG-4 Video Stream" -msgstr "" +msgstr "MPEG-4 Video Stream" #: literals.py:184 msgid "Sony (Minolta) Raw Image File" -msgstr "" +msgstr "Sony (Minolta) Raw Image File" #: literals.py:185 msgid "Magick Scripting Language" -msgstr "" +msgstr "Magick Scripting Language" #: literals.py:186 msgid "Windows 1 and 2 MSP file format" -msgstr "" +msgstr "Windows 1 and 2 MSP file format" #: literals.py:187 msgid "ImageMagick's own SVG internal renderer" -msgstr "" +msgstr "ImageMagick's own SVG internal renderer" #: literals.py:188 msgid "MTV Raytracing image format" -msgstr "" +msgstr "MTV Raytracing image format" #: literals.py:189 msgid "Magick Vector Graphics" -msgstr "" +msgstr "Magick Vector Graphics" #: literals.py:191 msgid "Nikon Digital SLR Camera Raw Image File" -msgstr "" +msgstr "Nikon Digital SLR Camera Raw Image File" #: literals.py:192 msgid "Constant image of uniform color" -msgstr "" +msgstr "Constant image of uniform color" #: literals.py:194 msgid "Raw opacity samples" -msgstr "" +msgstr "Raw opacity samples" #: literals.py:195 msgid "Olympus Digital Camera Raw Image File" -msgstr "" +msgstr "Olympus Digital Camera Raw Image File" #: literals.py:196 msgid "On-the-air bitmap" -msgstr "" +msgstr "On-the-air bitmap" #: literals.py:197 msgid "Open Type font (Freetype 2.4.2)" -msgstr "" +msgstr "Open Type font (Freetype 2.4.2)" #: literals.py:199 msgid "Xv thumbnail format" -msgstr "" +msgstr "Xv thumbnail format" #: literals.py:200 literals.py:277 msgid "16bit/pixel interleaved YUV" -msgstr "" +msgstr "16bit/pixel interleaved YUV" #: literals.py:201 msgid "Palm pixmap" -msgstr "" +msgstr "Palm pixmap" #: literals.py:202 msgid "Common 2-dimensional bitmap format" -msgstr "" +msgstr "Common 2-dimensional bitmap format" #: literals.py:203 msgid "Predefined pattern" -msgstr "" +msgstr "Predefined pattern" #: literals.py:204 msgid "Portable bitmap format (black and white)" -msgstr "" +msgstr "Portable bitmap format (black and white)" #: literals.py:205 literals.py:206 msgid "Photo CD" @@ -565,15 +567,15 @@ msgstr "Page Control Language" #: literals.py:208 literals.py:221 msgid "Apple Macintosh QuickDraw/PICT" -msgstr "" +msgstr "Apple Macintosh QuickDraw/PICT" #: literals.py:209 msgid "ZSoft IBM PC Paintbrush" -msgstr "" +msgstr "ZSoft IBM PC Paintbrush" #: literals.py:210 msgid "Palm Database ImageViewer Format" -msgstr "" +msgstr "Palm Database ImageViewer Format" #: literals.py:211 msgid "Portable Document Format" @@ -585,268 +587,273 @@ msgstr "Format portatil de archivo de documento" #: literals.py:213 msgid "Pentax Electronic File" -msgstr "" +msgstr "Pentax Electronic File" #: literals.py:214 msgid "Embrid Embroidery Format" -msgstr "" +msgstr "Embrid Embroidery Format" #: literals.py:215 msgid "Postscript Type 1 font (ASCII) (Freetype 2.4.2)" -msgstr "" +msgstr "Postscript Type 1 font (ASCII) (Freetype 2.4.2)" #: literals.py:216 msgid "Postscript Type 1 font (binary) (Freetype 2.4.2)" -msgstr "" +msgstr "Postscript Type 1 font (binary) (Freetype 2.4.2)" #: literals.py:217 msgid "Portable float format" -msgstr "" +msgstr "Portable float format" #: literals.py:218 msgid "Portable graymap format (gray scale)" -msgstr "" +msgstr "Portable graymap format (gray scale)" #: literals.py:219 msgid "JPEG-2000 VM Format" -msgstr "" +msgstr "JPEG-2000 VM Format" #: literals.py:220 msgid "Personal Icon" -msgstr "" +msgstr "Personal Icon" #: literals.py:222 msgid "Alias/Wavefront RLE image format" -msgstr "" +msgstr "Alias/Wavefront RLE image format" #: literals.py:223 msgid "PIXAR raster file" -msgstr "" +msgstr "PIXAR raster file" #: literals.py:224 msgid "Joint Photographic Experts Group JFIF format (62)" -msgstr "" +msgstr "Joint Photographic Experts Group JFIF format (62)" #: literals.py:226 msgid "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" -msgstr "" +msgstr "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:227 msgid "" "24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" msgstr "" +"24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:228 msgid "" "32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " "1.2.3.3,1.2.3.4)" msgstr "" +"32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" #: literals.py:229 msgid "" "8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " "1.2.3.3,1.2.3.4)" msgstr "" +"8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" #: literals.py:230 msgid "Portable anymap" -msgstr "" +msgstr "Portable anymap" #: literals.py:231 msgid "Portable pixmap format (color)" -msgstr "" +msgstr "Portable pixmap format (color)" #: literals.py:232 msgid "Show a preview an image enhancement, effect, or f/x" -msgstr "" +msgstr "Show a preview an image enhancement, effect, or f/x" #: literals.py:233 msgid "Adobe PostScript" -msgstr "" +msgstr "Adobe PostScript" #: literals.py:234 msgid "Adobe Level II PostScript" -msgstr "" +msgstr "Adobe Level II PostScript" #: literals.py:235 msgid "Adobe Level III PostScript" -msgstr "" +msgstr "Adobe Level III PostScript" #: literals.py:236 msgid "Adobe Large Document Format" -msgstr "" +msgstr "Adobe Large Document Format" #: literals.py:237 msgid "Adobe Photoshop bitmap" -msgstr "" +msgstr "Adobe Photoshop bitmap" #: literals.py:238 msgid "Pyramid encoded TIFF" -msgstr "" +msgstr "Pyramid encoded TIFF" #: literals.py:239 literals.py:253 msgid "Seattle Film Works" -msgstr "" +msgstr "Seattle Film Works" #: literals.py:241 msgid "Raw red samples" -msgstr "" +msgstr "Raw red samples" #: literals.py:242 msgid "Fuji CCD-RAW Graphic File" -msgstr "" +msgstr "Fuji CCD-RAW Graphic File" #: literals.py:243 literals.py:259 msgid "SUN Rasterfile" -msgstr "" +msgstr "SUN Rasterfile" #: literals.py:244 msgid "Raw red, blue, and green samples" -msgstr "" +msgstr "Raw red, blue, and green samples" #: literals.py:245 msgid "Raw red, green, and blue samples" -msgstr "" +msgstr "Raw red, green, and blue samples" #: literals.py:246 msgid "Raw red, green, blue, and matte samples" -msgstr "" +msgstr "Raw red, green, blue, and matte samples" #: literals.py:247 msgid "Raw red, green, blue, and opacity samples" -msgstr "" +msgstr "Raw red, green, blue, and opacity samples" #: literals.py:248 msgid "Alias/Wavefront image" -msgstr "" +msgstr "Alias/Wavefront image" #: literals.py:249 msgid "Utah Run length encoded image" -msgstr "" +msgstr "Utah Run length encoded image" #: literals.py:251 msgid "ZX-Spectrum SCREEN$" -msgstr "" +msgstr "ZX-Spectrum SCREEN$" #: literals.py:252 msgid "Scitex HandShake" -msgstr "" +msgstr "Scitex HandShake" #: literals.py:254 msgid "Irix RGB image" -msgstr "" +msgstr "Irix RGB image" #: literals.py:256 msgid "Sony Raw Format 2" -msgstr "" +msgstr "Sony Raw Format 2" #: literals.py:257 msgid "Sony Raw Format" -msgstr "" +msgstr "Sony Raw Format" #: literals.py:258 msgid "Steganographic image" -msgstr "" +msgstr "Steganographic image" #: literals.py:260 msgid "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" -msgstr "" +msgstr "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" #: literals.py:261 msgid "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" -msgstr "" +msgstr "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" #: literals.py:263 literals.py:273 msgid "Text" -msgstr "" +msgstr "Text" #: literals.py:265 msgid "EXIF Profile Thumbnail" -msgstr "" +msgstr "EXIF Profile Thumbnail" #: literals.py:266 msgid "Tagged Image File Format (LIBTIFF, Version 3.9.4)" -msgstr "" +msgstr "Tagged Image File Format (LIBTIFF, Version 3.9.4)" #: literals.py:267 msgid "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" -msgstr "" +msgstr "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" #: literals.py:268 msgid "Tile image with a texture" -msgstr "" +msgstr "Tile image with a texture" #: literals.py:269 msgid "PSX TIM" -msgstr "" +msgstr "PSX TIM" #: literals.py:270 msgid "TOPOL X Image" -msgstr "" +msgstr "TOPOL X Image" #: literals.py:271 msgid "TrueType font collection (Freetype 2.4.2)" -msgstr "" +msgstr "TrueType font collection (Freetype 2.4.2)" #: literals.py:272 msgid "TrueType font (Freetype 2.4.2)" -msgstr "" +msgstr "TrueType font (Freetype 2.4.2)" #: literals.py:275 msgid "Unicode Text format" -msgstr "" +msgstr "Unicode Text format" #: literals.py:276 msgid "X-Motif UIL table" -msgstr "" +msgstr "X-Motif UIL table" #: literals.py:280 msgid "VICAR rasterfile format" -msgstr "" +msgstr "VICAR rasterfile format" #: literals.py:281 msgid "Visual Image Directory" -msgstr "" +msgstr "Visual Image Directory" #: literals.py:282 literals.py:299 msgid "Khoros Visualization image" -msgstr "" +msgstr "Khoros Visualization image" #: literals.py:285 msgid "Wireless Bitmap (level 0) image" -msgstr "" +msgstr "Wireless Bitmap (level 0) image" #: literals.py:286 msgid "Windows Meta File" -msgstr "" +msgstr "Windows Meta File" #: literals.py:287 msgid "Word Perfect Graphics" -msgstr "" +msgstr "Word Perfect Graphics" #: literals.py:288 msgid "Windows Media Video" -msgstr "" +msgstr "Windows Media Video" #: literals.py:289 msgid "Compressed Windows Meta File" -msgstr "" +msgstr "Compressed Windows Meta File" #: literals.py:291 msgid "X Window System" -msgstr "" +msgstr "X Window System" #: literals.py:292 msgid "Foveon X3 (Sigma/Polaroid) Raw picture file" -msgstr "" +msgstr "Foveon X3 (Sigma/Polaroid) Raw picture file" #: literals.py:293 msgid "X Windows system bitmap (black and white)" -msgstr "" +msgstr "X Windows system bitmap (black and white)" #: literals.py:294 msgid "Constant image uniform color" -msgstr "" +msgstr "Constant image uniform color" #: literals.py:295 msgid "GIMP image" @@ -854,23 +861,23 @@ msgstr "Imágen GIMP" #: literals.py:296 msgid "Adobe XML metadata" -msgstr "" +msgstr "Adobe XML metadata" #: literals.py:297 msgid "X Windows system pixmap (color)" -msgstr "" +msgstr "X Windows system pixmap (color)" #: literals.py:298 msgid "Microsoft XML Paper Specification" -msgstr "" +msgstr "Microsoft XML Paper Specification" #: literals.py:300 msgid "XV thumbnail file" -msgstr "" +msgstr "XV thumbnail file" #: literals.py:301 msgid "X Windows system window dump (color)" -msgstr "" +msgstr "X Windows system window dump (color)" #: literals.py:303 msgid "Raw yellow samples" @@ -878,17 +885,17 @@ msgstr "Muestras crudas de amarillo" #: literals.py:304 msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" -msgstr "" +msgstr "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" -#: views.py:15 +#: views.py:17 msgid "suported file formats" msgstr "formatos de archivos apoyados" -#: views.py:20 +#: views.py:22 msgid "name" msgstr "nombre" -#: views.py:24 +#: views.py:26 msgid "description" msgstr "descripción" @@ -906,13 +913,11 @@ msgstr "Ruta de archivo al programa imagemagick." #: conf/settings.py:15 msgid "" -"Graphics conversion backend to use. Options are: " -"converter.backends.imagemagick, converter.backends.graphicsmagick and " -"converter.backends.python." +"Graphics conversion backend to use. Options are: converter.backends." +"imagemagick, converter.backends.graphicsmagick and converter.backends.python." msgstr "" -"Manejador de conversión a usarse. Opciones son: " -"converter.backends.imagemagick, converter.backends.graphicsmagick y " -"converter.backends.python." +"Manejador de conversión a usarse. Opciones son: converter.backends." +"imagemagick, converter.backends.graphicsmagick y converter.backends.python." #: conf/settings.py:16 msgid "Path to the unoconv program." @@ -920,11 +925,11 @@ msgstr "Ruta de acceso al programa de unoconv." #: conf/settings.py:17 msgid "" -"Use alternate method of connection to LibreOffice using a pipe, it is slower" -" but less prone to segmentation faults." +"Use alternate method of connection to LibreOffice using a pipe, it is slower " +"but less prone to segmentation faults." msgstr "" -"Utilizar el método alternativo de conexión a LibreOffice con un tubo, es más" -" lento pero menos propensos a fallos de segmentación." +"Utilizar el método alternativo de conexión a LibreOffice con un tubo, es más " +"lento pero menos propensos a fallos de segmentación." #: templates/converter_file_formats_help.html:3 msgid "Help" @@ -938,5 +943,3 @@ msgid "" msgstr "" "Estos son los formatos de archivo apoyados por el servidor del convertidor " "seleccionado. En este caso: '%(backend)s'" - - diff --git a/apps/converter/locale/it/LC_MESSAGES/django.mo b/apps/converter/locale/it/LC_MESSAGES/django.mo index 8c019894646f24a17d0b11e0f11c9cec637fa4a8..c0fe6b694140bc2782f97d97ad86d83a0f9fd37a 100644 GIT binary patch delta 1897 zcmXZcdq~x19LMpm&C;wawNqX)k9yjaJb8|mmUc1i;<2_SYvk5tNr@zpG;Glp{3`mR zKZJ_1=<-KKMNpA+BQ{vjk|;;eXrpKnEr`-um%-@5X73Nb2Y#H_^E|)b?|Ht@_xt?L z)xB|t_QrJ;C3q*}%yxv$vdk=6Y*ve(Vmrnyj@MtKaPSj4XV-DU$1@s2FY;+luVjb%KTAYaO zs8n9Yk@y=X;a~3lb39BxquejmB~)N{P^I*GX=vi7s7wr_K#D9IHC~2;vB8b6K-GLB zDzFaJdp($ny_k$IQKcNf0A^BO1sK5*ScL@O*=IDA>aS5RZo_KajVi?*=PL}-PbSZ4 zSd1JOt3fW?z)vQ2VLtYtGW!Dce4x^|&^ZIsS>NhuXa_Cs#%9c-zYEjxG^*C!n1Ovb z2IHrjqp%{|gVdhAL4Ib-w_0mMT3OIxJse6jvi_ z+dfo;_fRkNA^+0$A1VVA=lX%fP=U3eGV(ntbM2@acOoBvokh*xhl6n(^;6(p9*yNR z>M$QqqEh!OYDfL3LlcVb`U-BMO7aIL;3JIJ zhu%*kk%5<}iQnQ-OgTR-d3#PM>GMU4!!_SFHMXs3T^F9y*w$1LEQv%*!Vz7;=;VrM f`JTi{KM!BnxUP9aV>7qcwC(AhwDf$qIFR)LWC`Gn delta 1916 zcmXZceQ1?s7{~EzIonH4x1-z6Hs_vAotd5;pQBTET;-*;UC<+v9sFzZ`j^JrXQpa~yfCB_rs2J5kyehMQvfFABgZEzB2;V90; zo6d(ArC+)@9B;rm^f%yKOrrumv^X#;q45m^%D_*kg&v>+i!2HIN#tW&oFAbUyo@^8 zZA@ZOqgfudV?K5uQ??Zg@MBcw4x<7*7tl~d90hU>K9aCkMRFe=28$XT#U*@0u|Y6H{OYp=?89nKWd@R zP=Sr2o}0i3=2FM0SdJ=XJ(gk%D!?sRggr~LV(}m6JJLiaV&9X^S_JEuQQ=GotxX=vhQ+=%a^GI9-dg1=D# z);$x}ehDhT7f|DA)TMg|708F^;W1Q=FJm=c!7{vqD#2sVl7C%>Vj3P+pf*mTUXL!E zff+ad1u7%oVjKR3s_Fcd;Q^XZ0d%1OshQPjG3Q6;QyA^+OIZwcT3Hq=}2 z7HWLN^-ns_qfRo8I{9r>01vSi^SLVFE;PY_$3X6? z(7C7x+fb?AhFa)VH~*gV6e?rmI3NE+y#MnH!G;~?sKpzhv zvDg?YLR%9)P=fqR+Z0899#1TozU1apXm?>!|fhsM};*g$g`aN28O* zZk&x*QK`F+I#Fb8cxjqZwcU)LU@t0=N$tGrSc|$`O<02+s0^l2f$ekShfwQ$g#;eh z_cXN8&+Z40uM2Bfk9u%}vlF#oKWf8wu?~;8@r#&C{|DE5Rg!-&4-41p z_Y^lmBcFkC)WRMX;PPzK)O|Jcb_@-rlks>@@6e9nu7+3ocf|+#2U7#R{R8n`sn=3{ z@!r9~;qJlASggFrkNJKqk??#!nOK^+6}y-@+pw*0W2&!bIMvgg^s, 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" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2011-12-09 14:53+0000\n" "Last-Translator: Pierpaolo Baldan \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:10 +#: __init__.py:15 msgid "file formats" msgstr "formato file" @@ -630,8 +631,7 @@ msgstr "Joint Photographic Experts Group JFIF format (62)" #: literals.py:226 msgid "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" -msgstr "" -"Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:227 msgid "" @@ -887,15 +887,15 @@ msgstr "Raw yellow samples" msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" msgstr "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" -#: views.py:15 +#: views.py:17 msgid "suported file formats" msgstr "formato file supportati" -#: views.py:20 +#: views.py:22 msgid "name" msgstr "nome" -#: views.py:24 +#: views.py:26 msgid "description" msgstr "descrizione" @@ -913,13 +913,12 @@ msgstr "File path per il progarmma " #: conf/settings.py:15 msgid "" -"Graphics conversion backend to use. Options are: " -"converter.backends.imagemagick, converter.backends.graphicsmagick and " -"converter.backends.python." +"Graphics conversion backend to use. Options are: converter.backends." +"imagemagick, converter.backends.graphicsmagick and converter.backends.python." msgstr "" -"Backend da usare per la conversione grafica. Le opzioni sono: " -"converter.backends.imagemagick, converter.backends.graphicsmagick e " -"converter.backends.python." +"Backend da usare per la conversione grafica. Le opzioni sono: converter." +"backends.imagemagick, converter.backends.graphicsmagick e converter.backends." +"python." #: conf/settings.py:16 msgid "Path to the unoconv program." @@ -927,8 +926,8 @@ msgstr "Path per il programma unoconv" #: conf/settings.py:17 msgid "" -"Use alternate method of connection to LibreOffice using a pipe, it is slower" -" but less prone to segmentation faults." +"Use alternate method of connection to LibreOffice using a pipe, it is slower " +"but less prone to segmentation faults." msgstr "" "Utilizzare il metodo alternativo di collegamento a LibreOffice utilizzando " "questo collegamento, è più lento ma meno soggetto a errori di segmentazione." @@ -945,5 +944,3 @@ msgid "" msgstr "" "Questi sono il formati file supportati dal backend selezionato.In questo " "caso : '%(backend)s'" - - diff --git a/apps/converter/locale/pt/LC_MESSAGES/django.mo b/apps/converter/locale/pt/LC_MESSAGES/django.mo index 5b966ac130c7e44a570c346aa8acd778deee3bfd..79dcb617691902cfd0059f8c2284789243638d1c 100644 GIT binary patch delta 1914 zcmXZcZ%EZw9LMpmwRGMxSFX~$dVi^vE46!X{?D5ITWUe9dJv6*Ygi=ag{yla*)PJ1 z4SNvgR#XESMQx1!NKy3nNfcCDK^YVTNz@pN7NZ(t5BC0Wesb}3&iS3+Ip6dBo_qTT z(vA$Ioe5|7=hDm`mzm|8*|!yDO?U#o#5Xt<7tb?WkLz&)o<)sc!vcJSQT!YESP7je zxDK^$JI=zrSc|`49=?p4Z?kDw%&ZPdaXPl5Ht5Aq@F3>karE#KYJ(?Oh<{-iv*XS( z%%$Iq3a}MRa2L+R<5+`t;=Y?WcD{==jHNuN#Uf0g7Vg7J910vkkN$WD^}G!0u^BV4 z4>PeJtMI#^e;0MI5mbP$eHwFUq%&(0#!&sGNRZZv%FGZhz^53&Y1L+Pu?CgO&6th7 zI3D+-PI?%B!0V_?Y~t7-;||n3e-DirG!CEw7)C{QGZ=q{^*^WBFAS%GisM_Dde0&{@ zXD)J=E*}+0F?v{ss__O?z*|rm?nT{!e)P5AAPog@9=X`|3{~UFpSy)-qcYKiUtj`N z%af>+Ttsa=iptbKScnCU?)RVp`N~@dYThx_`ooRnpYqvl2J}52v)G+12i2d4ld%ya zxHjl_p)#@;wc#ODAXibTeua83#6{w_%?glvY%Qqq-KbIzF7aKBPBEZb-9tt87FFx? zr7m?I>Uj+o;a8|jyA$<`cLH^?5zN9rQK|kH_3g=A<~Ghoty_e8-r&=S(O8M>X}zeE z-#|tB06C1kzyh4L+}(*~s1mfJGSPzyydM?75OTroG-~}na2$rIUkMgrC;BUBD76<* zH5);t@*V2ZL{_-kSEB-0jni;D>iHhj`$thJy@CqpelR|Y%FLK17jQ0W{ZiyT-`3Dj zL@CsZ-v^#TEqEEV;cuwazY4}f&1N6bFGQWZ7T_3=^j@BlddJ|c7 z3I1pWMZ_(HSeHn|ChiISgG8bcL=BD{woe2e_GJUV$e6SZ$6 zj>b(m5szR1pM=b{F*H6iP=kT6*^jswbwC`ma4Y8EK6LOb>VW%LjIXf}E#g^(`E;YG z02kv(+<>ESAO3>ZBCa>_Uj`Iu#?NMDSdOK*2(@twR%3^6H#+qH^S>AIF-kv*Y1o44 z*oNbAo8P~Vx>z?Vz?UwK3L3qbjit<1zZ!|jenn-b18eaCmf*k%W@E7omC7YJ6yrD; zH=}O46OZ6UR3;X1?SZ%+HP3COF@nYxQ~)PYkzMh}A7X#{pZ)P(%%z{jL)POc)VkkL zf&7k{*nxV=W0;56Pys&jeS@rX?F$XnKq}YN!b+TmwW!o@_C16S{i~RR&oGRiP^mBB zA04;?f5H}22D(u5Z~FH5zQcUZw>}!WK`!~##L=i)h+;l2MHNp11GpE5;dxYz+(q5+ zJu2YusEZWTd4W`*=FLYv?FKBz!#INT?H&yk-Fs}n>`7imR-tatjtcM`>g{h}0lxId zzoCk5$Yd{&Ty*GHpx$^MD&S?Pz~ZPHXhT;Uw$o4mr;viShp0F1H^tj1AC-w3oP~=} zZ`p;q$r)4zdQh4AfW??u@BM!eM1JA65;boRYX6h<E8D;ET!LoD%u2A;eOQ3x-kP^pi=!2_3QbDI@o4-`{tm&2VELr8g*`qdSp?QhOTp zX5FY%{)4)C)@<+X$DjhJ$KkjN^}Q9fem5$mf1v`p?T`1MGV>J`aQYl?{{XViwdphz z(Q4Gf?Y;+58=gZQcng*Kr~Y^!rqUle*SmQx>W1a0s;@$=uf+kl05yLpreh-(Yi5i_ z8Uue`4rC50>6{l#PYp*S6FNgdrzTYGghJ6s_1F-91~oJ#HwKq9H^r0dnl>hyqfTsn btT~y8ClgK0v7}SCCe}L6AG&-X*st(^!nWZ@ diff --git a/apps/converter/locale/pt/LC_MESSAGES/django.po b/apps/converter/locale/pt/LC_MESSAGES/django.po index 47d15e7686..c7020773ea 100644 --- a/apps/converter/locale/pt/LC_MESSAGES/django.po +++ b/apps/converter/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-04 00:24+0000\n" -"Last-Translator: emersonsoares \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2011-11-22 15:26+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,7 +20,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:10 +#: __init__.py:15 msgid "file formats" msgstr "formatos de arquivo" @@ -888,15 +888,15 @@ msgstr "Amostras Raw amarelas" msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" msgstr "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" -#: views.py:15 +#: views.py:17 msgid "suported file formats" msgstr "formatos de arquivo suportados" -#: views.py:20 +#: views.py:22 msgid "name" msgstr "nome" -#: views.py:24 +#: views.py:26 msgid "description" msgstr "descrição" @@ -921,9 +921,8 @@ msgstr "" "imagemagick, converter.backends.graphicsmagick and converter.backends.python." #: conf/settings.py:16 -#, fuzzy msgid "Path to the unoconv program." -msgstr "Caminho do arquivo para o programa imagemagick converter." +msgstr "" #: conf/settings.py:17 msgid "" diff --git a/apps/converter/locale/ru/LC_MESSAGES/django.mo b/apps/converter/locale/ru/LC_MESSAGES/django.mo index 86540df866bc54e3259e71f37d445290ce4fd12e..3b20cd936ab9ddc93d6efa858f62e324b4e794b9 100644 GIT binary patch delta 1914 zcmXZde`u9e9LMqRa%}5%o4xy_~by1O4aS5EJy+4RcFmPw^>&C6!Wg8ibX zcw$ItWd0aYTbddEp$<{dVzp2#q(Ew#;2#m%jG#yx{@Vin)=+R$?3vefDfe(2Jhb+=sL9Lwo{H;Dh)FYGaeA0CW7uf{3E1ovuMGya|=6eoW#SY{q-;dfhU! z#q`@zseBu!<1mKs6jtFE_zm7d9o1nL&BL!zN9lh@qm0HlDiimx5T|h-8ZW^xHlfDX zBjsY-kxkek)O|mocKi$G<6YEI{)-WuOL`Pw40Yry0)5NS;5cj_>c&f`onA$ye)i*m z)#%aRfU~g+DH|I=rrLR&hm-gShRD0lI*yv(?(B5FiG|dk9iX8doOBn)u$cb%{Rw7& zqlzbcMUd($oI}3_RU%vXHkJ%L>1}pxCkF;3S5k3Jm1>gKtHDFA4R3; z4r&JlD}w+VF-kv$3UHSj--9Z;VN@WW<6Im?o$*!FdcUFq&t7HrFczb)VyL1~gf%!H zQ>e&yVgc?)509g2;4(gmH&JI=o(y(Wj|yNbDr3E<^@dR2g;C@aVSl=QQ8W4116nz7 z>cqC9-hz)&<0oDJ0_upyQ9GY-{V8{SdP@+Xhx*VYUB45x-d0|8XFqDE@44&4&M~~7TGZ>7y(V}I;#fvMiORsssG1l+%|D3B_*cHWa2-|6 zw~>p^dBm7Gu8%YT#kA>YEkQVp}r5FAxSWQ zgvM($CQ%V}@((}}51@8*3{^B&uo7?M6oy)ZK=RfF#a4lu*Mw1g4wb<^RA77E_$R0u z8AAg1?HY|m3{1EQq4h!WJc_!p&6!3m*n_I>cX0t8b>rWnGIay>8vcb!c@D3XG8sYD zP6dXs8FMt!Mne-fVFP9`jGvxcp1(V~F!Xd=d#t59lkVN|YFBJ^x;NA4)l?^HV%7S2 ziMqzbvcbIg%J8$9?vBjs-r8L|deeic__lB=-PO^T?qGg*-{9%^i{~OszbyS9XT#-% delta 1923 zcmXZce@vBC9LMqRrA(X4(7WbGEztI_EskbDs14 zp6_|yIT)Be7&zWA-wPC&Xan%PS+v-|KZd=TewDfTp(ZNqJN3!XrYpT-bgKz{ZI ze>`H<&1Oq*3u@j3*5DZ4h412WyxeS_)zY}eKnK>YGFyRh)C-=)TQQG|@J$TkNz@Bw zupEEGGF;f=TaTsmH@NR*4@h%MF z4mbWdQZBX+3Ccb|J@+#z;(xFR7m^NbWf?BPcGLpzM{W5dzMhTIU_0y>>cLB>NUxw$ z+p@;@0Swb0!Q1cvQZ_b$+-eta1s0R9jBoP&bbS-xRUza5>}sxD6PND+&8nuw`QAK*gJ!W-S<=ljoyx%fzU>rBo zKZ8n9u-lKI6}7>(`2-KdrC$Hn+QhVe^OZCu7a{13IKy*++pTTu(xi#l$vpyvA+^<9`jJ`uKn{Z+qX z9r@P_5)4o`wik5@K0=M3bN%m78JI&w9=O-hCH*)m123X#Vghyl2~@_v z@!W+!QPo^PUJ24#QIS1~I#xNro4-+vpctAL_mxSbO90-O8?>oG!qBkIAV^Lf;Sc~o^D#wtAH#(zL%>TlFBEaWID z, 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" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2011-11-22 19:01+0000\n" -"Last-Translator: gsv70 \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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" -"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:10 +#: __init__.py:15 msgid "file formats" msgstr "форматы файлов" @@ -630,8 +632,7 @@ msgstr "Joint Photographic Experts Group JFIF format (62)" #: literals.py:226 msgid "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" -msgstr "" -"Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" #: literals.py:227 msgid "" @@ -887,15 +888,15 @@ msgstr "Raw yellow samples" msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" msgstr "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" -#: views.py:15 +#: views.py:17 msgid "suported file formats" msgstr "поддерживаемые форматы файлов" -#: views.py:20 +#: views.py:22 msgid "name" msgstr "имя" -#: views.py:24 +#: views.py:26 msgid "description" msgstr "описание" @@ -913,13 +914,11 @@ msgstr "Путь к файлу программs GraphicsMagick." #: conf/settings.py:15 msgid "" -"Graphics conversion backend to use. Options are: " -"converter.backends.imagemagick, converter.backends.graphicsmagick and " -"converter.backends.python." +"Graphics conversion backend to use. Options are: converter.backends." +"imagemagick, converter.backends.graphicsmagick and converter.backends.python." msgstr "" -"Конвертер графических файлов. Возможные варианты: " -"converter.backends.imagemagick, converter.backends.graphicsmagick и " -"converter.backends.python." +"Конвертер графических файлов. Возможные варианты: converter.backends." +"imagemagick, converter.backends.graphicsmagick и converter.backends.python." #: conf/settings.py:16 msgid "Path to the unoconv program." @@ -927,8 +926,8 @@ msgstr "Путь к программе unoconv." #: conf/settings.py:17 msgid "" -"Use alternate method of connection to LibreOffice using a pipe, it is slower" -" but less prone to segmentation faults." +"Use alternate method of connection to LibreOffice using a pipe, it is slower " +"but less prone to segmentation faults." msgstr "" "Использовать альтернативный способ подключения к LibreOffice использованием " "конвейера pipe, это медленнее, но менее опасно ошибкой сегментации." @@ -944,5 +943,3 @@ msgid "" "backend. In this case: '%(backend)s'" msgstr "" "Эти форматы поддерживают выбранный конвертер. Сейчас это: '%(backend)s'" - - diff --git a/apps/django_gpg/locale/en/LC_MESSAGES/django.po b/apps/django_gpg/locale/en/LC_MESSAGES/django.po index bb2d01367b..871e1b3274 100644 --- a/apps/django_gpg/locale/en/LC_MESSAGES/django.po +++ b/apps/django_gpg/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-12-06 02:06-0400\n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,142 +17,114 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:14 -msgid "Verify document signatures" -msgstr "" - -#: __init__.py:15 -msgid "View keys" -msgstr "" - -#: __init__.py:16 -msgid "Delete keys" -msgstr "" - -#: __init__.py:17 -msgid "Query keyservers" -msgstr "" - -#: __init__.py:18 -msgid "Import key from keyservers" -msgstr "" - -#: __init__.py:19 -msgid "Upload detached signatures" -msgstr "" - -#: __init__.py:20 -msgid "Download detached signatures" -msgstr "" - -#: __init__.py:23 -msgid "Signatures" -msgstr "" - -#: __init__.py:39 views.py:67 +#: __init__.py:14 views.py:67 msgid "private keys" msgstr "" -#: __init__.py:40 views.py:70 +#: __init__.py:15 views.py:70 msgid "public keys" msgstr "" -#: __init__.py:41 +#: __init__.py:16 msgid "delete" msgstr "" -#: __init__.py:42 +#: __init__.py:17 msgid "query keyservers" msgstr "" -#: __init__.py:43 +#: __init__.py:18 msgid "import" msgstr "" -#: __init__.py:44 -msgid "upload signature" -msgstr "" - -#: __init__.py:45 -msgid "download signature" -msgstr "" - -#: __init__.py:46 +#: __init__.py:19 msgid "key management" msgstr "" -#: __init__.py:49 -msgid "signatures" -msgstr "" - -#: api.py:22 +#: api.py:19 msgid "Public" msgstr "" -#: api.py:23 +#: api.py:20 msgid "Secret" msgstr "" -#: api.py:31 api.py:36 +#: api.py:28 api.py:33 msgid "RSA" msgstr "" -#: api.py:32 +#: api.py:29 msgid "DSA" msgstr "" -#: api.py:37 +#: api.py:34 msgid "Elgamal" msgstr "" -#: api.py:51 +#: api.py:48 msgid "Bad signature." msgstr "" -#: api.py:55 +#: api.py:52 msgid "Document not signed or invalid signature." msgstr "" -#: api.py:59 +#: api.py:56 msgid "Signature error." msgstr "" -#: api.py:63 +#: api.py:60 msgid "Document is signed but no public key is available for verification." msgstr "" -#: api.py:67 +#: api.py:64 msgid "Document is signed, and signature is good." msgstr "" -#: api.py:71 +#: api.py:68 msgid "Document is signed with a valid signature." msgstr "" -#: api.py:144 +#: api.py:141 msgid "unknown" msgstr "" -#: forms.py:11 +#: forms.py:8 msgid "Term" msgstr "" -#: forms.py:12 +#: forms.py:9 msgid "Name, e-mail, key ID or key fingerprint to look for." msgstr "" -#: forms.py:18 -msgid "Signature file" +#: permissions.py:7 +msgid "Key management" msgstr "" -#: views.py:45 +#: permissions.py:9 +msgid "View keys" +msgstr "" + +#: permissions.py:10 +msgid "Delete keys" +msgstr "" + +#: permissions.py:11 +msgid "Query keyservers" +msgstr "" + +#: permissions.py:12 +msgid "Import keys from keyservers" +msgstr "" + +#: views.py:38 #, python-format msgid "Key: %s, imported successfully." msgstr "" -#: views.py:48 +#: views.py:43 #, python-format -msgid "Unable to import key id: %s" +msgid "Unable to import key id: %(key_id)s; %(error)s" msgstr "" #: views.py:52 @@ -233,58 +205,10 @@ msgstr "" msgid "Identifies" msgstr "" -#: views.py:205 -#, python-format -msgid "Signature status: %(widget)s %(text)s" -msgstr "" - -#: views.py:212 -msgid "embedded" -msgstr "" - -#: views.py:214 -msgid "detached" -msgstr "" - -#: views.py:219 -#, python-format -msgid "Signature ID: %s" -msgstr "" - -#: views.py:220 -#, python-format -msgid "Signature type: %s" -msgstr "" - -#: views.py:221 -#, python-format -msgid "Key ID: %s" -msgstr "" - -#: views.py:222 -#, python-format -msgid "Timestamp: %s" -msgstr "" - -#: views.py:223 -#, python-format -msgid "Signee: %s" -msgstr "" - -#: views.py:228 -#, python-format -msgid "signature properties for: %s" -msgstr "" - -#: views.py:250 -msgid "Detached signature uploaded successfully." -msgstr "" - -#: views.py:259 -#, python-format -msgid "Upload detached signature for: %s" -msgstr "" - #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." msgstr "" + +#: conf/settings.py:14 +msgid "Home directory used to store keys as well as configuration files." +msgstr "" diff --git a/apps/django_gpg/locale/es/LC_MESSAGES/django.mo b/apps/django_gpg/locale/es/LC_MESSAGES/django.mo index e37a8ed1ed4f0dded084e479b950eef99e3cd029..fc5b4088c5df6fac53ba9153e3e7c42e48de7d04 100644 GIT binary patch delta 1606 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 diff --git a/apps/django_gpg/locale/es/LC_MESSAGES/django.po b/apps/django_gpg/locale/es/LC_MESSAGES/django.po index 7517475856..897c9e4957 100644 --- a/apps/django_gpg/locale/es/LC_MESSAGES/django.po +++ b/apps/django_gpg/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-12-06 02:06-0400\n" -"PO-Revision-Date: 2011-12-06 06:14+0000\n" -"Last-Translator: rosarior \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:37+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,147 +18,119 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:14 -msgid "Verify document signatures" -msgstr "Verificar las firmas de documentos" - -#: __init__.py:15 -msgid "View keys" -msgstr "Ver llaves" - -#: __init__.py:16 -msgid "Delete keys" -msgstr "Borrar llaves" - -#: __init__.py:17 -msgid "Query keyservers" -msgstr "Hacer búsquedas en servidores de llaves" - -#: __init__.py:18 -msgid "Import key from keyservers" -msgstr "Importar llaves de los servidores de llaves" - -#: __init__.py:19 -msgid "Upload detached signatures" -msgstr "Subir una firma a parte" - -#: __init__.py:20 -msgid "Download detached signatures" -msgstr "Descargar la fima" - -#: __init__.py:23 -msgid "Signatures" -msgstr "Firmas" - -#: __init__.py:39 views.py:67 +#: __init__.py:14 views.py:67 msgid "private keys" msgstr "llaves privadas" -#: __init__.py:40 views.py:70 +#: __init__.py:15 views.py:70 msgid "public keys" msgstr "llaves públicas" -#: __init__.py:41 +#: __init__.py:16 msgid "delete" msgstr "borrar" -#: __init__.py:42 +#: __init__.py:17 msgid "query keyservers" msgstr "consultar servidor de llaves" -#: __init__.py:43 +#: __init__.py:18 msgid "import" msgstr "importar" -#: __init__.py:44 -msgid "upload signature" -msgstr "subir firma" - -#: __init__.py:45 -msgid "download signature" -msgstr "descargar firma" - -#: __init__.py:46 +#: __init__.py:19 msgid "key management" msgstr "manejo de llaves" -#: __init__.py:49 -msgid "signatures" -msgstr "firmas" - -#: api.py:22 +#: api.py:19 msgid "Public" msgstr "Pública" -#: api.py:23 +#: api.py:20 msgid "Secret" msgstr "Secreta" -#: api.py:31 api.py:36 +#: api.py:28 api.py:33 msgid "RSA" msgstr "RSA" -#: api.py:32 +#: api.py:29 msgid "DSA" msgstr "DSA" -#: api.py:37 +#: api.py:34 msgid "Elgamal" msgstr "Elgamal" -#: api.py:51 +#: api.py:48 msgid "Bad signature." msgstr "Firma invalida." -#: api.py:55 +#: api.py:52 msgid "Document not signed or invalid signature." msgstr "Documento no firmado o firma invalida." -#: api.py:59 +#: api.py:56 msgid "Signature error." msgstr "Error de firma." -#: api.py:63 +#: api.py:60 msgid "Document is signed but no public key is available for verification." msgstr "" "El document ha sido firmado pero no hay llave pública disponible para " "verificación." -#: api.py:67 +#: api.py:64 msgid "Document is signed, and signature is good." msgstr "El document ha sido firmado y la firma esta es buen estado." -#: api.py:71 +#: api.py:68 msgid "Document is signed with a valid signature." msgstr "El document ha sido firmado y la firma ha sido validada." -#: api.py:144 +#: api.py:141 msgid "unknown" msgstr "desconocida" -#: forms.py:11 +#: forms.py:8 msgid "Term" msgstr "Término" -#: forms.py:12 +#: forms.py:9 msgid "Name, e-mail, key ID or key fingerprint to look for." msgstr "" "Nombre, dirección de correo electrónico, identificador de llave or huella " "digital de llave a buscar." -#: forms.py:18 -msgid "Signature file" -msgstr "Archivo de firma" +#: permissions.py:7 +msgid "Key management" +msgstr "Gestión de llaves" -#: views.py:45 +#: permissions.py:9 +msgid "View keys" +msgstr "Ver llaves" + +#: permissions.py:10 +msgid "Delete keys" +msgstr "Borrar llaves" + +#: permissions.py:11 +msgid "Query keyservers" +msgstr "Hacer búsquedas en servidores de llaves" + +#: permissions.py:12 +msgid "Import keys from keyservers" +msgstr "Importar llaves del servidores de llaves" + +#: views.py:38 #, python-format msgid "Key: %s, imported successfully." msgstr "Llave: %s, importada exitosamente." -#: views.py:48 +#: views.py:43 #, python-format -msgid "Unable to import key id: %s" -msgstr "No se pudo importa la llave: %s" +msgid "Unable to import key id: %(key_id)s; %(error)s" +msgstr "No se pudo importar la llave: %(key_id)s ; %(error)s " #: views.py:52 msgid "Import key" @@ -241,62 +213,16 @@ msgstr "revocada" msgid "Identifies" msgstr "Identidades" -#: views.py:205 -#, python-format -msgid "Signature status: %(widget)s %(text)s" -msgstr "Estado de la firma: %(widget)s %(text)s" - -#: views.py:212 -msgid "embedded" -msgstr "integrada" - -#: views.py:214 -msgid "detached" -msgstr "a parte" - -#: views.py:219 -#, python-format -msgid "Signature ID: %s" -msgstr "ID de la firma: %s" - -#: views.py:220 -#, python-format -msgid "Signature type: %s" -msgstr "Tipo de firma: %s" - -#: views.py:221 -#, python-format -msgid "Key ID: %s" -msgstr "ID de la llave: %s" - -#: views.py:222 -#, python-format -msgid "Timestamp: %s" -msgstr "Fecha y hora: %s" - -#: views.py:223 -#, python-format -msgid "Signee: %s" -msgstr "Firmantes: %s" - -#: views.py:228 -#, python-format -msgid "signature properties for: %s" -msgstr "propiedades de firma para: %s" - -#: views.py:250 -msgid "Detached signature uploaded successfully." -msgstr "El archivo de firma fue subido exitosamente." - -#: views.py:259 -#, python-format -msgid "Upload detached signature for: %s" -msgstr "Subir firma a parte para: %s" - #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." msgstr "" "Lista de servidores de llaves a ser utilizados para buscar llaves " "desconocidas." +#: conf/settings.py:14 +msgid "Home directory used to store keys as well as configuration files." +msgstr "" +"Directorio de inicio utilizado para almacenar las llaves, así como los " +"archivos de configuración." + diff --git a/apps/django_gpg/locale/it/LC_MESSAGES/django.mo b/apps/django_gpg/locale/it/LC_MESSAGES/django.mo index 44d5c883f59b04faf8c86605f5765374212d4deb..6178823a5bccbe1f8633f1ad15ec60f94a424bf7 100644 GIT binary patch delta 1246 zcmYk*O-NKx6u|ML`ThM>PNw-RHAfwrF)K4Sl`W!AR0@I?Pv=z+bw=JyiXv&7qCgN{ zQ3N3o89}F5I2J#S(f<7wQAGgyg>*odJ?_~MOMF^BOQY6a4HSQ9Bm{a&?aBkIO2 z-gqCrAE(?0=se*AU#7@TTtwaAC+Z1OD32zR;pxLOjO#Ff6Sy7ca0f0UOUfGRTTCV^ zx{`{zZUM5iRN{Cw9X}mi-~{eL2Y2CP)RV2CR^%HRxQhCG2_I^Lt*9HeqbAyc`g}JQ z;W^Zb40`idkV|glP=77`ZAQAlL!^o_izWCJHPa>3%-^DJ@EHyK;eB4rBD!G(YKd!+ z9Hjv%aH17+uOf8)vc!zYW_|zKDu`O5o+u>rbftv;0JWrbgeIW>5FepUf0UZEo=i8@ zN^T=I5xTi1uB~w$*@9XvZRDLeKbX(4VoVKlDqt6aXT6@!e-o( zu+?uVcFgSQcXP9xocPF~C6^+7k?3&5eU%m8-5dz&WrSMVLVE+jmS8aJ)X6}nHDt$F zCeXn$ZANo2^zXUWw&tKakX`EUjP_VgJZf}CW2R$Ajdo{!qRCmGXu1%MjGFz{==@Cf zpCtE9?y|d(SCiR$(Kd%HPBCASU!LSUtjDm7ux*^TodHw2dd;xK_uPYpp-i*K?ziJ+ O+;s03PPtu0g?|CC>z_3M literal 4723 zcma);O^h5z6@Uu}I4pl5A^ao|%EU?5@y^d~g5!+6PS(3?X+##A-E{~TOSLn#v&Hsw zH(fn5UUNW10_73`2csxLkp)5o$wGiYLI??jl|v*VazI=nIT9BRC=v%wNRjwnb@$A8 zy_RTA_1D#1_3FJ>uil#*ci(YEaV^n4OFQyjrM?E|?%>At{r4;NGW-EN2IoGY)JNfS z@O`icXW%aU5FEmz@Oiilufa#*zf0bKsQ7*s%6ci}r(Wd7(&`Enc`udx3A~T~FCZe+ z>*f15;RE#Ff}e-~g$wY$JC%AIu0d2*&qJB_0=x@;ujExI`v0o@{@e2XA4 zA@~lw8{YH5LcfPg&O>q4Dfkh%1n-CE;9)d4g8&LFn3$ldzN6CLd zS?@n({}4|382!5-rYa3(-YgV78)g4A{4o7hDEqMv#qNtx<|QRZQ2hTb$WQ%(@~1 z{}a^kpHSl9P9{sdJ_u!hmm#0jvry*upvX(1=q5zdyj@vfeBd|Ib6QXAMdmY(QD>IVf_vkT3{qHlUn|CQU9G ze=`1ce|;#*=s;^vby@sC^*Ut#YIt9R{QOF!hF(z?AJ2Ikq`)Mum9!B*rtGEV0^CfCmE)MU9%wsrNfk!Ega5SAL3 zF^Y%sh0GecDAHTDT(GN+*CQK6_1mlF`f0)nGTC*5cIu4jYVUfn$+4rZRyLN@%GiLZ zN6&L^Iy-i1xE`cYV!HBb(CJw3w+B(QhmfQ*=-W7$B(fQ>HOO_GOxujPW@ubwwj!&y zlS~h7=C)nOypcD1 zbNsp3y<5EfjPoIAcE@W-m=PD>7~oNci*pC@Zk&wbph#VP+4Sw4wzWR~p9|s8UJ*Ya zLT|gcXEWlA{XPXcCHgi8@7|#Ty0eGh2g>C z$qSohB75>;+eLP&>vICrGii3@x;>j8^*rYG5)V_O^1amFEV%e;i?^FL>#I%Iw@B-! zVc>;0#2p6SawgP;5Y-24y!fG*eY+7}Ju6YXr@Pe=koXU0i%-su!Uib362e?}Iozs9 z7@!C=)pcH!>#8n07GiKLMA`n9?Q-Ijy_C9aN=WGQzA#70PWDY~dR7jiifr7=chpq& z@M@BOypm7}+ga^iX8j<_y~^w`*+uMF12RyO+AJsF$L<(^^h$O@mBFTp^e{;;>U@@b z-FEU?yIaFgo`c@fYi7^HdUa)OV`kk-daAAYp6k}m40^t{nY8pyo~NxwqsQqVY}GqS zzmX;0WG=}XeVN;E-VdywIe%`mwp=>4wt{0@dZ9T#Uz=a3HIM7&LaTYa)_lC#WMFOG z4xKE&f83LL{)yIO3&)yVGtU^G*ETZ~`^e<7^XDB0!z59n&zPu-)~C|yO?@l8dAcV@ zN|Zd!^td-*18SSr^jo@}led^NTiP=kjq14wciZ+-J+?W?K6uAB(!#Ks?e={mXLiHo zjiWPb?X}g3-{$MhndKzT+1}b_h<`a2jWjYYKB+r9Ci6C5ys&w;c49J4*4wsOZ8h#B zT@HFnpV)HwSk;!Mb3PhmCaRrHvOWhdPD9r(E}YcGN>5F$s zn!2honzA$+GQA8QFI84ZqY07gSI6t*=0IhO({huph>R5i=#pB_v+f%ab|I?X)?SOJYPYmgJBo zvD+d|YR;jItP1BXa!ZL}b@5>67xhyNDpS;WWlbFpHnYsuAc=1pBgahnE%Z@24r0lc=$i6OlF^V2B15TaGuU}QgASs*6VR%(XCebxF zwbT2&T}+X@Jy$0CTX#fisF6S`@?Y?55bi=KdZ*LG`-FcmltrmoJz|DBnoQMENx78K zut+8c6L};pPJJQHW;n@84kQhe>&akJO+&z|b|qH3s8WKuz$O=JObwWFOc4R&F-6Jk zQF8I`iaslw8S2%lRM~Kl!WI&z2o~{WOsI`eW~W~C$l2gP0&XED}m_S!@Xf z{t{g_`wDKGKS$mdaeMnyr\n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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" @@ -18,145 +18,117 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:14 -msgid "Verify document signatures" -msgstr "Verifica la firma del documento" - -#: __init__.py:15 -msgid "View keys" -msgstr "Vista delle chiavi" - -#: __init__.py:16 -msgid "Delete keys" -msgstr "Cancella chiavi" - -#: __init__.py:17 -msgid "Query keyservers" -msgstr "Interroga l'autorità per le chiavi" - -#: __init__.py:18 -msgid "Import key from keyservers" -msgstr "Importa chiave dall'autorità" - -#: __init__.py:19 -msgid "Upload detached signatures" -msgstr "Carica firme separatamente" - -#: __init__.py:20 -msgid "Download detached signatures" -msgstr "Scarica firme separatamente" - -#: __init__.py:23 -msgid "Signatures" -msgstr "Firma" - -#: __init__.py:39 views.py:67 +#: __init__.py:14 views.py:67 msgid "private keys" msgstr "Chiave privata" -#: __init__.py:40 views.py:70 +#: __init__.py:15 views.py:70 msgid "public keys" msgstr "Chiave pubblica" -#: __init__.py:41 +#: __init__.py:16 msgid "delete" msgstr "cancella" -#: __init__.py:42 +#: __init__.py:17 msgid "query keyservers" msgstr "Interroga il server delle chiavi" -#: __init__.py:43 +#: __init__.py:18 msgid "import" msgstr "import" -#: __init__.py:44 -msgid "upload signature" -msgstr "aggiorna firma" - -#: __init__.py:45 -msgid "download signature" -msgstr "scarica firma" - -#: __init__.py:46 +#: __init__.py:19 msgid "key management" msgstr "gestione della firma" -#: __init__.py:49 -msgid "signatures" -msgstr "firma" - -#: api.py:22 +#: api.py:19 msgid "Public" msgstr "Pubblica" -#: api.py:23 +#: api.py:20 msgid "Secret" msgstr "Segreta" -#: api.py:31 api.py:36 +#: api.py:28 api.py:33 msgid "RSA" msgstr "RSA" -#: api.py:32 +#: api.py:29 msgid "DSA" msgstr "DSA" -#: api.py:37 +#: api.py:34 msgid "Elgamal" msgstr "Elgamal" -#: api.py:51 +#: api.py:48 msgid "Bad signature." msgstr "Firma cattiva." -#: api.py:55 +#: api.py:52 msgid "Document not signed or invalid signature." msgstr "Documento non firmato o firma invalida." -#: api.py:59 +#: api.py:56 msgid "Signature error." msgstr "Errore di firma" -#: api.py:63 +#: api.py:60 msgid "Document is signed but no public key is available for verification." msgstr "" "Il documento è stato firmato, ma la chiave pubblica non è disponibile per la" " verifica" -#: api.py:67 +#: api.py:64 msgid "Document is signed, and signature is good." msgstr "Documento firmato e firma è buona." -#: api.py:71 +#: api.py:68 msgid "Document is signed with a valid signature." msgstr "Il documento è firmato con una firma valida." -#: api.py:144 +#: api.py:141 msgid "unknown" msgstr "sconosciuto" -#: forms.py:11 +#: forms.py:8 msgid "Term" msgstr "Scadenza" -#: forms.py:12 +#: forms.py:9 msgid "Name, e-mail, key ID or key fingerprint to look for." msgstr "Nome, e-mail,key ID , impronte digitali per cercare" -#: forms.py:18 -msgid "Signature file" -msgstr "File della firma" +#: permissions.py:7 +msgid "Key management" +msgstr "" -#: views.py:45 +#: permissions.py:9 +msgid "View keys" +msgstr "Vista delle chiavi" + +#: permissions.py:10 +msgid "Delete keys" +msgstr "Cancella chiavi" + +#: permissions.py:11 +msgid "Query keyservers" +msgstr "Interroga l'autorità per le chiavi" + +#: permissions.py:12 +msgid "Import keys from keyservers" +msgstr "" + +#: views.py:38 #, python-format msgid "Key: %s, imported successfully." msgstr "Chiave: %s, importata con successo." -#: views.py:48 +#: views.py:43 #, python-format -msgid "Unable to import key id: %s" -msgstr "Impossibile importare la chiave id: %s" +msgid "Unable to import key id: %(key_id)s; %(error)s" +msgstr "" #: views.py:52 msgid "Import key" @@ -239,60 +211,12 @@ msgstr "revocata" msgid "Identifies" msgstr "Identifica" -#: views.py:205 -#, python-format -msgid "Signature status: %(widget)s %(text)s" -msgstr "Status della firma: %(widget)s %(text)s" - -#: views.py:212 -msgid "embedded" -msgstr "incorporato" - -#: views.py:214 -msgid "detached" -msgstr "distaccato" - -#: views.py:219 -#, python-format -msgid "Signature ID: %s" -msgstr "ID Firma: %s" - -#: views.py:220 -#, python-format -msgid "Signature type: %s" -msgstr "Tipo di firma: %s" - -#: views.py:221 -#, python-format -msgid "Key ID: %s" -msgstr "Chiave ID: %s" - -#: views.py:222 -#, python-format -msgid "Timestamp: %s" -msgstr "Timestamp: %s" - -#: views.py:223 -#, python-format -msgid "Signee: %s" -msgstr "Signee: %s" - -#: views.py:228 -#, python-format -msgid "signature properties for: %s" -msgstr "Proprietà per la firma: %s" - -#: views.py:250 -msgid "Detached signature uploaded successfully." -msgstr "Firma scaduta aggiornata con successo." - -#: views.py:259 -#, python-format -msgid "Upload detached signature for: %s" -msgstr "Aggiornata firma scaduta per: %s" - #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." msgstr "Lista di server per chiavi che si possono interrogare." +#: conf/settings.py:14 +msgid "Home directory used to store keys as well as configuration files." +msgstr "" + diff --git a/apps/django_gpg/locale/pt/LC_MESSAGES/django.mo b/apps/django_gpg/locale/pt/LC_MESSAGES/django.mo index cbde9b3dc3c2f39bd3e52295c558bb4949d69968..4a908407bbbcf2f722c2cde25739338c3a0dad57 100644 GIT binary patch delta 780 zcmXYvJxE(o6vt1RmnO#8XrlF_YF!+H74lI~LnUKzXoos>l0>M5HcFgyc%8bGPM1=s z7KB1w94tj>p-bHbH|wA@ZY_eLQ=o(X{?B)~=l<@!=iYbD`Sadp|EB%ZjQ7s4yZA8P z8!^kl)D0$V7f!%0@D@CQQFsoMumwBef2enHf^k@Y9N7%iy$A3ndTlTZ8GWMR(QS*JJ^4NU2s2)AHoFtBbbK2p$ch*@it7czl16{PL*CjPRN_Zaiadq7_Z%wW22|&t!uV&XgnLjb|AczqgbDK7 z1q(^vh9j_#uP9Lo>Vs2ESy+L3I1hW^0%TZ&NfNI^75W-ViT6;6x1bc+3FAMY?jJy3 zo&RDXX-*)GTR+ay?%+zO;w1SHE*rpAP(~X}No4w{3K+zDahViSQ!?dJA-8cUgcXCi zFPN{p)>1O@a|B)JXHjv86IhR%jecbrmP`8e@g~<-(Nv9ve+w qZ>P(}{MTlz8F7E&A6+w1aw8p2GOJ6=b*n8ls`Z!87OP9Ox?KUe(n^N_ delta 1195 zcmZwFPe@cj9Ki9>U0t;{ORdy$o2-q@j9pVBPl?hWiViLw>h|3C)GgO1Z=PFGuo4tR zbb3Y5r9+44AV~#5bP+EFL8qt=1>T}d6kWXa{k?tarD5lN=FQB`{C+d`t_!(>Q z52lnVt5q5`bhO4R11a3fdpdFenW9cb<7cD(QIw$bC>z|tU3eesaS@aF24%x{Sce}Y zzhEQ#s}&j&@o$ugtGF2@D# zpi zrho8g-^)+&m8x{OoaO2KlvQ%HO+>_5uwBnF@)mZR;8pG8i@7jVZClzhrVz$&{Xg)b z^>L%lFF$eh@-sc_8ne7ma;BpU*0u~&7)|umImPigpN)fCiCk)92c!JLtgCFt\n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" "MIME-Version: 1.0\n" @@ -18,143 +18,115 @@ msgstr "" "Language: pt\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:14 -msgid "Verify document signatures" -msgstr "" - -#: __init__.py:15 -msgid "View keys" -msgstr "Ver as chaves" - -#: __init__.py:16 -msgid "Delete keys" -msgstr "Excluir chaves" - -#: __init__.py:17 -msgid "Query keyservers" -msgstr "Consulta servidores de chaves" - -#: __init__.py:18 -msgid "Import key from keyservers" -msgstr "Importar chave de servidores de chaves" - -#: __init__.py:19 -msgid "Upload detached signatures" -msgstr "" - -#: __init__.py:20 -msgid "Download detached signatures" -msgstr "" - -#: __init__.py:23 -msgid "Signatures" -msgstr "Assinaturas" - -#: __init__.py:39 views.py:67 +#: __init__.py:14 views.py:67 msgid "private keys" msgstr "chaves privadas" -#: __init__.py:40 views.py:70 +#: __init__.py:15 views.py:70 msgid "public keys" msgstr "chaves públicas" -#: __init__.py:41 +#: __init__.py:16 msgid "delete" msgstr "excluir" -#: __init__.py:42 +#: __init__.py:17 msgid "query keyservers" msgstr "" -#: __init__.py:43 +#: __init__.py:18 msgid "import" msgstr "" -#: __init__.py:44 -msgid "upload signature" -msgstr "" - -#: __init__.py:45 -msgid "download signature" -msgstr "" - -#: __init__.py:46 +#: __init__.py:19 msgid "key management" msgstr "" -#: __init__.py:49 -msgid "signatures" -msgstr "assinaturas" - -#: api.py:22 +#: api.py:19 msgid "Public" msgstr "Público" -#: api.py:23 +#: api.py:20 msgid "Secret" msgstr "Segredo" -#: api.py:31 api.py:36 +#: api.py:28 api.py:33 msgid "RSA" msgstr "RSA" -#: api.py:32 +#: api.py:29 msgid "DSA" msgstr "DSA" -#: api.py:37 +#: api.py:34 msgid "Elgamal" msgstr "Elgamal" -#: api.py:51 +#: api.py:48 msgid "Bad signature." msgstr "Assinatura ruim." -#: api.py:55 +#: api.py:52 msgid "Document not signed or invalid signature." msgstr "Documento não assinado ou inválido assinatura." -#: api.py:59 +#: api.py:56 msgid "Signature error." msgstr "Erro de assinatura." -#: api.py:63 +#: api.py:60 msgid "Document is signed but no public key is available for verification." msgstr "" -#: api.py:67 +#: api.py:64 msgid "Document is signed, and signature is good." msgstr "" -#: api.py:71 +#: api.py:68 msgid "Document is signed with a valid signature." msgstr "" -#: api.py:144 +#: api.py:141 msgid "unknown" msgstr "desconhecido" -#: forms.py:11 +#: forms.py:8 msgid "Term" msgstr "" -#: forms.py:12 +#: forms.py:9 msgid "Name, e-mail, key ID or key fingerprint to look for." msgstr "" -#: forms.py:18 -msgid "Signature file" +#: permissions.py:7 +msgid "Key management" msgstr "" -#: views.py:45 +#: permissions.py:9 +msgid "View keys" +msgstr "Ver as chaves" + +#: permissions.py:10 +msgid "Delete keys" +msgstr "Excluir chaves" + +#: permissions.py:11 +msgid "Query keyservers" +msgstr "Consulta servidores de chaves" + +#: permissions.py:12 +msgid "Import keys from keyservers" +msgstr "" + +#: views.py:38 #, python-format msgid "Key: %s, imported successfully." msgstr "" -#: views.py:48 +#: views.py:43 #, python-format -msgid "Unable to import key id: %s" -msgstr "Não é possível importar chave: %s" +msgid "Unable to import key id: %(key_id)s; %(error)s" +msgstr "" #: views.py:52 msgid "Import key" @@ -234,60 +206,12 @@ msgstr "" msgid "Identifies" msgstr "" -#: views.py:205 -#, python-format -msgid "Signature status: %(widget)s %(text)s" -msgstr "Status da assinatura: %(widget)s %(text)s" - -#: views.py:212 -msgid "embedded" -msgstr "embutido" - -#: views.py:214 -msgid "detached" -msgstr "" - -#: views.py:219 -#, python-format -msgid "Signature ID: %s" -msgstr "" - -#: views.py:220 -#, python-format -msgid "Signature type: %s" -msgstr "" - -#: views.py:221 -#, python-format -msgid "Key ID: %s" -msgstr "" - -#: views.py:222 -#, python-format -msgid "Timestamp: %s" -msgstr "" - -#: views.py:223 -#, python-format -msgid "Signee: %s" -msgstr "" - -#: views.py:228 -#, python-format -msgid "signature properties for: %s" -msgstr "" - -#: views.py:250 -msgid "Detached signature uploaded successfully." -msgstr "" - -#: views.py:259 -#, python-format -msgid "Upload detached signature for: %s" -msgstr "" - #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." msgstr "" +#: conf/settings.py:14 +msgid "Home directory used to store keys as well as configuration files." +msgstr "" + diff --git a/apps/django_gpg/locale/ru/LC_MESSAGES/django.mo b/apps/django_gpg/locale/ru/LC_MESSAGES/django.mo index 93a6b8285844a1db89bc56a295db00cb4da1c6ae..a55c4e91b6b1235e1c111705ce2353794fe3c0e6 100644 GIT binary patch literal 3930 zcma)-TWlOx8GsK^C@lAsLMgXXNJ89rZ>|Ml6DOpxLoH$wY*QiL#@^%g;Mo~>X4V@= z5#*xOREZj>QV~^ZqpG63At$YgW5@PWB`yz~dEgCrKp=$RjW-?;-#HTDLoX|?e#U1RXWymNLHLJvbL0Bedz5+w{u=Iw)rXY&2>dZ*O5K1t_y+tS z`~^G)*Wi=zKNbOAwdTb@&1JD*Q0~Ipn8SxV<0Vg&&3QK=JqYke~V^ zH;Ml*+55lXhj{-tl=vS;Sp0Yd%D&wh`=Qt!%-+8SH3>Kh|IGXp&J^GX$&h$sDE?oA zkHPEk)9@xV@VD?8SjOlPcm|$?YY>$xhf|W@T@X?AD3tvgO1zcq{TV2ApMoy@Av^*9 z4keDSAT0a_?1$fld3Xtme{aEE@HP}Zzkw3x-{9xqKcU#oku=HMZf+v~6#NW4p3P4| zvGW}K61)J#?>C|7xd}!7cd!8e0Y3pBr${`iBBTWBFqHWbNGqq;Bix^0$ok{yOv@*E z6y19nPclBv5Zj+(Nbh}_v5z78B{r#pTv8v&vG^;o?q+s94>Y(J9@q`<+;-$r{h^C)^4QdoiNtHjNV=>&WG-TgR*(Y z4Uys@n~+^i*Yot0$qZJt6X~Y$yn=e5Yi@l$z=CXctEqSDX{V|qx8^%BaTL_>#8EZe z4xsBXQp3S?qi+1vQQ2Xtda4m?Kj@BxAe;rq^_(fs=$RnY3np}D+-WCv10VJG>u9?1 zECDY#p4;omeWLx^@w-GMVYMKrc4_s4I1L8ZFzx#HDIM`@PTld;=&%~C5(}=GNR77B zqP|ILSOk)u{&sGo#`Ls_qM3&0EfzYDMM-Cwcv8g+_-Z2v+rs>(@+3=}A6%ydanp4Fz?w>6=iUN*hUi z8{Lbke9LBMBJ)9wQ``wN9hz88Y?oY{FcejjCakMxUDHhcQ3$0a(^c9}wOU$L-AL+M zRp#`(8+NUy@65N-p~UC9<2yAY{h~bM*Wy{#)w+@DG=HQdDXHVzeugG$cyXjcvk=Uo zHeQ@JDod9-6$alo({X;ZntztW(pD8c<}5nC9vL2+$c-Cm@%&g+bF2BM8?`7u8C3La z9M4yZ#TvcVm?}&M^(SmVJFFY)uq0 zhYGd8KjV1j%-3tu3gYWwwD`3K>C8_Wr;d(B6uAVvFAJ;LY!+g%;m(-T1>eMcH_{|U z#ralzc~h-N#hBg2uu<&Gjg5|tbkbKYlyb)cKc-muNpfA$u{n(r&vE^OdV1CgBNGpO zXYzRdKu1pO&6qGh;!g)v8nmJhOu2E})rt-qxl>*vbiDlWAgo6f?a!yL(a=)|b?b3x zpTDPE8X79=y?eDhmYx_Ym-P`{(unhZcxYgI>Cn)iJf=HJhsq^=_H1hlGNnHDl-V=T zms9qo@ z(Y7xq=Ve9PTP6cRE{JM$X&KR75v3PR zJw07=8n@80L|<}1#i{K^;7uG|OLPAc;>#?pz?I~AWnV+Q>+~r5(=HcV2f90&9_M<5 zS?P^?+1~AymcLEWCH63$hHLML3qMLLjfXw8maa|zPVJ2>Wwaz8f^)rUiAG{x7VDcN zQ@$`8gnU({r@sARQt6jMvcJL?geuxi)!r*9V{AwQv)$>T=KCh)5YbKtq-hcDqHLM! zkxSVmZQMSIoF9%hMPQ!3zd!OWVFaasojUZcb#+b0z=L{CNr3h?-mNEBBro!9ZRwZn T+>-bd^Q(4C;n+P5NTB}(EEgAu delta 157 zcmca5w}!>yo)F7a1|VPrVi_P-0b*t#)&XJ=umIvuKuJp=4N?OGlO5R2CeLLT=QY$d zG}1LNQ!p^HGBBHbkX>2_B4VmwXl`X, 2011. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-12-06 02:06-0400\n" -"PO-Revision-Date: 2011-12-05 17:43+0000\n" -"Last-Translator: rosarior \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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/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:14 -msgid "Verify document signatures" -msgstr "" +#: __init__.py:14 views.py:67 +msgid "private keys" +msgstr "секретные ключи" -#: __init__.py:15 -msgid "View keys" -msgstr "" +#: __init__.py:15 views.py:70 +msgid "public keys" +msgstr "открытые ключи" #: __init__.py:16 -msgid "Delete keys" -msgstr "" +msgid "delete" +msgstr "удалить" #: __init__.py:17 -msgid "Query keyservers" -msgstr "" +msgid "query keyservers" +msgstr "запрос ключевых серверов" #: __init__.py:18 -msgid "Import key from keyservers" -msgstr "" +msgid "import" +msgstr "получить" #: __init__.py:19 -msgid "Upload detached signatures" -msgstr "" - -#: __init__.py:20 -msgid "Download detached signatures" -msgstr "" - -#: __init__.py:23 -msgid "Signatures" -msgstr "" - -#: __init__.py:39 views.py:67 -msgid "private keys" -msgstr "" - -#: __init__.py:40 views.py:70 -msgid "public keys" -msgstr "" - -#: __init__.py:41 -msgid "delete" -msgstr "" - -#: __init__.py:42 -msgid "query keyservers" -msgstr "" - -#: __init__.py:43 -msgid "import" -msgstr "" - -#: __init__.py:44 -msgid "upload signature" -msgstr "" - -#: __init__.py:45 -msgid "download signature" -msgstr "" - -#: __init__.py:46 msgid "key management" -msgstr "" +msgstr "управление ключами" -#: __init__.py:49 -msgid "signatures" -msgstr "" - -#: api.py:22 +#: api.py:19 msgid "Public" -msgstr "" +msgstr "Открытый" -#: api.py:23 +#: api.py:20 msgid "Secret" -msgstr "" +msgstr "секретный" -#: api.py:31 api.py:36 +#: api.py:28 api.py:33 msgid "RSA" -msgstr "" +msgstr "RSA" -#: api.py:32 +#: api.py:29 msgid "DSA" -msgstr "" +msgstr "DSA" -#: api.py:37 +#: api.py:34 msgid "Elgamal" -msgstr "" +msgstr "Elgamal" -#: api.py:51 +#: api.py:48 msgid "Bad signature." -msgstr "" +msgstr "Неверная подпись" -#: api.py:55 +#: api.py:52 msgid "Document not signed or invalid signature." -msgstr "" +msgstr "Документ не подписан, либо подпись неверна." -#: api.py:59 +#: api.py:56 msgid "Signature error." -msgstr "" +msgstr "Ошибка подписи." -#: api.py:63 +#: api.py:60 msgid "Document is signed but no public key is available for verification." -msgstr "" +msgstr "Документ подписан, но нет открытого ключа для проверки." -#: api.py:67 +#: api.py:64 msgid "Document is signed, and signature is good." -msgstr "" +msgstr "Документ подписан и подпись верна." -#: api.py:71 +#: api.py:68 msgid "Document is signed with a valid signature." -msgstr "" +msgstr "Документ подписан допустимой подписью." -#: api.py:144 +#: api.py:141 msgid "unknown" -msgstr "" +msgstr "неизвестно" -#: forms.py:11 +#: forms.py:8 msgid "Term" -msgstr "" +msgstr "Term" -#: forms.py:12 +#: forms.py:9 msgid "Name, e-mail, key ID or key fingerprint to look for." +msgstr "Имя, e-mail, ID ключа или отпечаток для поиска." + +#: permissions.py:7 +msgid "Key management" msgstr "" -#: forms.py:18 -msgid "Signature file" +#: permissions.py:9 +msgid "View keys" +msgstr "Просмотр ключей" + +#: permissions.py:10 +msgid "Delete keys" +msgstr "Удалить ключи" + +#: permissions.py:11 +msgid "Query keyservers" +msgstr "Запрос к серверам ключей" + +#: permissions.py:12 +msgid "Import keys from keyservers" msgstr "" -#: views.py:45 +#: views.py:38 #, python-format msgid "Key: %s, imported successfully." -msgstr "" +msgstr "Ключ %s, получен." -#: views.py:48 +#: views.py:43 #, python-format -msgid "Unable to import key id: %s" +msgid "Unable to import key id: %(key_id)s; %(error)s" msgstr "" #: views.py:52 msgid "Import key" -msgstr "" +msgstr "Получить ключ" #: views.py:53 #, python-format msgid "Are you sure you wish to import key id: %s?" -msgstr "" +msgstr "Хотите получить ключ id: %s?" #: views.py:78 msgid "Key ID" -msgstr "" +msgstr "ID ключа" #: views.py:82 msgid "Owner" -msgstr "" +msgstr "Владелец" #: views.py:102 #, python-format msgid "Key: %s, deleted successfully." -msgstr "" +msgstr "Ключ %s удалён." #: views.py:109 msgid "Delete key" -msgstr "" +msgstr "Удалить ключ." #: views.py:111 #, python-format @@ -190,103 +161,59 @@ msgid "" "that is part of a public/private pair the private key will be deleted as " "well." msgstr "" +"Вы уверены, что хотите удалить ключ %s? Если вы удалите открытый ключ то " +"соответствующий ему закрытый ключ тоже будет удалён." #: views.py:129 msgid "Query key server" -msgstr "" +msgstr "Запросить сервер ключей" #: views.py:142 msgid "results" -msgstr "" +msgstr "результаты" #: views.py:147 msgid "ID" -msgstr "" +msgstr "ID" #: views.py:151 msgid "type" -msgstr "" +msgstr "тип" #: views.py:155 msgid "creation date" -msgstr "" +msgstr "дата создания" #: views.py:159 msgid "disabled" -msgstr "" +msgstr "запрещено" #: views.py:163 msgid "expiration date" -msgstr "" +msgstr "дата окончания" #: views.py:167 msgid "expired" -msgstr "" +msgstr "истекло" #: views.py:171 msgid "length" -msgstr "" +msgstr "длина" #: views.py:175 msgid "revoked" -msgstr "" +msgstr "отозван" #: views.py:180 msgid "Identifies" -msgstr "" - -#: views.py:205 -#, python-format -msgid "Signature status: %(widget)s %(text)s" -msgstr "" - -#: views.py:212 -msgid "embedded" -msgstr "" - -#: views.py:214 -msgid "detached" -msgstr "" - -#: views.py:219 -#, python-format -msgid "Signature ID: %s" -msgstr "" - -#: views.py:220 -#, python-format -msgid "Signature type: %s" -msgstr "" - -#: views.py:221 -#, python-format -msgid "Key ID: %s" -msgstr "" - -#: views.py:222 -#, python-format -msgid "Timestamp: %s" -msgstr "" - -#: views.py:223 -#, python-format -msgid "Signee: %s" -msgstr "" - -#: views.py:228 -#, python-format -msgid "signature properties for: %s" -msgstr "" - -#: views.py:250 -msgid "Detached signature uploaded successfully." -msgstr "" - -#: views.py:259 -#, python-format -msgid "Upload detached signature for: %s" -msgstr "" +msgstr "Identifies" #: conf/settings.py:13 msgid "List of keyservers to be queried for unknown keys." +msgstr "Список ключевых серверов для запроса неизвестных ключей." + +#: conf/settings.py:14 +msgid "Home directory used to store keys as well as configuration files." msgstr "" + + diff --git a/apps/document_comments/locale/en/LC_MESSAGES/django.po b/apps/document_comments/locale/en/LC_MESSAGES/django.po index 5c78a1a8aa..b77b0a235e 100644 --- a/apps/document_comments/locale/en/LC_MESSAGES/django.po +++ b/apps/document_comments/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,84 +17,80 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:15 -msgid "Create new comments" -msgstr "" - -#: __init__.py:16 -msgid "Delete comments" -msgstr "" - -#: __init__.py:17 -msgid "Edit comments" -msgstr "" - -#: __init__.py:18 -msgid "View comments" -msgstr "" - -#: __init__.py:20 -msgid "Comments" -msgstr "" - -#: __init__.py:26 __init__.py:27 +#: __init__.py:19 __init__.py:20 msgid "delete" msgstr "" -#: __init__.py:28 +#: __init__.py:21 msgid "add comment" msgstr "" -#: __init__.py:29 utils.py:14 +#: __init__.py:22 msgid "comments" msgstr "" -#: __init__.py:33 +#: __init__.py:26 msgid "date" msgstr "" -#: __init__.py:37 +#: __init__.py:30 msgid "user" msgstr "" -#: __init__.py:41 +#: __init__.py:34 msgid "comment" msgstr "" -#: views.py:27 +#: permissions.py:7 +msgid "Comments" +msgstr "" + +#: permissions.py:9 +msgid "Create new comments" +msgstr "" + +#: permissions.py:10 +msgid "Delete comments" +msgstr "" + +#: permissions.py:11 +msgid "View comments" +msgstr "" + +#: views.py:36 msgid "Must provide at least one comment." msgstr "" -#: views.py:37 +#: views.py:46 #, python-format msgid "Comment \"%s\" deleted successfully." msgstr "" -#: views.py:39 +#: views.py:48 #, python-format msgid "Error deleting comment \"%(comment)s\": %(error)s" msgstr "" -#: views.py:54 +#: views.py:63 #, python-format msgid "Are you sure you wish to delete the comment: %s?" msgstr "" -#: views.py:56 +#: views.py:65 #, python-format msgid "Are you sure you wish to delete the comments: %s?" msgstr "" -#: views.py:86 +#: views.py:99 msgid "Comment added successfully." msgstr "" -#: views.py:93 +#: views.py:106 #, python-format msgid "Add comment to document: %s" msgstr "" -#: views.py:109 +#: views.py:126 #, python-format msgid "comments: %s" msgstr "" diff --git a/apps/document_comments/locale/es/LC_MESSAGES/django.mo b/apps/document_comments/locale/es/LC_MESSAGES/django.mo index d2d8efb3e2a839db1e0f6f49ff3103c4ff761f9a..3a098dbda394827f1e416f5699ba00c8c5fc8862 100644 GIT binary patch delta 596 zcmX}o&npCB7{Kv&?N}_kejaG4^`jK6nO#DYVxuTqBqtZWG_5VWqnX(QmsJ$^iIegV zCavXi_dyU0v{8&Sp> z-k^amn8aw65Is1BYJMGSv4pDDAvWR(>Uf4d_>2+!!Fra9NKl9x20Bm`=*9*dKn=$* zgcE=7)A&XcbJ)xHV6_kAtrg~V_*kW$EVnW z=NQIYR0SUX=AV$7;saH~pQsM-jr3J%TK$1$veC~6Vrf-Hg<7qSrdF#8swy8 z6Vr|*y_{W0%t+5N<0&JVN*L;jCr8ZWn13CN4gZgfn<-<^Ai^2xdWmI67Titg*^U`s lvezufv$3+1AJX>xV{N4&BMaH0%u?ENFFv(&z@H73e*ybFSJMCh delta 599 zcmZ9|J4?e*7{>9FUc6MTw^GF$^#TqOn#5AEOBF>N3X15WE&;0)w1uR)R&j822!gYN zi%uef&@Z5aD7p#a7Z4oO!A1XXbr27E^Gi;WC+|7i;k|I_sU>ir7!j(ADpTFmvc`#V zi=B9f2EL$)JwB!Sa2Dmci#529t$2uyc!~{J#yDPMAAbJKmsGc3sX8Wxuo_2Dg3?%z z(-^=7tir|LdmGPbW)=IH?+hxHz%(YYh=X{7y?BrEpLc9Wjj)I+Db>M6l!-W|a0&-- z2W17v*n$@r!Yh=Zhu`PVNTzy4Y5W6aAzw&;mF8u4C8LS@JAB@TRyQtbGURL7EBRUy zW%-0u_7hYy#cC^E$bBs(9frM2?ajZED|$!1$4qE;W?r9gvUV|7$m^4KF`J56hH2^? zmK8J2l$F$tgkkWaK9}9fx&PiXM)hGMW+YO>3Gdb4R^t?0+sPFiFB;gb&)E63O?!>Z Ytm_>Hmd=7>S}nh}o!EN8^{lF!Z$+0)Z~y=R diff --git a/apps/document_comments/locale/es/LC_MESSAGES/django.po b/apps/document_comments/locale/es/LC_MESSAGES/django.po index 233ac4ce9e..76f340a6fb 100644 --- a/apps/document_comments/locale/es/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/es/LC_MESSAGES/django.po @@ -1,101 +1,98 @@ # 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: \n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 04:34+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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:15 -msgid "Create new comments" -msgstr "Crear nuevos comentarios" - -#: __init__.py:16 -msgid "Delete comments" -msgstr "Eliminar comentarios" - -#: __init__.py:17 -msgid "Edit comments" -msgstr "Editar los comentarios" - -#: __init__.py:18 -msgid "View comments" -msgstr "Ver comentarios" - -#: __init__.py:20 -msgid "Comments" -msgstr "Comentarios" - -#: __init__.py:26 __init__.py:27 +#: __init__.py:19 __init__.py:20 msgid "delete" msgstr "eliminar" -#: __init__.py:28 +#: __init__.py:21 msgid "add comment" msgstr "añadir comentario" -#: __init__.py:29 utils.py:14 +#: __init__.py:22 msgid "comments" msgstr "comentarios" -#: __init__.py:33 +#: __init__.py:26 msgid "date" msgstr "fecha" -#: __init__.py:37 +#: __init__.py:30 msgid "user" msgstr "usuario" -#: __init__.py:41 +#: __init__.py:34 msgid "comment" msgstr "comentario" -#: views.py:27 +#: permissions.py:7 +msgid "Comments" +msgstr "Comentarios" + +#: permissions.py:9 +msgid "Create new comments" +msgstr "Crear nuevos comentarios" + +#: permissions.py:10 +msgid "Delete comments" +msgstr "Eliminar comentarios" + +#: permissions.py:11 +msgid "View comments" +msgstr "Ver comentarios" + +#: views.py:36 msgid "Must provide at least one comment." msgstr "Debe proveer al menos un comentario." -#: views.py:37 +#: views.py:46 #, python-format msgid "Comment \"%s\" deleted successfully." msgstr "Comentario \"%s\" eliminado exitosamente." -#: views.py:39 +#: views.py:48 #, python-format msgid "Error deleting comment \"%(comment)s\": %(error)s" msgstr "Error al eliminar el comentario \" %(comment)s\": %(error)s " -#: views.py:54 +#: views.py:63 #, python-format msgid "Are you sure you wish to delete the comment: %s?" msgstr "¿Está seguro que desea eliminar el comentario:% s?" -#: views.py:56 +#: views.py:65 #, python-format msgid "Are you sure you wish to delete the comments: %s?" msgstr "¿Está seguro que desea eliminar los comentarios:% s?" -#: views.py:86 +#: views.py:99 msgid "Comment added successfully." msgstr "Comentario añadido exitosamente." -#: views.py:93 +#: views.py:106 #, python-format msgid "Add comment to document: %s" msgstr "Añadir comentario al documento: %s" -#: views.py:109 +#: views.py:126 #, python-format msgid "comments: %s" msgstr "comentarios: %s" + + diff --git a/apps/document_comments/locale/it/LC_MESSAGES/django.mo b/apps/document_comments/locale/it/LC_MESSAGES/django.mo index f30ca8e21693b68036674450b3ad9a5439726b70..1fbae45066ce0540d56e3cb460771c86aa7ee55f 100644 GIT binary patch delta 544 zcmX}nze@sP7{KxO%zjySmJJaWn$%FBon{z^Ly=HKP&fx+afDDFs6p5<(~W8``mNSJ#R;E>(#G-_g1l{h*_dZ%n^GUH`Wsdv4tjn zVjK;RQW4xhd4GZWv$7b>B&!?oVpxT5!|HPL_0&4su+kkn?xH44|wDf>ZU^C{G5V*Iu;W z#;eEB))G-uu5dhQ#Zyr;X_~%+{b<&{$d~d?A)3jRZ7ZBG@MryVwXt%O&cy6X2zdoQz8c`*^~<|!|v7;W<#!fa^AzHoRyo~ zo|J=fY4D!FIew z6JOB6u7FZ;Orh-WU=i#^mwE0h|-72g8(vcAA>d_w74O%oX~hEbJQs;~T@)EFk&m_zwsALYek zfBzJv!IkeF%770j13vrpSL9Nk+?cPtC#M@D8_E9>C~j)CQ}X)~(p}C\n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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" @@ -18,84 +18,80 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:15 -msgid "Create new comments" -msgstr "Crea nuovo commento" - -#: __init__.py:16 -msgid "Delete comments" -msgstr "Cancella commenti" - -#: __init__.py:17 -msgid "Edit comments" -msgstr "Modifica commenti" - -#: __init__.py:18 -msgid "View comments" -msgstr "Visualizza commenti" - -#: __init__.py:20 -msgid "Comments" -msgstr "Commenti" - -#: __init__.py:26 __init__.py:27 +#: __init__.py:19 __init__.py:20 msgid "delete" msgstr "cancella" -#: __init__.py:28 +#: __init__.py:21 msgid "add comment" msgstr "aggiungi commento" -#: __init__.py:29 utils.py:14 +#: __init__.py:22 msgid "comments" msgstr "commenti" -#: __init__.py:33 +#: __init__.py:26 msgid "date" msgstr "data" -#: __init__.py:37 +#: __init__.py:30 msgid "user" msgstr "utente" -#: __init__.py:41 +#: __init__.py:34 msgid "comment" msgstr "commento" -#: views.py:27 +#: permissions.py:7 +msgid "Comments" +msgstr "Commenti" + +#: permissions.py:9 +msgid "Create new comments" +msgstr "Crea nuovo commento" + +#: permissions.py:10 +msgid "Delete comments" +msgstr "Cancella commenti" + +#: permissions.py:11 +msgid "View comments" +msgstr "Visualizza commenti" + +#: views.py:36 msgid "Must provide at least one comment." msgstr "Devi almeno fornire un commento" -#: views.py:37 +#: views.py:46 #, python-format msgid "Comment \"%s\" deleted successfully." msgstr "Commento \"%s\" cancellato con sucesso." -#: views.py:39 +#: views.py:48 #, python-format msgid "Error deleting comment \"%(comment)s\": %(error)s" msgstr "Erroro nel cancellare il commento \"%(comment)s\": %(error)s" -#: views.py:54 +#: views.py:63 #, python-format msgid "Are you sure you wish to delete the comment: %s?" msgstr "Sei sicuro di voler cancellare questo commento: %s?" -#: views.py:56 +#: views.py:65 #, python-format msgid "Are you sure you wish to delete the comments: %s?" msgstr "Sei sicuro di voler cancellare questi commenti: %s?" -#: views.py:86 +#: views.py:99 msgid "Comment added successfully." msgstr "Commento aggiunto con successo." -#: views.py:93 +#: views.py:106 #, python-format msgid "Add comment to document: %s" msgstr "Aggiungi un comento al documento: %s" -#: views.py:109 +#: views.py:126 #, python-format msgid "comments: %s" msgstr "commenti: %s" diff --git a/apps/document_comments/locale/pt/LC_MESSAGES/django.mo b/apps/document_comments/locale/pt/LC_MESSAGES/django.mo index 83bf515a70dcd2412d672fa4c76bd549f28f5dde..570fe8c0fc7c14f00778317265be864c77ecc052 100644 GIT binary patch delta 621 zcmX}oO-mb56oBCyo%#_w@v~q_3u%NPN-~oWR7Mvq3biz)BCg!%RfZTaGht@3(1p4Y zx*xhI_zT3Hy4FHBrCqoc)F0r+O`)4Y`<^s-$jNi(+?jLF%pdb0wSPBcd{)FT`GPzn zUy_vsf5auG@hjSRi$zRzD3!(6DEph(gZn7GK4Cu|p@k=y#Tzv7FZOY}GCP&(rtlo4 z!7F@<6KLQxcHvz6dLFMCVi9xHvrm*N<2#(fJ(T)6j^PbTKWQ=wCXQeZ%W6%jSr+3I z8aRMo@EIN>6RJy;20z>T*C>PCqYVClGWc&~uGXG>fkCoAt|!uOlB^`;F6kssF;%NO z52+ziLQdzc9;264iZtWziC^)Lj;r@uQPglOt6Gb;nj3{pzitJ7sDqjxSarRlJ*yUm zO*c#~eO$@U2d<84zL#Ink?UkicCnPV<(Dazo#J$S(V716SebE3_M}ZDD>{twD}naH zZ5{c6lUepR+#vF?by8+7_+Kcrk1kYwZ&z=-yYZ;89v>R3eHHCho4U%OjniA>Z6coO G`t}dh31N}| delta 613 zcmZ9|&npCB7{Kv&cgL^YwSGr_wNX+GGh^G$rX-YuB5}dNl%XwlwX)H>>!tY+=y#z z!y7d41x@VqE7gUwDC;g(;vP2O0oLFtR$~DN@d~@}>$jd)9Ra066#B3N6DW;FF^p5F z;R2T9V(Hn&V}@D79_qm|rDAAe9M@3lhuDo5DE*$W1wXJ+<&}!iRVMC6X^_BP+`wAg z$0j^M8MJ`X=(4nahce(J$_AcMHt>ebS6q|RttX}5-|%~zzR;L-m5{IGtfULm75_q$ z;&hfzw-1i<>P362J|NV4uc4l55&pLK4l}YOpcFsvgEyFZ*F3XCV zX3~o5M$9mHQJ-^mQtrR^jA4Dqh+1aSjCrqt=2mCZ$-0@eo3XQw8y#77b_Pl%&(K!F d({_4&+g|4{TRCq}TRQvHCVd*y*j|76?GN9{Q_27U diff --git a/apps/document_comments/locale/pt/LC_MESSAGES/django.po b/apps/document_comments/locale/pt/LC_MESSAGES/django.po index 8a190abb59..e06675dd45 100644 --- a/apps/document_comments/locale/pt/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/pt/LC_MESSAGES/django.po @@ -1,102 +1,99 @@ # 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-09-30 21:14+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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:15 -msgid "Create new comments" -msgstr "Criar novos comentários" - -#: __init__.py:16 -msgid "Delete comments" -msgstr "Excluir comentários" - -#: __init__.py:17 -msgid "Edit comments" -msgstr "Editar comentários" - -#: __init__.py:18 -msgid "View comments" -msgstr "Ver comentários" - -#: __init__.py:20 -msgid "Comments" -msgstr "Comentários" - -#: __init__.py:26 __init__.py:27 +#: __init__.py:19 __init__.py:20 msgid "delete" msgstr "excluir" -#: __init__.py:28 +#: __init__.py:21 msgid "add comment" msgstr "adicionar comentário" -#: __init__.py:29 utils.py:14 +#: __init__.py:22 msgid "comments" msgstr "comentários" -#: __init__.py:33 +#: __init__.py:26 msgid "date" msgstr "data" -#: __init__.py:37 +#: __init__.py:30 msgid "user" msgstr "usuário" -#: __init__.py:41 +#: __init__.py:34 msgid "comment" msgstr "comentário" -#: views.py:27 +#: permissions.py:7 +msgid "Comments" +msgstr "Comentários" + +#: permissions.py:9 +msgid "Create new comments" +msgstr "Criar novos comentários" + +#: permissions.py:10 +msgid "Delete comments" +msgstr "Excluir comentários" + +#: permissions.py:11 +msgid "View comments" +msgstr "Ver comentários" + +#: views.py:36 msgid "Must provide at least one comment." msgstr "Deve fornecer pelo menos um comentário." -#: views.py:37 +#: views.py:46 #, python-format msgid "Comment \"%s\" deleted successfully." msgstr "Comentário \"%s\" removido com sucesso." -#: views.py:39 +#: views.py:48 #, python-format msgid "Error deleting comment \"%(comment)s\": %(error)s" msgstr "Erro ao excluir comentário \"%(comment)s\": %(error)s" -#: views.py:54 +#: views.py:63 #, python-format msgid "Are you sure you wish to delete the comment: %s?" msgstr "Tem certeza de que deseja excluir o comentário: %s?" -#: views.py:56 +#: views.py:65 #, python-format msgid "Are you sure you wish to delete the comments: %s?" msgstr "Tem certeza de que deseja excluir os comentários: %s?" -#: views.py:86 +#: views.py:99 msgid "Comment added successfully." msgstr "Comentário adicionado com sucesso." -#: views.py:93 +#: views.py:106 #, python-format msgid "Add comment to document: %s" msgstr "Adicionar comentário ao documento: %s" -#: views.py:109 +#: views.py:126 #, python-format msgid "comments: %s" msgstr "comentários: %s" + + diff --git a/apps/document_comments/locale/ru/LC_MESSAGES/django.mo b/apps/document_comments/locale/ru/LC_MESSAGES/django.mo index b31ea9bdc2e3cf28f5c766ab87bfff9de0dd7c48..ade9d6c51b437ce29b0eadd1f4a9844828496ab2 100644 GIT binary patch delta 633 zcmX}oF>ljA6u|LI>e7-n4G9tg(h5_lqJR=R5hBRy(5fAfhy*HCQDH#W%5sbn8_v!^ zmkwQ6m@GEF0oj6BTf|g#;R8^_hv*Lf7otA-`DdSf_wL=t@?rVlcg6aoh^yp0`ITHC z+c|E;F;?+Ax_E{SoXabGUCTsZDNk_zJJ%8{}|Co0bzOlclVetF9Gzl8{-_8Vf6S zEB%jJtDwXclCCb|GEY*Wn4RR#v(x;~C!I8X>p4ykrk(z7eJ}1gCQh^oW8?JndmTAp zlJxzg@a*YUZQb}f4dbY`p;OR1uhh5oKR`MZ{VxCar=WKoCT%EX4mr3&F>}{bgo%U*4Nd&#ou=?A7)KQAXB~H)Jh2=io+2 ztj07N_=+ahIfbalF;vfEn2UQ@iU(MXCs>F#*pByDkDovLNm1((BA<;`%)xF{h5E4o zhf%{R%*L7DwS|u~vw%VNgIPjMjz#TT>3#tNMx>L5GntTAc#2mLG3}F?bXvm63R+jZ4D;^5? z{Dx`jTzrS4y&*5t>+)8f%GB9c_O|02WuRTz diff --git a/apps/document_comments/locale/ru/LC_MESSAGES/django.po b/apps/document_comments/locale/ru/LC_MESSAGES/django.po index 394a1bcad3..f05dc86d13 100644 --- a/apps/document_comments/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/ru/LC_MESSAGES/django.po @@ -1,103 +1,99 @@ # 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: \n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-11-19 20:58+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/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:15 -msgid "Create new comments" -msgstr "Создать новые комментарии" - -#: __init__.py:16 -msgid "Delete comments" -msgstr "Удалить комментарии" - -#: __init__.py:17 -msgid "Edit comments" -msgstr "Редактировать комментарии" - -#: __init__.py:18 -msgid "View comments" -msgstr "Просмотр комментариев" - -#: __init__.py:20 -msgid "Comments" -msgstr "Комментарии" - -#: __init__.py:26 __init__.py:27 +#: __init__.py:19 __init__.py:20 msgid "delete" msgstr "удалить" -#: __init__.py:28 +#: __init__.py:21 msgid "add comment" msgstr "добавить комментарий" -#: __init__.py:29 utils.py:14 +#: __init__.py:22 msgid "comments" msgstr "комментарии" -#: __init__.py:33 +#: __init__.py:26 msgid "date" msgstr "дата" -#: __init__.py:37 +#: __init__.py:30 msgid "user" msgstr "пользователь" -#: __init__.py:41 +#: __init__.py:34 msgid "comment" msgstr "комментарий" -#: views.py:27 +#: permissions.py:7 +msgid "Comments" +msgstr "Комментарии" + +#: permissions.py:9 +msgid "Create new comments" +msgstr "Создать новые комментарии" + +#: permissions.py:10 +msgid "Delete comments" +msgstr "Удалить комментарии" + +#: permissions.py:11 +msgid "View comments" +msgstr "Просмотр комментариев" + +#: views.py:36 msgid "Must provide at least one comment." msgstr "Должен быть хотя бы один комментарий." -#: views.py:37 +#: views.py:46 #, python-format msgid "Comment \"%s\" deleted successfully." msgstr "Комментарий \"%s\" удален." -#: views.py:39 +#: views.py:48 #, python-format msgid "Error deleting comment \"%(comment)s\": %(error)s" msgstr "Ошибка при удалении комментариев \"%(comment)s\": %(error)s" -#: views.py:54 +#: views.py:63 #, python-format msgid "Are you sure you wish to delete the comment: %s?" msgstr "Вы действительно хотите удалить комментарий %s?" -#: views.py:56 +#: views.py:65 #, python-format msgid "Are you sure you wish to delete the comments: %s?" msgstr "Вы действительно хотите удалить комментарии %s?" -#: views.py:86 +#: views.py:99 msgid "Comment added successfully." msgstr "Комментарий добавлен." -#: views.py:93 +#: views.py:106 #, python-format msgid "Add comment to document: %s" msgstr "Добавить комментарий на документ: %s" -#: views.py:109 +#: views.py:126 #, python-format msgid "comments: %s" msgstr "комментарии: %s" + + diff --git a/apps/document_indexing/locale/en/LC_MESSAGES/django.po b/apps/document_indexing/locale/en/LC_MESSAGES/django.po index 58bc82a104..c01c807d4a 100644 --- a/apps/document_indexing/locale/en/LC_MESSAGES/django.po +++ b/apps/document_indexing/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,183 +17,342 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:12 -msgid "View document indexes" -msgstr "" - -#: __init__.py:13 -msgid "Rebuild document indexes" -msgstr "" - -#: __init__.py:15 -msgid "Indexing" -msgstr "" - -#: __init__.py:19 -msgid "index list" -msgstr "" - -#: __init__.py:20 -msgid "go up one level" -msgstr "" - -#: __init__.py:21 __init__.py:23 models.py:26 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 +#: views.py:282 msgid "indexes" msgstr "" -#: __init__.py:25 +#: __init__.py:32 __init__.py:42 +msgid "index list" +msgstr "" + +#: __init__.py:33 views.py:76 +msgid "create index" +msgstr "" + +#: __init__.py:34 __init__.py:39 +msgid "edit" +msgstr "" + +#: __init__.py:35 __init__.py:40 +msgid "delete" +msgstr "" + +#: __init__.py:36 +msgid "tree template" +msgstr "" + +#: __init__.py:38 +msgid "new child node" +msgstr "" + +#: __init__.py:44 +msgid "go up one level" +msgstr "" + +#: __init__.py:49 msgid "rebuild indexes" msgstr "" -#: __init__.py:25 +#: __init__.py:49 msgid "Deletes and creates from scratch all the document indexes." msgstr "" -#: __init__.py:27 +#: __init__.py:51 msgid "Indexes" msgstr "" -#: api.py:83 -msgid "root" -msgstr "" - -#: api.py:139 +#: api.py:71 #, python-format msgid "Maximum suffix (%s) count reached." msgstr "" -#: api.py:175 +#: api.py:85 #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" msgstr "" -#: api.py:178 +#: api.py:97 api.py:112 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" msgstr "" -#: api.py:209 +#: api.py:151 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "" -#: filesystem.py:34 +#: filesystem.py:51 #, python-format msgid "Unable to create indexing directory; %s" msgstr "" -#: filesystem.py:52 +#: filesystem.py:69 #, python-format msgid "" "Unable to create symbolic link, file exists and could not be deleted: " "%(filepath)s; %(exc)s" msgstr "" -#: filesystem.py:54 +#: filesystem.py:71 #, python-format msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" msgstr "" -#: filesystem.py:71 +#: filesystem.py:84 #, python-format msgid "Unable to delete document symbolic link; %s" msgstr "" -#: filesystem.py:83 +#: filesystem.py:96 #, python-format msgid "Unable to delete indexing directory; %s" msgstr "" -#: models.py:11 +#: models.py:13 #, python-format msgid "Available functions: %s" msgstr "" -#: models.py:16 -msgid "indexing expression" +#: models.py:17 views.py:42 +msgid "name" msgstr "" -#: models.py:16 -msgid "Enter a python string expression to be evaluated." +#: models.py:17 +msgid "Internal name used to reference this index." +msgstr "" + +#: models.py:18 views.py:43 +msgid "title" msgstr "" #: models.py:18 +msgid "The name that will be visible to users." +msgstr "" + +#: models.py:19 models.py:50 msgid "enabled" msgstr "" #: models.py:19 -msgid "link documents" +msgid "Causes this index to be visible and updated when document data changes." msgstr "" -#: models.py:25 models.py:31 views.py:56 +#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 +#: views.py:197 views.py:227 views.py:267 msgid "index" msgstr "" -#: models.py:32 +#: models.py:48 +msgid "indexing expression" +msgstr "" + +#: models.py:48 +msgid "Enter a python string expression to be evaluated." +msgstr "" + +#: models.py:50 +msgid "Causes this node to be visible and updated when document data changes." +msgstr "" + +#: models.py:51 +msgid "link documents" +msgstr "" + +#: models.py:51 +msgid "" +"Check this option to have this node act as a container for documents and not " +"as a parent for further nodes." +msgstr "" + +#: models.py:57 models.py:63 +msgid "index template node" +msgstr "" + +#: models.py:58 +msgid "indexes template nodes" +msgstr "" + +#: models.py:64 msgid "value" msgstr "" -#: models.py:33 +#: models.py:65 msgid "documents" msgstr "" -#: models.py:46 models.py:51 +#: models.py:75 +msgid "index instance node" +msgstr "" + +#: models.py:76 +msgid "indexes instance nodes" +msgstr "" + +#: models.py:80 msgid "index instance" msgstr "" -#: models.py:47 -msgid "indexes instances" -msgstr "" - -#: models.py:52 +#: models.py:81 msgid "document" msgstr "" -#: models.py:59 +#: models.py:88 msgid "document rename count" msgstr "" -#: models.py:60 +#: models.py:89 msgid "documents rename count" msgstr "" +#: permissions.py:7 +msgid "Indexing" +msgstr "" + +#: permissions.py:9 +msgid "Configure document indexes" +msgstr "" + +#: permissions.py:10 +msgid "Create new document indexes" +msgstr "" + +#: permissions.py:11 +msgid "Edit document indexes" +msgstr "" + +#: permissions.py:12 +msgid "Delete document indexes" +msgstr "" + +#: permissions.py:14 +msgid "View document indexes" +msgstr "" + +#: permissions.py:15 +msgid "Rebuild document indexes" +msgstr "" + #: utils.py:19 msgid "document indexes" msgstr "" -#: views.py:38 +#: views.py:70 +msgid "Index created successfully." +msgstr "" + +#: views.py:94 +msgid "Index edited successfully" +msgstr "" + +#: views.py:100 +#, python-format +msgid "edit index: %s" +msgstr "" + +#: views.py:125 +#, python-format +msgid "Index: %s deleted successfully." +msgstr "" + +#: views.py:127 +#, python-format +msgid "Index: %(index)s delete error: %(error)s" +msgstr "" + +#: views.py:139 +#, python-format +msgid "Are you sure you with to delete the index: %s?" +msgstr "" + +#: views.py:164 +#, python-format +msgid "tree template nodes for index: %s" +msgstr "" + +#: views.py:167 +msgid "level" +msgstr "" + +#: views.py:188 +msgid "Index template node created successfully." +msgstr "" + +#: views.py:194 +msgid "create child node" +msgstr "" + +#: views.py:215 +msgid "Index template node edited successfully" +msgstr "" + +#: views.py:221 +#, python-format +msgid "edit index template node: %s" +msgstr "" + +#: views.py:228 views.py:268 views.py:336 +msgid "node" +msgstr "" + +#: views.py:250 +#, python-format +msgid "Node: %s deleted successfully." +msgstr "" + +#: views.py:252 +#, python-format +msgid "Node: %(node)s delete error: %(error)s" +msgstr "" + +#: views.py:261 +#, python-format +msgid "Are you sure you with to delete the index template node: %s?" +msgstr "" + +#: views.py:285 +msgid "nodes" +msgstr "" + +#: views.py:318 #, python-format msgid "contents for index: %s" msgstr "" -#: views.py:60 +#: views.py:340 msgid "items" msgstr "" -#: views.py:82 +#: views.py:365 msgid "Are you sure you wish to rebuild all indexes?" msgstr "" -#: views.py:83 +#: views.py:366 msgid "On large databases this operation may take some time to execute." msgstr "" -#: views.py:89 +#: views.py:372 msgid "Index rebuild completed successfully." msgstr "" -#: views.py:94 +#: views.py:377 #, python-format msgid "Index rebuild error: %s" msgstr "" -#: views.py:109 +#: views.py:399 #, python-format msgid "indexes containing: %s" msgstr "" +#: conf/settings.py:22 +msgid "" +"A dictionary that maps the index name and where on the filesystem that index " +"will be mirrored." +msgstr "" + #: templates/indexing_help.html:3 msgid "What are indexes?" msgstr "" diff --git a/apps/document_indexing/locale/es/LC_MESSAGES/django.mo b/apps/document_indexing/locale/es/LC_MESSAGES/django.mo index d52ef7c7cdc091e7a6aa3665f769cd470bb16945..d364289b69a33d4b32d4cbfcd0db05f1d3013fb4 100644 GIT binary patch literal 6325 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, 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 17: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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:36+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 "View document indexes" -msgstr "Ver los índices de documentos" - -#: __init__.py:13 -msgid "Rebuild document indexes" -msgstr "Generar índices de documentos" - -#: __init__.py:15 -msgid "Indexing" -msgstr "Indexación" - -#: __init__.py:19 -msgid "index list" -msgstr "lista de indices" - -#: __init__.py:20 -msgid "go up one level" -msgstr "subir un nivel" - -#: __init__.py:21 __init__.py:23 models.py:26 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 +#: views.py:282 msgid "indexes" msgstr "índices" -#: __init__.py:25 +#: __init__.py:32 __init__.py:42 +msgid "index list" +msgstr "lista de indices" + +#: __init__.py:33 views.py:76 +msgid "create index" +msgstr "crear índice" + +#: __init__.py:34 __init__.py:39 +msgid "edit" +msgstr "editar" + +#: __init__.py:35 __init__.py:40 +msgid "delete" +msgstr "borrar" + +#: __init__.py:36 +msgid "tree template" +msgstr "plantilla de árbol " + +#: __init__.py:38 +msgid "new child node" +msgstr "nuevo nodo secundario" + +#: __init__.py:44 +msgid "go up one level" +msgstr "subir un nivel" + +#: __init__.py:49 msgid "rebuild indexes" msgstr "generar índices" -#: __init__.py:25 +#: __init__.py:49 msgid "Deletes and creates from scratch all the document indexes." msgstr "Borra y crea de la nada todos los índices de documentos." -#: __init__.py:27 +#: __init__.py:51 msgid "Indexes" msgstr "Índices" -#: api.py:83 -msgid "root" -msgstr "raíz" - -#: api.py:139 +#: api.py:71 #, python-format msgid "Maximum suffix (%s) count reached." msgstr "Cuenta máxima de sufijo (%s) alcanzada." -#: api.py:175 +#: api.py:85 #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" @@ -72,7 +76,7 @@ msgstr "" "Error en la expresión de actualización de indexación: %(expression)s; " "%(exception)s " -#: api.py:178 +#: api.py:97 api.py:112 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -80,17 +84,17 @@ msgstr "" "Error actualizando el indice de documento, expresión: %(expression)s; " "%(exception)s " -#: api.py:209 +#: api.py:151 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "No se puede eliminar el nodo de indexación de documento; %s" -#: filesystem.py:34 +#: filesystem.py:51 #, python-format msgid "Unable to create indexing directory; %s" msgstr "No se puede crear el directorio de indexación; %s" -#: filesystem.py:52 +#: filesystem.py:69 #, python-format msgid "" "Unable to create symbolic link, file exists and could not be deleted: " @@ -99,111 +103,272 @@ msgstr "" "No se puede crear un enlace simbólico, el archivo existe y no puede " "eliminarse: %(filepath)s; %(exc)s " -#: filesystem.py:54 +#: filesystem.py:71 #, python-format msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" msgstr "No se puede crear enlace simbólico: %(filepath)s; %(exc)s " -#: filesystem.py:71 +#: filesystem.py:84 #, python-format msgid "Unable to delete document symbolic link; %s" msgstr "No se puede eliminar vínculo simbólico de documento; %s" -#: filesystem.py:83 +#: filesystem.py:96 #, python-format msgid "Unable to delete indexing directory; %s" msgstr "No se puede eliminar el directorio de indexación; %s" -#: models.py:11 +#: models.py:13 #, python-format msgid "Available functions: %s" msgstr "Funciones disponibles: %s" -#: models.py:16 -msgid "indexing expression" -msgstr "expresión de indexación" +#: models.py:17 views.py:42 +msgid "name" +msgstr "nombre" -#: models.py:16 -msgid "Enter a python string expression to be evaluated." -msgstr "Introduzca una expresión de python para ser evaluada." +#: models.py:17 +msgid "Internal name used to reference this index." +msgstr "Nombre interno que se utiliza para hacer referencia a este índice." + +#: models.py:18 views.py:43 +msgid "title" +msgstr "título" #: models.py:18 +msgid "The name that will be visible to users." +msgstr "El nombre que será visible para los usuarios." + +#: models.py:19 models.py:50 msgid "enabled" msgstr "habilitado" #: models.py:19 -msgid "link documents" -msgstr "enlace de documentos" +msgid "" +"Causes this index to be visible and updated when document data changes." +msgstr "" +"Hace que este índice sea visible y actualizado cuando los datos de " +"documentos cambien." -#: models.py:25 models.py:31 views.py:56 +#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 +#: views.py:197 views.py:227 views.py:267 msgid "index" msgstr "índice" -#: models.py:32 +#: models.py:48 +msgid "indexing expression" +msgstr "expresión de indexación" + +#: models.py:48 +msgid "Enter a python string expression to be evaluated." +msgstr "Introduzca una expresión de python para ser evaluada." + +#: models.py:50 +msgid "Causes this node to be visible and updated when document data changes." +msgstr "" +"Causa que este nodo sea visible y actualizado cuando los datos de los " +"documentos son cambiados." + +#: models.py:51 +msgid "link documents" +msgstr "enlace de documentos" + +#: models.py:51 +msgid "" +"Check this option to have this node act as a container for documents and not" +" as a parent for further nodes." +msgstr "" +"Marque esta opción para que el nodo actue como un contenedor de documentos y" +" no como un padre para mas nodos secundarios." + +#: models.py:57 models.py:63 +msgid "index template node" +msgstr "" + +#: models.py:58 +msgid "indexes template nodes" +msgstr "" + +#: models.py:64 msgid "value" msgstr "valor" -#: models.py:33 +#: models.py:65 msgid "documents" msgstr "documentos" -#: models.py:46 models.py:51 +#: models.py:75 +msgid "index instance node" +msgstr "" + +#: models.py:76 +msgid "indexes instance nodes" +msgstr "" + +#: models.py:80 msgid "index instance" msgstr "instancia de indice" -#: models.py:47 -msgid "indexes instances" -msgstr "instancias de indices" - -#: models.py:52 +#: models.py:81 msgid "document" msgstr "documento" -#: models.py:59 +#: models.py:88 msgid "document rename count" msgstr "conteo de cambio de nombre de documento" -#: models.py:60 +#: models.py:89 msgid "documents rename count" msgstr "conteos de cambio de nombre de documentos" +#: permissions.py:7 +msgid "Indexing" +msgstr "Indexación" + +#: permissions.py:9 +msgid "Configure document indexes" +msgstr "Configurar índices de documento" + +#: permissions.py:10 +msgid "Create new document indexes" +msgstr "Crear nuevos índices de documentos" + +#: permissions.py:11 +msgid "Edit document indexes" +msgstr "Editar los índices de documentos" + +#: permissions.py:12 +msgid "Delete document indexes" +msgstr "Eliminar los índices de documentos" + +#: permissions.py:14 +msgid "View document indexes" +msgstr "Ver los índices de documentos" + +#: permissions.py:15 +msgid "Rebuild document indexes" +msgstr "Generar índices de documentos" + #: utils.py:19 msgid "document indexes" msgstr "indices de documentos" -#: views.py:38 +#: views.py:70 +msgid "Index created successfully." +msgstr "Índice creado con exitosamente." + +#: views.py:94 +msgid "Index edited successfully" +msgstr "Índice editado con exitosamente." + +#: views.py:100 +#, python-format +msgid "edit index: %s" +msgstr "editar Índice: %s" + +#: views.py:125 +#, python-format +msgid "Index: %s deleted successfully." +msgstr "Índice: %s eliminado exitosamente." + +#: views.py:127 +#, python-format +msgid "Index: %(index)s delete error: %(error)s" +msgstr "Error al borrar índice: %(index)s, error: %(error)s " + +#: views.py:139 +#, python-format +msgid "Are you sure you with to delete the index: %s?" +msgstr "¿Seguro que desea eliminar el índice: %s?" + +#: views.py:164 +#, python-format +msgid "tree template nodes for index: %s" +msgstr "nodos de la plantilla del árbol del índice: %s" + +#: views.py:167 +msgid "level" +msgstr "nivel" + +#: views.py:188 +msgid "Index template node created successfully." +msgstr "" + +#: views.py:194 +msgid "create child node" +msgstr "" + +#: views.py:215 +msgid "Index template node edited successfully" +msgstr "" + +#: views.py:221 +#, python-format +msgid "edit index template node: %s" +msgstr "" + +#: views.py:228 views.py:268 views.py:336 +msgid "node" +msgstr "nodo" + +#: views.py:250 +#, python-format +msgid "Node: %s deleted successfully." +msgstr "" + +#: views.py:252 +#, python-format +msgid "Node: %(node)s delete error: %(error)s" +msgstr "" + +#: views.py:261 +#, python-format +msgid "Are you sure you with to delete the index template node: %s?" +msgstr "" + +#: views.py:285 +msgid "nodes" +msgstr "nodos" + +#: views.py:318 #, python-format msgid "contents for index: %s" msgstr "contenido del indice: %s" -#: views.py:60 +#: views.py:340 msgid "items" msgstr "artículos" -#: views.py:82 +#: views.py:365 msgid "Are you sure you wish to rebuild all indexes?" msgstr "¿Está seguro que desea reconstruir todos los índices?" -#: views.py:83 +#: views.py:366 msgid "On large databases this operation may take some time to execute." msgstr "" -"En bases de datos de gran tamaño esta operación puede tardar algún tiempo en " -"ejecutarse." +"En bases de datos de gran tamaño esta operación puede tardar algún tiempo en" +" ejecutarse." -#: views.py:89 +#: views.py:372 msgid "Index rebuild completed successfully." msgstr "Reconstrucción de Índices completada exitosamente." -#: views.py:94 +#: views.py:377 #, python-format msgid "Index rebuild error: %s" msgstr "Error de reconstrucción de índices: %s" -#: views.py:109 +#: views.py:399 #, python-format msgid "indexes containing: %s" msgstr "índices que contienen: %s" +#: conf/settings.py:22 +msgid "" +"A dictionary that maps the index name and where on the filesystem that index" +" will be mirrored." +msgstr "" + #: templates/indexing_help.html:3 msgid "What are indexes?" msgstr "¿Que son los índices?" @@ -212,3 +377,5 @@ msgstr "¿Que son los índices?" msgid "Indexes group documents into a tree like hierarchical structure." msgstr "" "Los índices agrupan documentos en una estructura jerárquica tipo árbol. " + + diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.mo b/apps/document_indexing/locale/it/LC_MESSAGES/django.mo index d7c013bab800dc10ec6cb977e3c21738d76f085e..16406cd1096d26c2a2dbe37bdc7f7a36ec75bf12 100644 GIT binary patch delta 918 zcmX}qKWGzC9Ki8kn%E}w&(&%Zt(H5Ln5J?y2`Q$jsGyWW{S)G(PA8rUi_NA3tE zP2EYo5E2=|r)@Np`LKwMcQJvlu!zf;#oma>I3C9_oW~@7L5=TNM@18lU<#vn33rP$ zkC?*mcn;(3B17ooK78Er18SU(-UI!(84qC`OQ?w^unRAv#$Cf0&S9MV z@_-i}c}8R4b0oLC$4$6|ow$NLvPz=~)^H0NWYPFNsPSpkaSE;eFZZ~)&TiLdvOhQD@~TG-)YqE5_aQR)Co@_ zp;AZYB-dO0w+z;|osKy=G~ohrZ{#)VS-wNPM9ZiH{W5|#ZM}V(OHab2T2w9UMY9B< zaH2=yDb4wBrFt=T=?6tunp(UOeiR8tqxql_y*iY$Gx}KB zd@*~#&g3(h&eAEn>`qsvDqhV#=G5JymCI!R#}$g%LSV-d>9Tj;_3NHh_NE-a;#mj% hX2+o4>=>NzYBNsNomspXn{5wPjnR&2r|S8x`~@q}a2o&s delta 976 zcmXxiJ7`l;7{Ku_kGAO}X>9Gw8gs2QsV&#$291~stq!)JP*FQbLAbUVB57_&f2-Zc^ML}sNK^(+Pt`*cpQ2$@O9&+yQyzcqV`EGv4UmNw$J;B>T znV{~ZR(&E<_}h3-yq1J-?%_GuXWk=WrXI!+tEG2D*Y#yn(vzKDOgC z>?gjwqQOr-^617d$Qfi4Blr_Lu!Y@dN)$D~AZox#?8PIf?=7Idw}`sm1tcj_^XBWg zL6$G$IPqnH-Sy_HsHwk$)A#{TV_&C;jd`5JcQ}r}kR(W=OQeV5e-hw7-;7!yNw(%h~R3`Um)3t~%wcaWbDPmu#ot7)R~GvRyO|m;R6JJHIv3$h2Q-jpQ|CEl2F- U{8HY1(mmUyk>#RYaLPIP3mjf~RsaA1 diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.po b/apps/document_indexing/locale/it/LC_MESSAGES/django.po index acac9a45c9..f0d1e65bcb 100644 --- a/apps/document_indexing/locale/it/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-10 07:01+0000\n" -"Last-Translator: Pierpaolo Baldan \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,52 +18,57 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:12 -msgid "View document indexes" -msgstr "Visualizza indici documento" - -#: __init__.py:13 -msgid "Rebuild document indexes" -msgstr "Ricostruisci indici documento" - -#: __init__.py:15 -msgid "Indexing" -msgstr "Indicizzazione" - -#: __init__.py:19 -msgid "index list" -msgstr "lista indici" - -#: __init__.py:20 -msgid "go up one level" -msgstr "sali di un livello" - -#: __init__.py:21 __init__.py:23 models.py:26 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 +#: views.py:282 msgid "indexes" msgstr "indici" -#: __init__.py:25 +#: __init__.py:32 __init__.py:42 +msgid "index list" +msgstr "lista indici" + +#: __init__.py:33 views.py:76 +msgid "create index" +msgstr "" + +#: __init__.py:34 __init__.py:39 +msgid "edit" +msgstr "" + +#: __init__.py:35 __init__.py:40 +msgid "delete" +msgstr "" + +#: __init__.py:36 +msgid "tree template" +msgstr "" + +#: __init__.py:38 +msgid "new child node" +msgstr "" + +#: __init__.py:44 +msgid "go up one level" +msgstr "sali di un livello" + +#: __init__.py:49 msgid "rebuild indexes" msgstr "ricostruisci gli indici" -#: __init__.py:25 +#: __init__.py:49 msgid "Deletes and creates from scratch all the document indexes." msgstr "Cancellazione e ricostruzione di tutti gli indici documento" -#: __init__.py:27 +#: __init__.py:51 msgid "Indexes" msgstr "Indici" -#: api.py:83 -msgid "root" -msgstr "root" - -#: api.py:139 +#: api.py:71 #, python-format msgid "Maximum suffix (%s) count reached." msgstr "Massimo dei suffissi contati (%s) ." -#: api.py:175 +#: api.py:85 #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" @@ -71,7 +76,7 @@ msgstr "" "Errore nella creazione dell'indice per l'espressione: %(expression)s; " "%(exception)s" -#: api.py:178 +#: api.py:97 api.py:112 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -79,17 +84,17 @@ msgstr "" "Errore nell'aggiornamento delle'indice documento per l'espressione: " "%(expression)s; %(exception)s" -#: api.py:209 +#: api.py:151 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "Impossibile cancellare l'indice del documento; %s" -#: filesystem.py:34 +#: filesystem.py:51 #, python-format msgid "Unable to create indexing directory; %s" msgstr "Impossibile creare la directory per gli indici; %s" -#: filesystem.py:52 +#: filesystem.py:69 #, python-format msgid "" "Unable to create symbolic link, file exists and could not be deleted: " @@ -98,111 +103,266 @@ msgstr "" "Impossibile creare un link simbolico, il file già esiste e non può essere " "cancellato: %(filepath)s; %(exc)s" -#: filesystem.py:54 +#: filesystem.py:71 #, python-format msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" msgstr "Impossibile creare un link simbolico: %(filepath)s; %(exc)s" -#: filesystem.py:71 +#: filesystem.py:84 #, python-format msgid "Unable to delete document symbolic link; %s" msgstr "Impossibile cancellare il link simbolico al documento; %s" -#: filesystem.py:83 +#: filesystem.py:96 #, python-format msgid "Unable to delete indexing directory; %s" msgstr "Impossibile cancellare la directory degli indici; %s" -#: models.py:11 +#: models.py:13 #, python-format msgid "Available functions: %s" msgstr "Funzioni disponibili: %s" -#: models.py:16 -msgid "indexing expression" -msgstr "Espressione per indice" +#: models.py:17 views.py:42 +msgid "name" +msgstr "" -#: models.py:16 -msgid "Enter a python string expression to be evaluated." -msgstr "Inserisci una espressione python perchè possa essere valutata." +#: models.py:17 +msgid "Internal name used to reference this index." +msgstr "" + +#: models.py:18 views.py:43 +msgid "title" +msgstr "" #: models.py:18 +msgid "The name that will be visible to users." +msgstr "" + +#: models.py:19 models.py:50 msgid "enabled" msgstr "abilitato" #: models.py:19 -msgid "link documents" -msgstr "link al documento" +msgid "" +"Causes this index to be visible and updated when document data changes." +msgstr "" -#: models.py:25 models.py:31 views.py:56 +#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 +#: views.py:197 views.py:227 views.py:267 msgid "index" msgstr "indice" -#: models.py:32 +#: models.py:48 +msgid "indexing expression" +msgstr "Espressione per indice" + +#: models.py:48 +msgid "Enter a python string expression to be evaluated." +msgstr "Inserisci una espressione python perchè possa essere valutata." + +#: models.py:50 +msgid "Causes this node to be visible and updated when document data changes." +msgstr "" + +#: models.py:51 +msgid "link documents" +msgstr "link al documento" + +#: models.py:51 +msgid "" +"Check this option to have this node act as a container for documents and not" +" as a parent for further nodes." +msgstr "" + +#: models.py:57 models.py:63 +msgid "index template node" +msgstr "" + +#: models.py:58 +msgid "indexes template nodes" +msgstr "" + +#: models.py:64 msgid "value" msgstr "valore" -#: models.py:33 +#: models.py:65 msgid "documents" msgstr "documenti" -#: models.py:46 models.py:51 +#: models.py:75 +msgid "index instance node" +msgstr "" + +#: models.py:76 +msgid "indexes instance nodes" +msgstr "" + +#: models.py:80 msgid "index instance" msgstr "istanza indice" -#: models.py:47 -msgid "indexes instances" -msgstr "istanze indici" - -#: models.py:52 +#: models.py:81 msgid "document" msgstr "document" -#: models.py:59 +#: models.py:88 msgid "document rename count" msgstr "conteggio della rinomina del documento" -#: models.py:60 +#: models.py:89 msgid "documents rename count" msgstr "conteggio delle rinomine dei documenti" +#: permissions.py:7 +msgid "Indexing" +msgstr "Indicizzazione" + +#: permissions.py:9 +msgid "Configure document indexes" +msgstr "" + +#: permissions.py:10 +msgid "Create new document indexes" +msgstr "" + +#: permissions.py:11 +msgid "Edit document indexes" +msgstr "" + +#: permissions.py:12 +msgid "Delete document indexes" +msgstr "" + +#: permissions.py:14 +msgid "View document indexes" +msgstr "Visualizza indici documento" + +#: permissions.py:15 +msgid "Rebuild document indexes" +msgstr "Ricostruisci indici documento" + #: utils.py:19 msgid "document indexes" msgstr "indici dei documenti" -#: views.py:38 +#: views.py:70 +msgid "Index created successfully." +msgstr "" + +#: views.py:94 +msgid "Index edited successfully" +msgstr "" + +#: views.py:100 +#, python-format +msgid "edit index: %s" +msgstr "" + +#: views.py:125 +#, python-format +msgid "Index: %s deleted successfully." +msgstr "" + +#: views.py:127 +#, python-format +msgid "Index: %(index)s delete error: %(error)s" +msgstr "" + +#: views.py:139 +#, python-format +msgid "Are you sure you with to delete the index: %s?" +msgstr "" + +#: views.py:164 +#, python-format +msgid "tree template nodes for index: %s" +msgstr "" + +#: views.py:167 +msgid "level" +msgstr "" + +#: views.py:188 +msgid "Index template node created successfully." +msgstr "" + +#: views.py:194 +msgid "create child node" +msgstr "" + +#: views.py:215 +msgid "Index template node edited successfully" +msgstr "" + +#: views.py:221 +#, python-format +msgid "edit index template node: %s" +msgstr "" + +#: views.py:228 views.py:268 views.py:336 +msgid "node" +msgstr "" + +#: views.py:250 +#, python-format +msgid "Node: %s deleted successfully." +msgstr "" + +#: views.py:252 +#, python-format +msgid "Node: %(node)s delete error: %(error)s" +msgstr "" + +#: views.py:261 +#, python-format +msgid "Are you sure you with to delete the index template node: %s?" +msgstr "" + +#: views.py:285 +msgid "nodes" +msgstr "" + +#: views.py:318 #, python-format msgid "contents for index: %s" msgstr "contenuto per indice: %s" -#: views.py:60 +#: views.py:340 msgid "items" msgstr "voci" -#: views.py:82 +#: views.py:365 msgid "Are you sure you wish to rebuild all indexes?" msgstr "Sei sicuro di voler ricostruire l'indice ?" -#: views.py:83 +#: views.py:366 msgid "On large databases this operation may take some time to execute." msgstr "" "Per un database di grosse dimensioni l'operazione protrebbe aver bisogno di " "tempo." -#: views.py:89 +#: views.py:372 msgid "Index rebuild completed successfully." msgstr "Ricostruzione dell'indice avvenuta con successo" -#: views.py:94 +#: views.py:377 #, python-format msgid "Index rebuild error: %s" msgstr "Errore nella ricostruzione dell'indice: %s" -#: views.py:109 +#: views.py:399 #, python-format msgid "indexes containing: %s" msgstr "Gli indici contengono: %s" +#: conf/settings.py:22 +msgid "" +"A dictionary that maps the index name and where on the filesystem that index" +" will be mirrored." +msgstr "" + #: templates/indexing_help.html:3 msgid "What are indexes?" msgstr "Cosa sono gli indici ?" diff --git a/apps/document_indexing/locale/pt/LC_MESSAGES/django.mo b/apps/document_indexing/locale/pt/LC_MESSAGES/django.mo index 3039293cfc66ef1337f9ce01e5dac90d65c32ab1..19b351c41bcb5688b0bd858866c3876d1c848f38 100644 GIT binary patch delta 994 zcmX}qUr19?9Ki82r?$;%rTHh9cq?q0Yy5Q{ z6{&}^hjQ7Y)F3{sp&~7Mm5ShfY{gfY!VQdLd#zHVIEEv*h+X&*W&D;p3U=ZUhS7&v z+^1AYU8%mfgKfN6#V~%ybJ$X^)FHI77av!BhcZrPZ-#E%iAS*oCs6`ra0kw!jJt_` zyoW8sR}X2B)ibIfzC>cHH@F?&V*o!PS^c1r0Kc&bgG7<>`%%XCpv;r3_K)Bir+NyL z^mj8^2sIufzPdrf#1*`N-|#$+Hz*auC)kA_kU5lRE60ril%1SGxgw1dxPW_c0~6@k zrqm1$;Bj2WA^eP`BQy@O>;cSTJ1(Kz-3oT#DoUVVC`b4gWkF4BleMY=4C8S1Igey@ zjY>}J7B=Dn%2h0(Y@{4i(aMA`=-5riTa=^xS{?Wkck%4yE9q}@U)O{>4$zWmJ1GW5 z5=XO{T#vW4S$<|VUr7>3Hqqrqyq%tIcibD6P?al?#mGrXl7BB;zU^JEbx->G-I8x` zH0wCCDbvj4ob23m^pZ7W+E!89ImHb2#o5P51E(`dGnHR(X1ku z*28TOE-IpxLb*tYHZ3B8pjt%Os%Q}{tX&`fGtTAR`@8quH}~9o?%XprjKb&oz=}|! z)O}R9Ok@CG`)DZ7{30>jz-Ii4CjP?&ngNlsn8q=DhMibezVm$qcQYQsVI0LEF5v-@ zg4`)htYZrkzc7N;yF{k34}0-0>Ly>6+(!M*VD&~E!#cc#O*oGl=r-2kGU|8tF@#UC ziTLt@4v&1KslhE|5AqYM@i$grIjhl?TGRk7r~$ii500Sz?mX)6rcu|sh9pH6OY;R> zCCj()IPs;6)!T3ehwvtL<0f9lA9xWb!Xj~ejGg!iSwno4BI6iFJ=q1+E1SVdT*m#l zg~!lWC6YlC3nO$M(iz6@cmktrzaLY$7gtg5eiPgAJ!+tB)Rg{3-B1I^Wv^ml1kaSl z8RU^0G@8LBtjFaVnJC`PDlhaT>!=Gp#|C_dt@sT!wLUIV?=ncE^R1|+)j$Nb3>CdLtT3Gp9xWn}^pj z{s)1uoi|e1ylZ8z+Fn&~AmHS3t~VMSJXmpVaw>Mpu`M^1%f?Pyu5B90cp?$wNhXa% z!c6vgZ-Q+ni*MpRMm%Zu_DAECig7FN#-lw%o#JL4HU zo%i}eS1QM??A�jtKLvw-TCO`xE+5UT0_K)49AcYa1`0WM@-s@NLal*s)TJvS6ii Gj{FA->4wn& diff --git a/apps/document_indexing/locale/pt/LC_MESSAGES/django.po b/apps/document_indexing/locale/pt/LC_MESSAGES/django.po index f8dd4bf8c3..03a01c827f 100644 --- a/apps/document_indexing/locale/pt/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/pt/LC_MESSAGES/django.po @@ -1,70 +1,74 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # 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-03 02:59+0000\n" -"Last-Translator: renataoliveira \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-02 14:17-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" "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 "View document indexes" -msgstr "Ver índices de documento" - -#: __init__.py:13 -msgid "Rebuild document indexes" -msgstr "Reconstruir índices de documento" - -#: __init__.py:15 -msgid "Indexing" -msgstr "Indexando" - -#: __init__.py:19 -msgid "index list" -msgstr "lista de índice" - -#: __init__.py:20 -msgid "go up one level" -msgstr "subir um nível" - -#: __init__.py:21 __init__.py:23 models.py:26 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 +#: views.py:282 msgid "indexes" msgstr "índices" -#: __init__.py:25 +#: __init__.py:32 __init__.py:42 +msgid "index list" +msgstr "lista de índice" + +#: __init__.py:33 views.py:76 +msgid "create index" +msgstr "" + +#: __init__.py:34 __init__.py:39 +msgid "edit" +msgstr "" + +#: __init__.py:35 __init__.py:40 +msgid "delete" +msgstr "" + +#: __init__.py:36 +msgid "tree template" +msgstr "" + +#: __init__.py:38 +msgid "new child node" +msgstr "" + +#: __init__.py:44 +msgid "go up one level" +msgstr "subir um nível" + +#: __init__.py:49 msgid "rebuild indexes" msgstr "reconstruir índices" -#: __init__.py:25 +#: __init__.py:49 msgid "Deletes and creates from scratch all the document indexes." msgstr "Exclui e criar a partir do zero todos os índices de documento." -#: __init__.py:27 +#: __init__.py:51 msgid "Indexes" msgstr "Índices" -#: api.py:83 -msgid "root" -msgstr "raiz" - -#: api.py:139 +#: api.py:71 #, python-format msgid "Maximum suffix (%s) count reached." msgstr "Quantidade máxima do sufixo (%s) alcançada." -#: api.py:175 +#: api.py:85 #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" @@ -72,7 +76,7 @@ msgstr "" "Erro de atualização na expressão de indexação do documento: %(expression)s; " "%(exception)s " -#: api.py:178 +#: api.py:97 api.py:112 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -80,17 +84,17 @@ msgstr "" "Erro de atualização de índice do documento, a expressão: %(expression)s ; " "%(exception)s " -#: api.py:209 +#: api.py:151 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "Não é possível excluir o nó de indexação de documentos; %s" -#: filesystem.py:34 +#: filesystem.py:51 #, python-format msgid "Unable to create indexing directory; %s" msgstr "Não é possível criar o diretório de indexação; %s" -#: filesystem.py:52 +#: filesystem.py:69 #, python-format msgid "" "Unable to create symbolic link, file exists and could not be deleted: " @@ -99,110 +103,266 @@ msgstr "" "Não é possível criar o link simbólico, o arquivo existe e não pode ser " "excluído: %(filepath)s; %(exc)s " -#: filesystem.py:54 +#: filesystem.py:71 #, python-format msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" msgstr "Não é possível criar o link simbólico: %(filepath)s; %(exc)s " -#: filesystem.py:71 +#: filesystem.py:84 #, python-format msgid "Unable to delete document symbolic link; %s" msgstr "Não é possível excluir o link simbólico do documento; %s" -#: filesystem.py:83 +#: filesystem.py:96 #, python-format msgid "Unable to delete indexing directory; %s" msgstr "Não é possível excluir o diretório de indexação; %s" -#: models.py:11 +#: models.py:13 #, python-format msgid "Available functions: %s" msgstr "Funções disponíveis: %s " -#: models.py:16 -msgid "indexing expression" -msgstr "expressão de indexação" +#: models.py:17 views.py:42 +msgid "name" +msgstr "" -#: models.py:16 -msgid "Enter a python string expression to be evaluated." -msgstr "Digite uma expressão python para ser avaliada." +#: models.py:17 +msgid "Internal name used to reference this index." +msgstr "" + +#: models.py:18 views.py:43 +msgid "title" +msgstr "" #: models.py:18 +msgid "The name that will be visible to users." +msgstr "" + +#: models.py:19 models.py:50 msgid "enabled" msgstr "habilitado" #: models.py:19 -msgid "link documents" -msgstr "ligar documentos" +msgid "" +"Causes this index to be visible and updated when document data changes." +msgstr "" -#: models.py:25 models.py:31 views.py:56 +#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 +#: views.py:197 views.py:227 views.py:267 msgid "index" msgstr "índice" -#: models.py:32 +#: models.py:48 +msgid "indexing expression" +msgstr "expressão de indexação" + +#: models.py:48 +msgid "Enter a python string expression to be evaluated." +msgstr "Digite uma expressão python para ser avaliada." + +#: models.py:50 +msgid "Causes this node to be visible and updated when document data changes." +msgstr "" + +#: models.py:51 +msgid "link documents" +msgstr "ligar documentos" + +#: models.py:51 +msgid "" +"Check this option to have this node act as a container for documents and not" +" as a parent for further nodes." +msgstr "" + +#: models.py:57 models.py:63 +msgid "index template node" +msgstr "" + +#: models.py:58 +msgid "indexes template nodes" +msgstr "" + +#: models.py:64 msgid "value" msgstr "valor" -#: models.py:33 +#: models.py:65 msgid "documents" msgstr "documentos" -#: models.py:46 models.py:51 +#: models.py:75 +msgid "index instance node" +msgstr "" + +#: models.py:76 +msgid "indexes instance nodes" +msgstr "" + +#: models.py:80 msgid "index instance" msgstr "exemplo de índice" -#: models.py:47 -msgid "indexes instances" -msgstr "exemplos de índices" - -#: models.py:52 +#: models.py:81 msgid "document" msgstr "documento" -#: models.py:59 +#: models.py:88 msgid "document rename count" msgstr "contagem de renomeação do documento" -#: models.py:60 +#: models.py:89 msgid "documents rename count" msgstr "contagem de renomeação dos documentos" +#: permissions.py:7 +msgid "Indexing" +msgstr "Indexando" + +#: permissions.py:9 +msgid "Configure document indexes" +msgstr "" + +#: permissions.py:10 +msgid "Create new document indexes" +msgstr "" + +#: permissions.py:11 +msgid "Edit document indexes" +msgstr "" + +#: permissions.py:12 +msgid "Delete document indexes" +msgstr "" + +#: permissions.py:14 +msgid "View document indexes" +msgstr "Ver índices de documento" + +#: permissions.py:15 +msgid "Rebuild document indexes" +msgstr "Reconstruir índices de documento" + #: utils.py:19 msgid "document indexes" msgstr "índices de documento" -#: views.py:38 +#: views.py:70 +msgid "Index created successfully." +msgstr "" + +#: views.py:94 +msgid "Index edited successfully" +msgstr "" + +#: views.py:100 +#, python-format +msgid "edit index: %s" +msgstr "" + +#: views.py:125 +#, python-format +msgid "Index: %s deleted successfully." +msgstr "" + +#: views.py:127 +#, python-format +msgid "Index: %(index)s delete error: %(error)s" +msgstr "" + +#: views.py:139 +#, python-format +msgid "Are you sure you with to delete the index: %s?" +msgstr "" + +#: views.py:164 +#, python-format +msgid "tree template nodes for index: %s" +msgstr "" + +#: views.py:167 +msgid "level" +msgstr "" + +#: views.py:188 +msgid "Index template node created successfully." +msgstr "" + +#: views.py:194 +msgid "create child node" +msgstr "" + +#: views.py:215 +msgid "Index template node edited successfully" +msgstr "" + +#: views.py:221 +#, python-format +msgid "edit index template node: %s" +msgstr "" + +#: views.py:228 views.py:268 views.py:336 +msgid "node" +msgstr "" + +#: views.py:250 +#, python-format +msgid "Node: %s deleted successfully." +msgstr "" + +#: views.py:252 +#, python-format +msgid "Node: %(node)s delete error: %(error)s" +msgstr "" + +#: views.py:261 +#, python-format +msgid "Are you sure you with to delete the index template node: %s?" +msgstr "" + +#: views.py:285 +msgid "nodes" +msgstr "" + +#: views.py:318 #, python-format msgid "contents for index: %s" msgstr "conteúdos para o índice: %s" -#: views.py:60 +#: views.py:340 msgid "items" msgstr "itens" -#: views.py:82 +#: views.py:365 msgid "Are you sure you wish to rebuild all indexes?" msgstr "Tem certeza de que deseja reconstruir todos os índices?" -#: views.py:83 +#: views.py:366 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." +"Em grandes bases de dados esta operação pode levar algum tempo para " +"executar." -#: views.py:89 +#: views.py:372 msgid "Index rebuild completed successfully." msgstr "Reconstrução de índice concluída com êxito." -#: views.py:94 +#: views.py:377 #, python-format msgid "Index rebuild error: %s" msgstr "Reconstrução de índice de erro: %s" -#: views.py:109 +#: views.py:399 #, python-format msgid "indexes containing: %s" msgstr "índices contendo: %s" +#: conf/settings.py:22 +msgid "" +"A dictionary that maps the index name and where on the filesystem that index" +" will be mirrored." +msgstr "" + #: templates/indexing_help.html:3 msgid "What are indexes?" msgstr "Quais são os índices?" @@ -211,3 +371,5 @@ msgstr "Quais são os índices?" msgid "Indexes group documents into a tree like hierarchical structure." msgstr "" "Indexar documentos agrupados em uma árvore como uma estrutura hierárquica." + + diff --git a/apps/document_indexing/locale/ru/LC_MESSAGES/django.mo b/apps/document_indexing/locale/ru/LC_MESSAGES/django.mo index 59a1601a1a751b53a0d61bda250f98b07c96d8d4..3c66adf6c69cdd836ccc90e3e1a1454a14b179ca 100644 GIT binary patch delta 1031 zcmX}qK}b|V7{Kw-wc6b*&BZk}aZ7AhZyIqY>1lC<`h)_WyEen3><~ym|A@e)Hx-H$vHsl7hR6 zQb#*LyOgI?J1*waQD$9AX?PFI@D)b!14gi-K&fu*!7iM|TKtHze%B5fR$~l<=*Cez zq*PX2$vv3H{XBSwLHv$G=-;W-5j3$L7jnKuStq-fLJ0R^2l}xeB~Sv3aRO!Cb@bp2 z`iZaR7*N$JT@k)SVk-yt;(PSsXQZkhbP`|-eON>kSzm*)z7A!dw%mLd2FT_qJj=Yn zW`}VNhlsDfF}R2)cPll83wRZ43YF@^Ic&k7C;>uyl$yj=lq-9Lr|}I=V}M05T)|%a zgAcKjQw`&0&H>Vr)ny?Axx+H@*Nh`riL)5SCnzcWgf;jZJFvV&DXKb87sJcB--{?$ z^#VDw`ici}3uWI5(k6eT#mDv`2FIBYQz$RYpuF$^HC#hEz%QTuI=`YyvL`oDO$*SZ zkhAS#=ef#Cy%1MXR+nS9M;?iZ@cCT>=W*0JL_)m z9<{8AXgHimTBDiah7n^tY#M3ZOd4i*T%Xia;bc0UiKo5&eS_LDGp<`nBc*lfRy-PL zYK$~#jZy=V=4hnV-f&l*`#;kbjkMJ_QoKES+R_G1J(V8QEyIik28`jjX&Lx0QsAh$ zJ<*U0-Hta|_EMn*yyJJugYlLW2 zR8Ac_bSOwcItVI0%A{L|h?zqW6=EHdZXK#am-_y6|IB|r^MC#RuNn4D_);r{&PR$= zPu@m0GL&k@cbU9M^A4r_xPWE2h7tUSL5w(+I);7NhVxj98Ce_sy||h3L5yN6x^NVC zD3wwV(hW0MPQ!2XV%{dDx-g7QIEJ#ww`qT&^wWr5f^ArU-B^m3Q6?I}e7uj+?shGG1MGEqgYQdiN3a)r;UqS(y3_?eR{0PQb51&rqui;B?KNU2R^lyez~?AO`T=Y3J03t!p;A2R zD6c4FeHcawd@fzSi8Am7%D@Hm$G!WQ{C|Gh9!#=GV-!5?PG|l*BctDsr8f>!{AyW%?c7irtiDVX{k^ zP?G$dzUh9)gflyq)OzDdLyupKnYpfJXJTN$Fk4+MJ3S{lI{k+eG2Q4Li2IM|Ml7O* z0>Pl4Clu0x!AK}>>NMX3bkm l)(n-4_6=*w>@OOvTC`r\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-02 14:17-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" "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 "View document indexes" -msgstr "Просмотр индексов документа" - -#: __init__.py:13 -msgid "Rebuild document indexes" -msgstr "Восстановление индексов документа" - -#: __init__.py:15 -msgid "Indexing" -msgstr "Индексирование" - -#: __init__.py:19 -msgid "index list" -msgstr "список индекса" - -#: __init__.py:20 -msgid "go up one level" -msgstr "перейти на уровень выше" - -#: __init__.py:21 __init__.py:23 models.py:26 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 +#: views.py:282 msgid "indexes" msgstr "индексы" -#: __init__.py:25 +#: __init__.py:32 __init__.py:42 +msgid "index list" +msgstr "список индекса" + +#: __init__.py:33 views.py:76 +msgid "create index" +msgstr "" + +#: __init__.py:34 __init__.py:39 +msgid "edit" +msgstr "" + +#: __init__.py:35 __init__.py:40 +msgid "delete" +msgstr "" + +#: __init__.py:36 +msgid "tree template" +msgstr "" + +#: __init__.py:38 +msgid "new child node" +msgstr "" + +#: __init__.py:44 +msgid "go up one level" +msgstr "перейти на уровень выше" + +#: __init__.py:49 msgid "rebuild indexes" msgstr "восстановление индексов" -#: __init__.py:25 +#: __init__.py:49 msgid "Deletes and creates from scratch all the document indexes." msgstr "Удаляет и создается с нуля, все индексы документа." -#: __init__.py:27 +#: __init__.py:51 msgid "Indexes" msgstr "Индексы" -#: api.py:83 -msgid "root" -msgstr "корень" - -#: api.py:139 +#: api.py:71 #, python-format msgid "Maximum suffix (%s) count reached." msgstr "Достигнуто максимальное (%s) число суффиксов " -#: api.py:175 +#: api.py:85 #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" @@ -72,7 +75,7 @@ msgstr "" "Ошибка в выражении обновления индексов документа: %(expression)s; " "%(exception)s" -#: api.py:178 +#: api.py:97 api.py:112 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -80,17 +83,17 @@ msgstr "" "Ошибка при обновлении индекса документа, выражение: %(expression)s; " "%(exception)s" -#: api.py:209 +#: api.py:151 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "Не удается удалить узел индексирования документов; %s." -#: filesystem.py:34 +#: filesystem.py:51 #, python-format msgid "Unable to create indexing directory; %s" msgstr "Не удается создать индексации каталога; %s." -#: filesystem.py:52 +#: filesystem.py:69 #, python-format msgid "" "Unable to create symbolic link, file exists and could not be deleted: " @@ -99,111 +102,266 @@ msgstr "" "Невозможно создать символическую ссылку, файл существует и не может быть " "удален: %(filepath)s; %(exc)s" -#: filesystem.py:54 +#: filesystem.py:71 #, python-format msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" msgstr "Невозможно создать символическую ссылку: %(filepath)s; %(exc)s" -#: filesystem.py:71 +#: filesystem.py:84 #, python-format msgid "Unable to delete document symbolic link; %s" msgstr "Не удается удалить символическую ссылку документа;%s." -#: filesystem.py:83 +#: filesystem.py:96 #, python-format msgid "Unable to delete indexing directory; %s" msgstr "Не удается удалить каталог индексации; %s." -#: models.py:11 +#: models.py:13 #, python-format msgid "Available functions: %s" msgstr "Доступные функции: %s." -#: models.py:16 -msgid "indexing expression" -msgstr "выражение индексации " +#: models.py:17 views.py:42 +msgid "name" +msgstr "" -#: models.py:16 -msgid "Enter a python string expression to be evaluated." -msgstr "Введите строковое выражение питона для вычисления." +#: models.py:17 +msgid "Internal name used to reference this index." +msgstr "" + +#: models.py:18 views.py:43 +msgid "title" +msgstr "" #: models.py:18 +msgid "The name that will be visible to users." +msgstr "" + +#: models.py:19 models.py:50 msgid "enabled" msgstr "разрешено" #: models.py:19 -msgid "link documents" -msgstr "связать документы" +msgid "" +"Causes this index to be visible and updated when document data changes." +msgstr "" -#: models.py:25 models.py:31 views.py:56 +#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 +#: views.py:197 views.py:227 views.py:267 msgid "index" msgstr "индекс" -#: models.py:32 +#: models.py:48 +msgid "indexing expression" +msgstr "выражение индексации " + +#: models.py:48 +msgid "Enter a python string expression to be evaluated." +msgstr "Введите строковое выражение питона для вычисления." + +#: models.py:50 +msgid "Causes this node to be visible and updated when document data changes." +msgstr "" + +#: models.py:51 +msgid "link documents" +msgstr "связать документы" + +#: models.py:51 +msgid "" +"Check this option to have this node act as a container for documents and not" +" as a parent for further nodes." +msgstr "" + +#: models.py:57 models.py:63 +msgid "index template node" +msgstr "" + +#: models.py:58 +msgid "indexes template nodes" +msgstr "" + +#: models.py:64 msgid "value" msgstr "значение" -#: models.py:33 +#: models.py:65 msgid "documents" msgstr "документы" -#: models.py:46 models.py:51 +#: models.py:75 +msgid "index instance node" +msgstr "" + +#: models.py:76 +msgid "indexes instance nodes" +msgstr "" + +#: models.py:80 msgid "index instance" msgstr "экземпляр индекса" -#: models.py:47 -msgid "indexes instances" -msgstr "экземпляры индекса" - -#: models.py:52 +#: models.py:81 msgid "document" msgstr "документ" -#: models.py:59 +#: models.py:88 msgid "document rename count" msgstr "счетчик переименования документа" -#: models.py:60 +#: models.py:89 msgid "documents rename count" msgstr "счетчик переименования документов" +#: permissions.py:7 +msgid "Indexing" +msgstr "Индексирование" + +#: permissions.py:9 +msgid "Configure document indexes" +msgstr "" + +#: permissions.py:10 +msgid "Create new document indexes" +msgstr "" + +#: permissions.py:11 +msgid "Edit document indexes" +msgstr "" + +#: permissions.py:12 +msgid "Delete document indexes" +msgstr "" + +#: permissions.py:14 +msgid "View document indexes" +msgstr "Просмотр индексов документа" + +#: permissions.py:15 +msgid "Rebuild document indexes" +msgstr "Восстановление индексов документа" + #: utils.py:19 msgid "document indexes" msgstr "индексы документов" -#: views.py:38 +#: views.py:70 +msgid "Index created successfully." +msgstr "" + +#: views.py:94 +msgid "Index edited successfully" +msgstr "" + +#: views.py:100 +#, python-format +msgid "edit index: %s" +msgstr "" + +#: views.py:125 +#, python-format +msgid "Index: %s deleted successfully." +msgstr "" + +#: views.py:127 +#, python-format +msgid "Index: %(index)s delete error: %(error)s" +msgstr "" + +#: views.py:139 +#, python-format +msgid "Are you sure you with to delete the index: %s?" +msgstr "" + +#: views.py:164 +#, python-format +msgid "tree template nodes for index: %s" +msgstr "" + +#: views.py:167 +msgid "level" +msgstr "" + +#: views.py:188 +msgid "Index template node created successfully." +msgstr "" + +#: views.py:194 +msgid "create child node" +msgstr "" + +#: views.py:215 +msgid "Index template node edited successfully" +msgstr "" + +#: views.py:221 +#, python-format +msgid "edit index template node: %s" +msgstr "" + +#: views.py:228 views.py:268 views.py:336 +msgid "node" +msgstr "" + +#: views.py:250 +#, python-format +msgid "Node: %s deleted successfully." +msgstr "" + +#: views.py:252 +#, python-format +msgid "Node: %(node)s delete error: %(error)s" +msgstr "" + +#: views.py:261 +#, python-format +msgid "Are you sure you with to delete the index template node: %s?" +msgstr "" + +#: views.py:285 +msgid "nodes" +msgstr "" + +#: views.py:318 #, python-format msgid "contents for index: %s" msgstr "содержания для индекса: %s." -#: views.py:60 +#: views.py:340 msgid "items" msgstr "членов" -#: views.py:82 +#: views.py:365 msgid "Are you sure you wish to rebuild all indexes?" msgstr "Вы уверены, что хотите перестроить все индексы?" -#: views.py:83 +#: views.py:366 msgid "On large databases this operation may take some time to execute." msgstr "" "В больших базах данных эта операция может занять некоторое время для " "выполнения." -#: views.py:89 +#: views.py:372 msgid "Index rebuild completed successfully." msgstr "восстановление индекса успешно завершено." -#: views.py:94 +#: views.py:377 #, python-format msgid "Index rebuild error: %s" msgstr "Индекс восстановить ошибка: %s" -#: views.py:109 +#: views.py:399 #, python-format msgid "indexes containing: %s" msgstr "индексы, содержащие: %s" +#: conf/settings.py:22 +msgid "" +"A dictionary that maps the index name and where on the filesystem that index" +" will be mirrored." +msgstr "" + #: templates/indexing_help.html:3 msgid "What are indexes?" msgstr "что за индексы?" @@ -211,3 +369,5 @@ msgstr "что за индексы?" #: templates/indexing_help.html:4 msgid "Indexes group documents into a tree like hierarchical structure." msgstr "Индексы группы документов в древовидной иерархической структуре." + + diff --git a/apps/document_signatures/locale/en/LC_MESSAGES/django.po b/apps/document_signatures/locale/en/LC_MESSAGES/django.po index f2c2ac4175..c20bb776e9 100644 --- a/apps/document_signatures/locale/en/LC_MESSAGES/django.po +++ b/apps/document_signatures/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: 2012-01-01 20:14-0400\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,15 +17,15 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:50 +#: __init__.py:83 msgid "upload signature" msgstr "" -#: __init__.py:51 +#: __init__.py:84 msgid "download signature" msgstr "" -#: __init__.py:52 +#: __init__.py:85 msgid "signatures" msgstr "" @@ -33,40 +33,40 @@ msgstr "" msgid "Signature file" msgstr "" -#: models.py:19 -msgid "document version" -msgstr "" - #: models.py:20 -msgid "signature state" +msgid "document version" msgstr "" #: models.py:21 msgid "signature file" msgstr "" -#: models.py:26 +#: models.py:22 +msgid "has embedded signature" +msgstr "" + +#: models.py:35 msgid "document version signature" msgstr "" -#: models.py:27 +#: models.py:36 msgid "document version signatures" msgstr "" #: permissions.py:7 -msgid "Verify document signatures" +msgid "Document signatures" msgstr "" #: permissions.py:8 -msgid "Upload detached signatures" +msgid "Verify document signatures" msgstr "" #: permissions.py:9 -msgid "Download detached signatures" +msgid "Upload detached signatures" msgstr "" -#: permissions.py:12 -msgid "Document signatures" +#: permissions.py:10 +msgid "Download detached signatures" msgstr "" #: views.py:47 @@ -112,11 +112,11 @@ msgstr "" msgid "signature properties for: %s" msgstr "" -#: views.py:92 +#: views.py:96 msgid "Detached signature uploaded successfully." msgstr "" -#: views.py:101 +#: views.py:105 #, python-format msgid "Upload detached signature for: %s" msgstr "" diff --git a/apps/document_signatures/locale/es/LC_MESSAGES/django.mo b/apps/document_signatures/locale/es/LC_MESSAGES/django.mo index a1ea5d8bfc37c6c5e11dab0de8e70f53bbf16e4d..809b0a7cd65170f646edc2d848fa525fb8dd239f 100644 GIT binary patch delta 704 zcmXZXK~EDw6bJBGDIhC>DgsfI3?UI3+3vOyLsn`GqVYguQ<`w_G^N9KOm}88Gi#Mg zjh}#I<5%$Hjf08tZn&8E0W`*oCyyq2^S>=~`OSNI^WMDIv+s*1p9TwrkndxJ%)meJ z1}qc^ap4Lq!VUP-A*2RZ5Yq`luEHI-2oK;DsLp)@^LKCI8hi&Y!!K|e{(y7v_XHV` zC0v}zQQ{_CMqGiYAq|*+@Brq6CAMUQ30vYi$zxek5!+ZI=&K>}zG17E1eZ{?-@9q}*gl z;rgKJ1yx$v3@ck+uo(nykXD0AUNo%R3hxBB0~~jc8SAw)lcvY4 z(jjfCHrH0c;V8PTM~U+J>~f^!G3)W;2T{yKFaOqkckdaKQOY9jwK$7Ix}Pv9OqZ@d zM0?Q_OqS^S`8xf6zijh?;)uU2OK$x{tLOaC8b2BBODHT*48CmsnJU5G#x*6rmf(T(<7l{MziI~?YZIA5R( zV=slmp86N`B3^PU^=Kh~f)}q|^ys07g5QO@E#G@#i#0MAu_Pui+h> zg4q-noQ2bH0ah5%dpM8$Bu(@Z{)7d14xhunBd=ic?iMb=|L_@H$Pi7!5AX%lGIUCF zID8&mM6ihb8${4AY^sy zffE$}W;vFRhiruv;(u(8(O~Aukj3|7YZ)F!GIC;`D(%~e>hQ|soua?SUwS>S?DZPs?Qm@(vy4nz?B{Y@q zS&CVGduY}4tRcfl*n#YY9U1w7!gpGR!E36i^9|ipt42lDw1(bnZlbj3_ND6x+mT&` z8)|L0mCUzc7?qB<><8{<{5|aqikSh6Z^p}u4*t^idE4O~$-j6(SJLAiQrJK8g3;9j D1eItH diff --git a/apps/document_signatures/locale/es/LC_MESSAGES/django.po b/apps/document_signatures/locale/es/LC_MESSAGES/django.po index 45c95e124d..9b61d43a02 100644 --- a/apps/document_signatures/locale/es/LC_MESSAGES/django.po +++ b/apps/document_signatures/locale/es/LC_MESSAGES/django.po @@ -1,31 +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. -# FIRST AUTHOR , YEAR. # -#, fuzzy +# Translators: +# Roberto Rosario , 2012. msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-01 20:14-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:30+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: \n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:50 +#: __init__.py:83 msgid "upload signature" msgstr "subir firma" -#: __init__.py:51 +#: __init__.py:84 msgid "download signature" msgstr "descargar firma" -#: __init__.py:52 +#: __init__.py:85 msgid "signatures" msgstr "firmas" @@ -33,42 +34,42 @@ msgstr "firmas" msgid "Signature file" msgstr "Archivo de firma" -#: models.py:19 +#: models.py:20 msgid "document version" msgstr "versión del documento" -#: models.py:20 -msgid "signature state" -msgstr "estado de la firma" - #: models.py:21 msgid "signature file" msgstr "archivo de firma" -#: models.py:26 +#: models.py:22 +msgid "has embedded signature" +msgstr "tiene firma integrada" + +#: models.py:35 msgid "document version signature" msgstr "firma de la versión de documento" -#: models.py:27 +#: models.py:36 msgid "document version signatures" msgstr "firmas de las versiónes de documentos" #: permissions.py:7 +msgid "Document signatures" +msgstr "Firmas de documentos" + +#: permissions.py:8 msgid "Verify document signatures" msgstr "Verificar firmas de documentos" -#: permissions.py:8 +#: permissions.py:9 msgid "Upload detached signatures" msgstr "Subir firmas aparte" -#: permissions.py:9 +#: permissions.py:10 msgid "Download detached signatures" msgstr "Descargar firmas aparte" -#: permissions.py:12 -msgid "Document signatures" -msgstr "Firmas de documentos" - #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" @@ -112,12 +113,13 @@ msgstr "Firmante: %s" msgid "signature properties for: %s" msgstr "propiedades de la firma para: %s" -#: views.py:92 +#: views.py:96 msgid "Detached signature uploaded successfully." msgstr "Firma aparte subida exitosamente." -#: views.py:101 +#: views.py:105 #, python-format msgid "Upload detached signature for: %s" msgstr "Subir firma aparte para: %s" + diff --git a/apps/document_signatures/locale/it/LC_MESSAGES/django.mo b/apps/document_signatures/locale/it/LC_MESSAGES/django.mo index dac760626fb3d11073e7722d8cfa25833fc1ad93..ca0e80de7c2286290884144057497791c2f51bce 100644 GIT binary patch delta 513 zcmZwC&q^FI90%}h{d1VAD6|w>sOiNjZ6-6z9%R}rh1!BpQFIU1TeNXDWhPmY-*#J} zEEGzQ7CiN4PkjKvlMmn%^x)km@CEwK>d_GRB;lLn_dA|Co&I$;{MTS?XN<80##lbV z*dw?Nry;>9_#Mu|L--UP!#Q{k6L_8E3_cB3{*79yjOul zXXup;l_KX0zUg+gCkICb@R$DjAib$5EuB43l|Fb~*2+||*jISQmVH%f(b1|d_$sN& zpufeNz6OIqO7Rb~ufL>Llk9o-N$*jRz1ZNKvO<5XgCty+hUC&wYg|7!lx$ReuPX7* e`8pKb_D0*#Zoc5x%l4w>Pue_RI{7{Rv+*C-`hzV1 delta 379 zcmYMuu}Z^09LMp0wRK2av4e|(-lT(^rlnITrDqds@sgA@6{qU=1ozhgok!1~1?iyn(y$0cPDR%(@R)gr5c4`FnVYi|pfXh@s*d(K@Uw zhPlm^c~7*@M8{y~hSTrbmg4wVQJiu!3BpT$JPQ);MjBIkw#(bG@1%r*39m~$hHhcdP&ONxZ_Qev6n`%#!d!O zGE0~SYZ#{J%9hY|$LRN)Xs5x<3w-YS-b7, YEAR. # -#, fuzzy +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-01 20:14-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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: \n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:50 +#: __init__.py:83 msgid "upload signature" msgstr "aggiorna firma" -#: __init__.py:51 +#: __init__.py:84 msgid "download signature" msgstr "scarica firma" -#: __init__.py:52 +#: __init__.py:85 msgid "signatures" msgstr "firma" @@ -33,42 +33,42 @@ msgstr "firma" msgid "Signature file" msgstr "File della firma" -#: models.py:19 -msgid "document version" -msgstr "" - #: models.py:20 -msgid "signature state" +msgid "document version" msgstr "" #: models.py:21 msgid "signature file" msgstr "file della firma" -#: models.py:26 +#: models.py:22 +msgid "has embedded signature" +msgstr "" + +#: models.py:35 msgid "document version signature" msgstr "" -#: models.py:27 +#: models.py:36 msgid "document version signatures" msgstr "" #: permissions.py:7 +msgid "Document signatures" +msgstr "" + +#: permissions.py:8 msgid "Verify document signatures" msgstr "Verifica la firma del documento" -#: permissions.py:8 +#: permissions.py:9 msgid "Upload detached signatures" msgstr "Carica firme separatamente" -#: permissions.py:9 +#: permissions.py:10 msgid "Download detached signatures" msgstr "Scarica firme separatamente" -#: permissions.py:12 -msgid "Document signatures" -msgstr "" - #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" @@ -112,12 +112,13 @@ msgstr "Signee: %s" msgid "signature properties for: %s" msgstr "Proprietà per la firma: %s" -#: views.py:92 +#: views.py:96 msgid "Detached signature uploaded successfully." msgstr "Firma scaduta aggiornata con successo." -#: views.py:101 +#: views.py:105 #, python-format msgid "Upload detached signature for: %s" msgstr "Aggiornata firma scaduta per: %s" + diff --git a/apps/document_signatures/locale/pt/LC_MESSAGES/django.mo b/apps/document_signatures/locale/pt/LC_MESSAGES/django.mo index d2c545543e992fcd36bfeb5b1608d23686098858..df072bfcdd2b8ee95db4c6a64c2986cc9160f2dd 100644 GIT binary patch delta 793 zcmXZXJ#P~+7zc1CB(yzV8VV_G0pU=fiOS_Jp%UdF2%%CjG!UiPkdWNeT(8QVPiG&2 zGUNlmcA_kN0K^6rFfg+rhAxPgvUM*jEc~6+lJ95x9zTzt?a>dp-tV!@3xY9$c^dN< z<^{}GDSR;OG$AEefyd!}sN)1Q;B%ORFX2)68tVHW;TYV3I&Kdhf&X9ujvOFlijW?e z9W2Nq9L5g@b;9-i^QZ6>_M1>Ad92T+P%MvmP zCl3;G7G8#z(X*PzdAu-IC+!0t5f#JM3PEhNuAufn*NbWrZY2l z>g)*%=hmjkY>FcRy$t)vwW+A;a6FD-=xR;a8}lFRZ-p)wksIAR@h iQAECUXb|?dvR1uD2g_P9poJQ(l(ypROgecxRQM0F2cC`q delta 704 zcmYMv&ubGw6u|LG+O%nkw#N7)RdKCWEi#gnqOgXNZL`MUW>b>1P(fj(O9;lS?rv1P zBWmwLH_kXDB1C z3>IP?lYF?3s^H_{{u4Y#`~p?MkErs#pt^7u)er6A6sAT87tWxnGlxZ*xrFD5A0`IP zKF5>XFW$3I2Y2uQ{=h@{7ggu!F(D3P0aYgrRGr+yv)Dlmqhb68Cy2jd2EXGh{=qYN zVti0<8IzKY4HoLc+jtrup*pyQllXcVe;ALR#q5bAY^jlre#I`wj&9G#cVc5&5IUh7 z{T|8pSB;hHM%mQX&3dC!vr~2Vp67?M8noJ*a=F(EWYg2N)M~9MSA5qA+g?|eIIL?6 zx%`66<#|}@`9+yq%;iXwb@xF#_@B378g*H%$&#U6tLfFsg&Q^7Oj%A4%BEj-x)h2f%dpF9>YodiRqV7cdVXsu fx|wjde, YEAR. # -#, fuzzy +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-01 20:14-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+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: \n" +"Language: pt\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:50 +#: __init__.py:83 msgid "upload signature" msgstr "upload do assinatura" -#: __init__.py:51 +#: __init__.py:84 msgid "download signature" msgstr "download do assinatura" -#: __init__.py:52 +#: __init__.py:85 msgid "signatures" msgstr "assinaturas" @@ -33,42 +33,42 @@ msgstr "assinaturas" msgid "Signature file" msgstr "Arquivo de assinatura" -#: models.py:19 +#: models.py:20 msgid "document version" msgstr "versão do documento" -#: models.py:20 -msgid "signature state" -msgstr "estado do assinatura" - #: models.py:21 msgid "signature file" msgstr "arquivo do assinatura" -#: models.py:26 +#: models.py:22 +msgid "has embedded signature" +msgstr "" + +#: models.py:35 msgid "document version signature" msgstr "assinatura do versão do documento" -#: models.py:27 +#: models.py:36 msgid "document version signatures" msgstr "assinaturas de versão de documentos" #: permissions.py:7 +msgid "Document signatures" +msgstr "Assinaturas de documentos" + +#: permissions.py:8 msgid "Verify document signatures" msgstr "Verificar as assinaturas de documentos" -#: permissions.py:8 +#: permissions.py:9 msgid "Upload detached signatures" msgstr "Upload de assinaturas destacadas" -#: permissions.py:9 +#: permissions.py:10 msgid "Download detached signatures" msgstr "Download assinaturas destacadas" -#: permissions.py:12 -msgid "Document signatures" -msgstr "Assinaturas de documentos" - #: views.py:47 #, python-format msgid "Signature status: %(widget)s %(text)s" @@ -112,12 +112,13 @@ msgstr "Signee: %s" msgid "signature properties for: %s" msgstr "propriedades da assinatura para: %s" -#: views.py:92 +#: views.py:96 msgid "Detached signature uploaded successfully." msgstr "Assinatura separado enviado com sucesso." -#: views.py:101 +#: views.py:105 #, python-format msgid "Upload detached signature for: %s" msgstr "Upload de assinatura separada para: %s" + diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.mo b/apps/document_signatures/locale/ru/LC_MESSAGES/django.mo index d0393e9f05a4ac3b6ee719e2404b1d02a4e2f9f4..5bc118cc1650a3c9fe0b907e77248b649d9c8fce 100644 GIT binary patch literal 2402 zcmai!%WoS+9LI;!Qes}EKzWPlAyuMky=y0k$c+PPok$T_M5)UK329@GovrL$YiG7; zN)Jtn;6P{u5^zCOMI1OrQB&NeO(djV(X7M?QT_lsa3g$=>fE`TGZ?`VI`l`XeCep9HA|RC9_C%V<2) zCfR_?XdJ*V%p?OTvnSdsstMI?XHcIhPLw7ZC|5L|Y?Eq-60qm-P`{`~G$__+6oj(N z^P<9~Q*&(<_<{$`x@T8tD=3$Rl+~bKUre)tR}LD&RUJu*y#<$qd1a3o$=(%ZG^2wvQ4)RP z;#JRou!LkE2;ZqL@=BkKcM@gE;W^<;$8+~=bn5hgBZ;$i36lme(U=nzG=L>rJgQP> z+4Q}p@RcKEl1_3cS=_)b|1-XKR+N=7T``avMVsSAd(n3JWTALEH7lB)uZ*IsIThn% zP?JW<%kg=onmN;~Ich$bOP9Td>3h=l9nUu#q-#1-212H0-Y*%ad|@k?H43&uH?meH zYgqKpGo!i8m|=}t76gr1an2$4edNY+S?jokk$TUT$|(7^E9Iu;SJNyC#g1up6)uNa-Nqp>|pe3kzvQKAfsJpLT^Z zQBx|CG@EgLhNv{8si1B8fjOKiP8TOT<;$e4)G5zZcp;2ZbQ|fCn$5cHxF>jd-u9(X z`7@;{W2_@b{;I+^Cf%}Eaok#tkIgwM2{p(4AT?7De7kN;d42=0f!mChGCy*H$J6|f zJD9QZ`3ygHjMLOQn$KkT+uY(1$9f{4-8mZ1kJ2>Ku*NeMzj!fLfs8c_oeXrc!zre} z50~|Iy`eY5FZCV#t%a*xZ|f~=ZtGUK6s~Z+9)7Mjv2_D-kVrFqwIiTg9I{*bR(M(8 zCIJ{+WBQuD1zVrtStb)(J8mKqcVKX1mmA$;(*+Kl&F~6oMK5Z%8yIPSLG+J$P2bd; zz54nZd4{{o;Zn~Tto8Y-=pS@TZ|@bAyYpK^&RcOjR4n9(UnEC$xrB70q;)Hn_$nz? zt0(cez6kEhE{{~4>&SYQzLxr->V4{_uOf^sy^gppp<_|Gdm7lMKS@Iv#MNEK X3~lN%7l*r3?Og|`L2vK6&Jo9dspOo| delta 670 zcmYMw&ubGw6bJB^A5GiU+8Ss@QM!UsN;_o}(jZGnvnFed?q^ zh>(-uLGZAI{u2rny$E^{ym|E`h(zNDd#ynJRRlbLz%XZGbx|9dt)AVd~< z9r+4*16fMo3vmLM;TtHyZ*UI&f|uZ5cpGMtqcc_^@7sVg@BzFDci=Vn;Xhd6OH)Mam|JP0%kUYThsW>=d<_-&8D52d-~ybR7(HYO zmN9R@0`8~h!vWDp$Q7MJ?m!|l`r{(x4iq8(z7H3n5AhzFMvmjc*?=EBJ6?o1a@Y-C z;xkYKP4Z+Fc@fDS;A&7L;oM0yB4LJJ=aIPE^Fq<~Rax4!+M*h`PSo+cqUJ=dD(974UMM+yFjR8|p%fGa z8-?vY?u6(2c6H4brX^~ceBV;d#>$@6)Fs0SBhe1(PB%PoB0o^&ds~JfH#Jk2OS-8w zjEYvP*?Oy0#@?>ib39kHUFT4h4Xs(<;y0HJqjJz$^8>FO?@hSzdgjjCPnoBQ_`_5& ImZo?90|u~V&Hw-a diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po index feb24e1186..f4645708af 100644 --- a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po @@ -1,31 +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. -# FIRST AUTHOR , YEAR. # -#, fuzzy +# Translators: +# Sergey Glita , 2012. msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-01 20:14-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:20+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: \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:50 +#: __init__.py:83 msgid "upload signature" msgstr "выложить подпись" -#: __init__.py:51 +#: __init__.py:84 msgid "download signature" msgstr "скачать подпись" -#: __init__.py:52 +#: __init__.py:85 msgid "signatures" msgstr "подписи" @@ -33,41 +34,41 @@ msgstr "подписи" msgid "Signature file" msgstr "Файл подписи" -#: models.py:19 -msgid "document version" -msgstr "" - #: models.py:20 -msgid "signature state" -msgstr "" +msgid "document version" +msgstr "версия документа" #: models.py:21 msgid "signature file" +msgstr "файл подписи" + +#: models.py:22 +msgid "has embedded signature" msgstr "" -#: models.py:26 +#: models.py:35 msgid "document version signature" -msgstr "" +msgstr "подпись версии документа" -#: models.py:27 +#: models.py:36 msgid "document version signatures" -msgstr "" +msgstr "подписи версии документа" #: permissions.py:7 +msgid "Document signatures" +msgstr "Подписи документа" + +#: permissions.py:8 msgid "Verify document signatures" msgstr "Проверить подпись документа" -#: permissions.py:8 +#: permissions.py:9 msgid "Upload detached signatures" msgstr "Выложить отделённые подписи" -#: permissions.py:9 +#: permissions.py:10 msgid "Download detached signatures" -msgstr "" - -#: permissions.py:12 -msgid "Document signatures" -msgstr "" +msgstr "Скачать отделенные подписи" #: views.py:47 #, python-format @@ -112,12 +113,13 @@ msgstr "Подписано: %s" msgid "signature properties for: %s" msgstr "свойства подписи для %s" -#: views.py:92 +#: views.py:96 msgid "Detached signature uploaded successfully." msgstr "Отделённая подпись выложена." -#: views.py:101 +#: views.py:105 #, python-format msgid "Upload detached signature for: %s" msgstr "Выложить отделённую подпись для %s" + diff --git a/apps/documents/locale/en/LC_MESSAGES/django.po b/apps/documents/locale/en/LC_MESSAGES/django.po index 65016db1b2..78ed932de9 100644 --- a/apps/documents/locale/en/LC_MESSAGES/django.po +++ b/apps/documents/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,91 +17,97 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:49 __init__.py:159 -msgid "Documents" -msgstr "" - -#: __init__.py:60 -msgid "Documents setup" -msgstr "" - -#: __init__.py:70 +#: __init__.py:63 msgid "all documents" msgstr "" -#: __init__.py:71 models.py:415 views.py:709 +#: __init__.py:64 models.py:636 views.py:871 msgid "recent documents" msgstr "" -#: __init__.py:72 +#: __init__.py:65 msgid "upload new documents" msgstr "" -#: __init__.py:73 +#: __init__.py:66 msgid "clone metadata" msgstr "" -#: __init__.py:74 +#: __init__.py:67 msgid "details" msgstr "" -#: __init__.py:75 +#: __init__.py:68 msgid "properties" msgstr "" -#: __init__.py:76 __init__.py:77 __init__.py:92 __init__.py:114 -#: __init__.py:120 +#: __init__.py:69 __init__.py:70 __init__.py:92 __init__.py:116 +#: __init__.py:122 msgid "delete" msgstr "" -#: __init__.py:78 __init__.py:91 __init__.py:113 __init__.py:119 +#: __init__.py:71 __init__.py:91 __init__.py:115 __init__.py:121 msgid "edit" msgstr "" -#: __init__.py:79 +#: __init__.py:72 msgid "preview" msgstr "" -#: __init__.py:80 +#: __init__.py:73 __init__.py:74 __init__.py:75 msgid "download" msgstr "" -#: __init__.py:81 +#: __init__.py:76 msgid "find duplicates" msgstr "" -#: __init__.py:82 +#: __init__.py:77 msgid "find all duplicates" msgstr "" -#: __init__.py:82 +#: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." msgstr "" -#: __init__.py:83 +#: __init__.py:78 msgid "update office documents' page count" msgstr "" -#: __init__.py:83 +#: __init__.py:78 msgid "" "Update the page count of the office type documents. This is useful when " "enabling office document support after there were already office type " "documents in the database." msgstr "" -#: __init__.py:84 __init__.py:85 +#: __init__.py:79 __init__.py:80 msgid "clear transformations" msgstr "" -#: __init__.py:86 +#: __init__.py:81 msgid "print" msgstr "" -#: __init__.py:87 +#: __init__.py:82 msgid "history" msgstr "" +#: __init__.py:83 +msgid "Find missing document files" +msgstr "" + +#: __init__.py:86 +msgid "Clear the document image cache" +msgstr "" + +#: __init__.py:86 +msgid "" +"Clear the graphics representations used to speed up the documents' display " +"and interactive transformations results." +msgstr "" + #: __init__.py:89 msgid "page transformations" msgstr "" @@ -158,724 +164,881 @@ msgstr "" msgid "reset view" msgstr "" -#: __init__.py:107 -msgid "Find missing document files" +#: __init__.py:108 +msgid "versions" msgstr "" -#: __init__.py:110 -msgid "document type list" -msgstr "" - -#: __init__.py:111 views.py:877 -msgid "document types" +#: __init__.py:109 +msgid "revert" msgstr "" #: __init__.py:112 +msgid "document type list" +msgstr "" + +#: __init__.py:113 views.py:1050 +msgid "document types" +msgstr "" + +#: __init__.py:114 msgid "documents of this type" msgstr "" -#: __init__.py:115 views.py:990 +#: __init__.py:117 views.py:1161 msgid "create document type" msgstr "" -#: __init__.py:117 +#: __init__.py:119 msgid "filenames" msgstr "" -#: __init__.py:118 +#: __init__.py:120 msgid "add filename to document type" msgstr "" -#: __init__.py:161 __init__.py:186 models.py:101 views.py:69 +#: __init__.py:164 permissions.py:7 +msgid "Documents" +msgstr "" + +#: __init__.py:166 __init__.py:179 models.py:90 views.py:79 msgid "documents" msgstr "" -#: __init__.py:173 +#: __init__.py:169 msgid "thumbnail" msgstr "" -#: __init__.py:176 -msgid "tags" -msgstr "" - -#: __init__.py:179 +#: __init__.py:172 msgid "metadata" msgstr "" -#: forms.py:60 +#: forms.py:63 msgid "Page image" msgstr "" -#: forms.py:70 forms.py:209 +#: forms.py:73 forms.py:270 msgid "Contents" msgstr "" -#: forms.py:116 -msgid "Details" +#: forms.py:109 +msgid "Page" msgstr "" #: forms.py:121 +msgid "Details" +msgstr "" + +#: forms.py:126 msgid "Click on the image for full size preview" msgstr "" -#: forms.py:131 +#: forms.py:136 #, python-format msgid "Document pages (%s)" msgstr "" -#: forms.py:166 +#: forms.py:162 +msgid "Use the new version filename as the document filename" +msgstr "" + +#: forms.py:178 msgid "Quick document rename" msgstr "" -#: forms.py:169 +#: forms.py:185 +msgid "Version update" +msgstr "" + +#: forms.py:190 +msgid "Release level" +msgstr "" + +#: forms.py:196 +msgid "Release level serial" +msgstr "" + +#: forms.py:204 +msgid "Comment" +msgstr "" + +#: forms.py:210 msgid "New document filename" msgstr "" -#: forms.py:223 -msgid "Page size" -msgstr "" - -#: forms.py:224 -msgid "Custom page width" -msgstr "" - -#: forms.py:225 -msgid "Custom page height" -msgstr "" - -#: forms.py:226 -msgid "Page orientation" -msgstr "" - -#: forms.py:227 +#: forms.py:288 msgid "Page range" msgstr "" -#: literals.py:8 -msgid "Create documents" +#: forms.py:318 +msgid "Compress" msgstr "" -#: literals.py:9 -msgid "Edit document properties" +#: forms.py:318 +msgid "" +"Download the document in the original format or in a compressed manner. " +"This option is selectable only when downloading one document, for multiple " +"documents, the bundle will always be downloads as a compressed file." msgstr "" #: literals.py:10 -msgid "Edit documents" -msgstr "" - -#: literals.py:11 -msgid "View documents" -msgstr "" - -#: literals.py:12 -msgid "Delete documents" -msgstr "" - -#: literals.py:13 -msgid "Download documents" -msgstr "" - -#: literals.py:14 -msgid "Transform documents" -msgstr "" - -#: literals.py:15 -msgid "Execute document modifying tools" -msgstr "" - -#: literals.py:17 -msgid "Edit document types" -msgstr "" - -#: literals.py:18 -msgid "Delete document types" -msgstr "" - -#: literals.py:19 -msgid "Create document types" -msgstr "" - -#: literals.py:23 msgid "Document creation" msgstr "" -#: literals.py:24 +#: literals.py:11 #, python-format msgid "Document \"%(content_object)s\" created by %(fullname)s." msgstr "" -#: literals.py:25 +#: literals.py:12 #, python-format msgid "" "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." msgstr "" -#: literals.py:31 +#: literals.py:18 msgid "Document edited" msgstr "" -#: literals.py:32 +#: literals.py:19 #, python-format msgid "Document \"%(content_object)s\" edited by %(fullname)s." msgstr "" -#: literals.py:33 +#: literals.py:20 #, python-format msgid "" "Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " "The following changes took place: %(changes)s." msgstr "" -#: literals.py:42 +#: literals.py:29 msgid "Document deleted" msgstr "" -#: literals.py:43 +#: literals.py:30 #, python-format msgid "Document \"%(document)s\" deleted by %(fullname)s." msgstr "" -#: literals.py:44 +#: literals.py:31 #, python-format msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." msgstr "" -#: models.py:63 +#: literals.py:42 +msgid "final" +msgstr "" + +#: literals.py:43 +msgid "alpha" +msgstr "" + +#: literals.py:44 +msgid "beta" +msgstr "" + +#: literals.py:45 +msgid "release candidate" +msgstr "" + +#: literals.py:46 +msgid "hotfix" +msgstr "" + +#: models.py:61 msgid "name" msgstr "" -#: models.py:69 models.py:78 models.py:315 views.py:896 views.py:926 -#: views.py:955 views.py:960 views.py:1003 views.py:1049 views.py:1083 +#: models.py:67 models.py:77 models.py:524 views.py:1068 views.py:1097 +#: views.py:1126 views.py:1131 views.py:1174 views.py:1220 views.py:1254 msgid "document type" msgstr "" -#: models.py:70 +#: models.py:68 msgid "documents types" msgstr "" -#: models.py:79 -msgid "file" -msgstr "" - -#: models.py:86 -msgid "added" -msgstr "" - -#: models.py:87 -msgid "updated" -msgstr "" - -#: models.py:88 -msgid "checksum" -msgstr "" - -#: models.py:89 +#: models.py:78 msgid "description" msgstr "" -#: models.py:100 models.py:332 models.py:404 models.py:419 views.py:209 +#: models.py:79 +msgid "added" +msgstr "" + +#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: views.py:351 msgid "document" msgstr "" -#: models.py:181 +#: models.py:287 +#, python-format +msgid "Major %(major)i.%(minor)i, (new release)" +msgstr "" + +#: models.py:288 +#, python-format +msgid "Minor %(major)i.%(minor)i, (some updates)" +msgstr "" + +#: models.py:289 +#, python-format +msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" +msgstr "" + +#: models.py:301 +msgid "mayor" +msgstr "" + +#: models.py:302 +msgid "minor" +msgstr "" + +#: models.py:303 +msgid "micro" +msgstr "" + +#: models.py:304 +msgid "release level" +msgstr "" + +#: models.py:305 +msgid "serial" +msgstr "" + +#: models.py:306 +msgid "timestamp" +msgstr "" + +#: models.py:307 views.py:1357 +msgid "comment" +msgstr "" + +#: models.py:310 +msgid "file" +msgstr "" + +#: models.py:314 +msgid "checksum" +msgstr "" + +#: models.py:318 models.py:319 models.py:542 +msgid "document version" +msgstr "" + +#: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." msgstr "" -#: models.py:316 +#: models.py:525 views.py:1353 msgid "filename" msgstr "" -#: models.py:317 views.py:1010 +#: models.py:526 views.py:1181 msgid "enabled" msgstr "" -#: models.py:324 +#: models.py:533 msgid "document type quick rename filename" msgstr "" -#: models.py:325 +#: models.py:534 msgid "document types quick rename filenames" msgstr "" -#: models.py:333 +#: models.py:545 msgid "content" msgstr "" -#: models.py:334 +#: models.py:546 msgid "page label" msgstr "" -#: models.py:335 +#: models.py:547 msgid "page number" msgstr "" -#: models.py:338 +#: models.py:550 #, python-format msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" msgstr "" -#: models.py:346 models.py:383 +#: models.py:558 models.py:604 msgid "document page" msgstr "" -#: models.py:347 +#: models.py:559 msgid "document pages" msgstr "" -#: models.py:358 +#: models.py:579 msgid "Enter a valid value." msgstr "" -#: models.py:384 views.py:333 +#: models.py:605 views.py:449 msgid "order" msgstr "" -#: models.py:385 views.py:334 views.py:389 views.py:418 +#: models.py:606 views.py:450 views.py:511 views.py:542 msgid "transformation" msgstr "" -#: models.py:386 views.py:335 +#: models.py:607 views.py:451 msgid "arguments" msgstr "" -#: models.py:386 +#: models.py:607 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "" -#: models.py:394 +#: models.py:615 msgid "document page transformation" msgstr "" -#: models.py:395 +#: models.py:616 msgid "document page transformations" msgstr "" -#: models.py:403 +#: models.py:624 msgid "user" msgstr "" -#: models.py:405 +#: models.py:626 msgid "accessed" msgstr "" -#: models.py:414 +#: models.py:635 msgid "recent document" msgstr "" -#: models.py:420 +#: models.py:641 msgid "Document type" msgstr "" -#: models.py:421 +#: models.py:642 msgid "MIME type" msgstr "" -#: models.py:422 views.py:117 +#: models.py:643 views.py:132 msgid "Filename" msgstr "" -#: models.py:423 -msgid "Filename extension" -msgstr "" - -#: models.py:424 +#: models.py:644 msgid "Metadata value" msgstr "" -#: models.py:425 +#: models.py:645 msgid "Content" msgstr "" -#: models.py:426 +#: models.py:646 msgid "Description" msgstr "" -#: models.py:427 +#: models.py:647 msgid "Tags" msgstr "" -#: models.py:428 +#: models.py:648 msgid "Comments" msgstr "" -#: statistics.py:38 +#: permissions.py:9 +msgid "Create documents" +msgstr "" + +#: permissions.py:10 +msgid "Edit document properties" +msgstr "" + +#: permissions.py:11 +msgid "Edit documents" +msgstr "" + +#: permissions.py:12 +msgid "View documents" +msgstr "" + +#: permissions.py:13 +msgid "Delete documents" +msgstr "" + +#: permissions.py:14 views.py:408 +msgid "Download documents" +msgstr "" + +#: permissions.py:15 +msgid "Transform documents" +msgstr "" + +#: permissions.py:16 +msgid "Execute document modifying tools" +msgstr "" + +#: permissions.py:17 +msgid "Revert documents to a previous version" +msgstr "" + +#: permissions.py:18 +msgid "Create new document versions" +msgstr "" + +#: permissions.py:20 +msgid "Documents setup" +msgstr "" + +#: permissions.py:22 +msgid "View document types" +msgstr "" + +#: permissions.py:23 +msgid "Edit document types" +msgstr "" + +#: permissions.py:24 +msgid "Delete document types" +msgstr "" + +#: permissions.py:25 +msgid "Create document types" +msgstr "" + +#: statistics.py:40 #, python-format msgid "Document types: %d" msgstr "" -#: statistics.py:39 +#: statistics.py:41 #, python-format msgid "Documents in database: %d" msgstr "" -#: statistics.py:44 +#: statistics.py:46 #, python-format msgid "Documents in storage: %d" msgstr "" -#: statistics.py:46 +#: statistics.py:48 #, python-format msgid "" "Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " "bytes" msgstr "" -#: statistics.py:56 +#: statistics.py:58 #, python-format msgid "Document pages in database: %d" msgstr "" -#: statistics.py:57 +#: statistics.py:59 #, python-format msgid "Minimum amount of pages per document: %(page_count__min)d" msgstr "" -#: statistics.py:58 +#: statistics.py:60 #, python-format msgid "Maximum amount of pages per document: %(page_count__max)d" msgstr "" -#: statistics.py:59 +#: statistics.py:61 #, python-format msgid "Average amount of pages per document: %(page_count__avg)f" msgstr "" -#: statistics.py:65 +#: statistics.py:67 msgid "Document statistics" msgstr "" -#: views.py:118 -msgid "File extension" -msgstr "" - -#: views.py:119 +#: views.py:133 msgid "File mimetype" msgstr "" -#: views.py:120 +#: views.py:134 msgid "File mime encoding" msgstr "" -#: views.py:121 +#: views.py:135 msgid "File size" msgstr "" -#: views.py:122 +#: views.py:136 msgid "Exists in storage" msgstr "" -#: views.py:123 +#: views.py:137 msgid "File path in storage" msgstr "" -#: views.py:124 +#: views.py:138 msgid "Date added" msgstr "" -#: views.py:125 +#: views.py:139 msgid "Time added" msgstr "" -#: views.py:126 +#: views.py:140 msgid "Checksum" msgstr "" -#: views.py:127 +#: views.py:141 msgid "UUID" msgstr "" -#: views.py:128 +#: views.py:142 msgid "Pages" msgstr "" -#: views.py:137 +#: views.py:151 #, python-format msgid "document properties for: %s" msgstr "" -#: views.py:159 +#: views.py:173 msgid "document data" msgstr "" -#: views.py:184 views.py:521 +#: views.py:197 views.py:646 msgid "Must provide at least one document." msgstr "" -#: views.py:200 -#, python-format -msgid "Document: %s deleted successfully." +#: views.py:218 +msgid "Document deleted successfully." msgstr "" -#: views.py:202 +#: views.py:220 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "" -#: views.py:217 +#: views.py:235 #, python-format msgid "Are you sure you wish to delete the document: %s?" msgstr "" -#: views.py:219 +#: views.py:237 #, python-format msgid "Are you sure you wish to delete the documents: %s?" msgstr "" -#: views.py:256 +#: views.py:276 #, python-format msgid "Document \"%s\" edited successfully." msgstr "" -#: views.py:329 +#: views.py:342 +msgid "documents to be downloaded" +msgstr "" + +#: views.py:352 views.py:1337 +msgid "version" +msgstr "" + +#: views.py:409 +msgid "Download" +msgstr "" + +#: views.py:411 +msgid "Return" +msgstr "" + +#: views.py:445 #, python-format msgid "transformations for: %s" msgstr "" -#: views.py:353 +#: views.py:472 msgid "Document page transformation created successfully." msgstr "" -#: views.py:362 +#: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" msgstr "" -#: views.py:378 +#: views.py:500 msgid "Document page transformation edited successfully." msgstr "" -#: views.py:391 +#: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" msgstr "" -#: views.py:409 +#: views.py:533 msgid "Document page transformation deleted successfully." msgstr "" -#: views.py:420 +#: views.py:544 #, python-format msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " "%(document_page)s" msgstr "" -#: views.py:434 +#: views.py:562 #, python-format msgid "duplicates of: %s" msgstr "" -#: views.py:446 +#: views.py:574 msgid "Are you sure you wish to find all duplicates?" msgstr "" -#: views.py:447 views.py:506 views.py:571 +#: views.py:575 views.py:633 views.py:701 msgid "On large databases this operation may take some time to execute." msgstr "" -#: views.py:462 +#: views.py:598 msgid "duplicated documents" msgstr "" -#: views.py:497 +#: views.py:624 #, python-format msgid "" "Page count update complete. Documents processed: %(total)d, documents with " "changed page count: %(change)d" msgstr "" -#: views.py:505 +#: views.py:632 #, python-format msgid "" "Are you sure you wish to update the page count for the office documents (%d)?" msgstr "" -#: views.py:534 +#: views.py:664 #, python-format msgid "" "All the page transformations for document: %s, have been deleted " "successfully." msgstr "" -#: views.py:536 +#: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " "%(error)s." msgstr "" -#: views.py:542 +#: views.py:672 msgid "document transformation" msgstr "" -#: views.py:551 +#: views.py:681 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for document: %s?" msgstr "" -#: views.py:553 +#: views.py:683 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for documents: " "%s?" msgstr "" -#: views.py:581 +#: views.py:711 msgid "missing documents" msgstr "" -#: views.py:594 views.py:632 +#: views.py:727 views.py:769 #, python-format msgid "details for: %s" msgstr "" -#: views.py:647 +#: views.py:788 msgid "Document page edited successfully." msgstr "" -#: views.py:656 +#: views.py:797 #, python-format msgid "edit: %s" msgstr "" -#: views.py:667 +#: views.py:814 msgid "There are no more pages in this document" msgstr "" -#: views.py:680 +#: views.py:832 msgid "You are already at the first page of this document" msgstr "" -#: views.py:823 +#: views.py:993 #, python-format msgid "print: %s" msgstr "" -#: views.py:894 +#: views.py:1066 #, python-format msgid "documents of type \"%s\"" msgstr "" -#: views.py:914 +#: views.py:1086 msgid "Document type edited successfully" msgstr "" -#: views.py:917 +#: views.py:1089 #, python-format msgid "Error editing document type; %s" msgstr "" -#: views.py:922 +#: views.py:1094 #, python-format msgid "edit document type: %s" msgstr "" -#: views.py:947 +#: views.py:1118 #, python-format msgid "Document type: %s deleted successfully." msgstr "" -#: views.py:949 +#: views.py:1120 #, python-format msgid "Document type: %(document_type)s delete error: %(error)s" msgstr "" -#: views.py:964 +#: views.py:1135 #, python-format msgid "Are you sure you wish to delete the document type: %s?" msgstr "" -#: views.py:965 +#: views.py:1136 msgid "" "The document type of all documents using this document type will be set to " "none." msgstr "" -#: views.py:981 +#: views.py:1152 msgid "Document type created successfully" msgstr "" -#: views.py:984 +#: views.py:1155 #, python-format msgid "Error creating document type; %(error)s" msgstr "" -#: views.py:1002 +#: views.py:1173 #, python-format msgid "filenames for document type: %s" msgstr "" -#: views.py:1033 +#: views.py:1204 msgid "Document type filename edited successfully" msgstr "" -#: views.py:1036 +#: views.py:1207 #, python-format msgid "Error editing document type filename; %s" msgstr "" -#: views.py:1041 +#: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" msgstr "" -#: views.py:1050 views.py:1076 views.py:1084 +#: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" msgstr "" -#: views.py:1068 +#: views.py:1239 #, python-format msgid "Document type filename: %s deleted successfully." msgstr "" -#: views.py:1070 +#: views.py:1241 #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" msgstr "" -#: views.py:1086 +#: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " "type \"%(document_type)s\"?" msgstr "" -#: views.py:1111 +#: views.py:1282 msgid "Document type filename created successfully" msgstr "" -#: views.py:1114 +#: views.py:1285 #, python-format msgid "Error creating document type filename; %(error)s" msgstr "" -#: views.py:1120 +#: views.py:1291 #, python-format msgid "create filename for document type: %s" msgstr "" -#: widgets.py:26 +#: views.py:1306 +msgid "Document image cache cleared successfully" +msgstr "" + +#: views.py:1308 +#, python-format +msgid "Error clearing document image cache; %s" +msgstr "" + +#: views.py:1314 +msgid "Are you sure you wish to clear the document image cache?" +msgstr "" + +#: views.py:1331 +#, python-format +msgid "versions for document: %s" +msgstr "" + +#: views.py:1341 +msgid "time and date" +msgstr "" + +#: views.py:1345 +msgid "mimetype" +msgstr "" + +#: views.py:1349 +msgid "encoding" +msgstr "" + +#: views.py:1380 +msgid "Document version reverted successfully" +msgstr "" + +#: views.py:1382 +#, python-format +msgid "Error reverting document version; %s" +msgstr "" + +#: views.py:1389 +msgid "Are you sure you wish to revert to this version?" +msgstr "" + +#: views.py:1390 +msgid "All later version after this one will be deleted too." +msgstr "" + +#: widgets.py:25 msgid "document page image" msgstr "" -#: wizards.py:34 +#: wizards.py:36 msgid "step 1 of 3: Document type" msgstr "" -#: wizards.py:35 +#: wizards.py:37 msgid "step 2 of 3: Metadata selection" msgstr "" -#: wizards.py:36 +#: wizards.py:38 msgid "step 3 of 3: Document metadata" msgstr "" -#: wizards.py:44 +#: wizards.py:46 msgid "Next step" msgstr "" diff --git a/apps/documents/locale/es/LC_MESSAGES/django.mo b/apps/documents/locale/es/LC_MESSAGES/django.mo index 670f8b0ae86425b23b1a90c824aa2bbb5b366fc7..fd334df0ed97dfea8e7d15ff444359d080da6a8c 100644 GIT binary patch delta 5333 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 delta 5075 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 diff --git a/apps/documents/locale/es/LC_MESSAGES/django.po b/apps/documents/locale/es/LC_MESSAGES/django.po index 533bf311c8..9f0dc4aa70 100644 --- a/apps/documents/locale/es/LC_MESSAGES/django.po +++ b/apps/documents/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 15:33+0000\n" -"Last-Translator: rosarior \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:42+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,75 +18,67 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:49 __init__.py:159 -msgid "Documents" -msgstr "Documentos" - -#: __init__.py:60 -msgid "Documents setup" -msgstr "Configuración de documentos" - -#: __init__.py:70 +#: __init__.py:63 msgid "all documents" msgstr "todos los documentos" -#: __init__.py:71 models.py:415 views.py:709 +#: __init__.py:64 models.py:636 views.py:871 msgid "recent documents" msgstr "documentos recientes" -#: __init__.py:72 +#: __init__.py:65 msgid "upload new documents" msgstr "subir nuevos documentos" -#: __init__.py:73 +#: __init__.py:66 msgid "clone metadata" msgstr "clonar metadatos" -#: __init__.py:74 +#: __init__.py:67 msgid "details" msgstr "detalles" -#: __init__.py:75 +#: __init__.py:68 msgid "properties" msgstr "propiedades" -#: __init__.py:76 __init__.py:77 __init__.py:92 __init__.py:114 -#: __init__.py:120 +#: __init__.py:69 __init__.py:70 __init__.py:92 __init__.py:116 +#: __init__.py:122 msgid "delete" msgstr "eliminar" -#: __init__.py:78 __init__.py:91 __init__.py:113 __init__.py:119 +#: __init__.py:71 __init__.py:91 __init__.py:115 __init__.py:121 msgid "edit" msgstr "editar" -#: __init__.py:79 +#: __init__.py:72 msgid "preview" msgstr "muestra" -#: __init__.py:80 +#: __init__.py:73 __init__.py:74 __init__.py:75 msgid "download" msgstr "descarga" -#: __init__.py:81 +#: __init__.py:76 msgid "find duplicates" msgstr "encontrar duplicados" -#: __init__.py:82 +#: __init__.py:77 msgid "find all duplicates" msgstr "encontrar todos los duplicados" -#: __init__.py:82 +#: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." msgstr "" "Buscar todas las sumas de comprobación de los documentos y devolver una " "lista de las coincidencias exactas." -#: __init__.py:83 +#: __init__.py:78 msgid "update office documents' page count" msgstr "actualizar el número de páginas de los documentos de oficina" -#: __init__.py:83 +#: __init__.py:78 msgid "" "Update the page count of the office type documents. This is useful when " "enabling office document support after there were already office type " @@ -96,18 +88,32 @@ msgstr "" "cuando active el apoyo de documentos de oficina después de que ya existían " "documentos de oficina en la base de datos." -#: __init__.py:84 __init__.py:85 +#: __init__.py:79 __init__.py:80 msgid "clear transformations" msgstr "borrar transformaciones" -#: __init__.py:86 +#: __init__.py:81 msgid "print" msgstr "imprimir" -#: __init__.py:87 +#: __init__.py:82 msgid "history" msgstr "historia" +#: __init__.py:83 +msgid "Find missing document files" +msgstr "Buscar archivos de documentos perdidos" + +#: __init__.py:86 +msgid "Clear the document image cache" +msgstr "" + +#: __init__.py:86 +msgid "" +"Clear the graphics representations used to speed up the documents' display " +"and interactive transformations results." +msgstr "" + #: __init__.py:89 msgid "page transformations" msgstr "transformaciones de la página" @@ -164,168 +170,147 @@ msgstr "girar a la izquierda" msgid "reset view" msgstr "Restablecer vista" -#: __init__.py:107 -msgid "Find missing document files" -msgstr "Buscar archivos de documentos perdidos" +#: __init__.py:108 +msgid "versions" +msgstr "versiones" -#: __init__.py:110 +#: __init__.py:109 +msgid "revert" +msgstr "revertir" + +#: __init__.py:112 msgid "document type list" msgstr "ista de tipos de documentos" -#: __init__.py:111 views.py:877 +#: __init__.py:113 views.py:1050 msgid "document types" msgstr "tipos de documentos" -#: __init__.py:112 +#: __init__.py:114 msgid "documents of this type" msgstr "documentos de este tipo" -#: __init__.py:115 views.py:990 +#: __init__.py:117 views.py:1161 msgid "create document type" msgstr "crear tipo de documento" -#: __init__.py:117 +#: __init__.py:119 msgid "filenames" msgstr "nombres de archivo" -#: __init__.py:118 +#: __init__.py:120 msgid "add filename to document type" msgstr "Añadir nombre de archivo para tipo de documento" -#: __init__.py:161 __init__.py:186 models.py:101 views.py:69 +#: __init__.py:164 permissions.py:7 +msgid "Documents" +msgstr "Documentos" + +#: __init__.py:166 __init__.py:179 models.py:90 views.py:79 msgid "documents" msgstr "documentos" -#: __init__.py:173 +#: __init__.py:169 msgid "thumbnail" msgstr "miniatura" -#: __init__.py:176 -msgid "tags" -msgstr "etiquetas" - -#: __init__.py:179 +#: __init__.py:172 msgid "metadata" msgstr "metadatos" -#: forms.py:60 +#: forms.py:63 msgid "Page image" msgstr "Imagen de la página" -#: forms.py:70 forms.py:209 +#: forms.py:73 forms.py:270 msgid "Contents" msgstr "Contenido" -#: forms.py:116 +#: forms.py:109 +msgid "Page" +msgstr "Página" + +#: forms.py:121 msgid "Details" msgstr "Detalles" -#: forms.py:121 +#: forms.py:126 msgid "Click on the image for full size preview" msgstr "Haga clic en la imagen para ver una muestra de tamaño completo" -#: forms.py:131 +#: forms.py:136 #, python-format msgid "Document pages (%s)" msgstr "Páginas del documento (%s)" -#: forms.py:166 +#: forms.py:162 +msgid "Use the new version filename as the document filename" +msgstr "" + +#: forms.py:178 msgid "Quick document rename" msgstr "Cambio rápido de nombre" -#: forms.py:169 +#: forms.py:185 +msgid "Version update" +msgstr "Actualizar versión" + +#: forms.py:190 +msgid "Release level" +msgstr "Nivel de liberación" + +#: forms.py:196 +msgid "Release level serial" +msgstr "" + +#: forms.py:204 +msgid "Comment" +msgstr "Comentario" + +#: forms.py:210 msgid "New document filename" msgstr "Nuevo nombre del archivo" -#: forms.py:223 -msgid "Page size" -msgstr "Tamaño de la página" - -#: forms.py:224 -msgid "Custom page width" -msgstr "Ancho de página alterno" - -#: forms.py:225 -msgid "Custom page height" -msgstr "Alto de página alterno" - -#: forms.py:226 -msgid "Page orientation" -msgstr "Orientación de la página" - -#: forms.py:227 +#: forms.py:288 msgid "Page range" msgstr "Rango de páginas" -#: literals.py:8 -msgid "Create documents" -msgstr "Crear documentos" +#: forms.py:318 +msgid "Compress" +msgstr "Comprimir" -#: literals.py:9 -msgid "Edit document properties" -msgstr "Editar propiedades del documento" +#: forms.py:318 +msgid "" +"Download the document in the original format or in a compressed manner. " +"This option is selectable only when downloading one document, for multiple " +"documents, the bundle will always be downloads as a compressed file." +msgstr "" #: literals.py:10 -msgid "Edit documents" -msgstr "Editar documentos" - -#: literals.py:11 -msgid "View documents" -msgstr "Ver documentos" - -#: literals.py:12 -msgid "Delete documents" -msgstr "Eliminar documentos" - -#: literals.py:13 -msgid "Download documents" -msgstr "Descargar documentos" - -#: literals.py:14 -msgid "Transform documents" -msgstr "Transformar documentos" - -#: literals.py:15 -msgid "Execute document modifying tools" -msgstr "Ejecutar herramientas de modificación de documento" - -#: literals.py:17 -msgid "Edit document types" -msgstr "Editar tipos de documentos" - -#: literals.py:18 -msgid "Delete document types" -msgstr "Eliminar tipos de documentos" - -#: literals.py:19 -msgid "Create document types" -msgstr "Crear tipos de documentos" - -#: literals.py:23 msgid "Document creation" msgstr "Creación de documentos" -#: literals.py:24 +#: literals.py:11 #, python-format msgid "Document \"%(content_object)s\" created by %(fullname)s." msgstr "Documento \"%(content_object)s\", creado por %(fullname)s." -#: literals.py:25 +#: literals.py:12 #, python-format msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." msgstr "" "Documento \"%(content_object)s\", creado en %(datetime)s por %(fullname)s." -#: literals.py:31 +#: literals.py:18 msgid "Document edited" msgstr "Documento editado" -#: literals.py:32 +#: literals.py:19 #, python-format msgid "Document \"%(content_object)s\" edited by %(fullname)s." msgstr "Documento \"%(content_object)s\", editado por %(fullname)s." -#: literals.py:33 +#: literals.py:20 #, python-format msgid "" "Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." @@ -334,58 +319,122 @@ msgstr "" "Documento \"%(content_object)s\" fue editado en \"%(datetime)s por " "%(fullname)s. Los siguientes cambios tuvieron lugar: %(changes)s." -#: literals.py:42 +#: literals.py:29 msgid "Document deleted" msgstr "Documento eliminado" -#: literals.py:43 +#: literals.py:30 #, python-format msgid "Document \"%(document)s\" deleted by %(fullname)s." msgstr "Documento \"%(document)s\" eliminado por %(fullname)s." -#: literals.py:44 +#: literals.py:31 #, python-format msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." msgstr "Documento \"%(document)s\" eliminado en %(datetime)s por %(fullname)s." -#: models.py:63 +#: literals.py:42 +msgid "final" +msgstr "final" + +#: literals.py:43 +msgid "alpha" +msgstr "alfa" + +#: literals.py:44 +msgid "beta" +msgstr "beta" + +#: literals.py:45 +msgid "release candidate" +msgstr "Candidato de liberación" + +#: literals.py:46 +msgid "hotfix" +msgstr "revisión" + +#: models.py:61 msgid "name" msgstr "nombre" -#: models.py:69 models.py:78 models.py:315 views.py:896 views.py:926 -#: views.py:955 views.py:960 views.py:1003 views.py:1049 views.py:1083 +#: models.py:67 models.py:77 models.py:524 views.py:1068 views.py:1097 +#: views.py:1126 views.py:1131 views.py:1174 views.py:1220 views.py:1254 msgid "document type" msgstr "tipo de documento" -#: models.py:70 +#: models.py:68 msgid "documents types" msgstr "tipos de documentos" -#: models.py:79 -msgid "file" -msgstr "archivo" - -#: models.py:86 -msgid "added" -msgstr "agregado" - -#: models.py:87 -msgid "updated" -msgstr "actualizado" - -#: models.py:88 -msgid "checksum" -msgstr "suma de comprobación" - -#: models.py:89 +#: models.py:78 msgid "description" msgstr "descripción" -#: models.py:100 models.py:332 models.py:404 models.py:419 views.py:209 +#: models.py:79 +msgid "added" +msgstr "agregado" + +#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: views.py:351 msgid "document" msgstr "documento" -#: models.py:181 +#: models.py:287 +#, python-format +msgid "Major %(major)i.%(minor)i, (new release)" +msgstr "" + +#: models.py:288 +#, python-format +msgid "Minor %(major)i.%(minor)i, (some updates)" +msgstr "" + +#: models.py:289 +#, python-format +msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" +msgstr "" + +#: models.py:301 +msgid "mayor" +msgstr "mayor" + +#: models.py:302 +msgid "minor" +msgstr "menor" + +#: models.py:303 +msgid "micro" +msgstr "micro" + +#: models.py:304 +msgid "release level" +msgstr "" + +#: models.py:305 +msgid "serial" +msgstr "" + +#: models.py:306 +msgid "timestamp" +msgstr "" + +#: models.py:307 views.py:1357 +msgid "comment" +msgstr "comentario" + +#: models.py:310 +msgid "file" +msgstr "archivo" + +#: models.py:314 +msgid "checksum" +msgstr "suma de comprobación" + +#: models.py:318 models.py:319 models.py:542 +msgid "document version" +msgstr "" + +#: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." @@ -393,141 +442,197 @@ msgstr "" "El formato de este archivo de documento no se conoce, el número de páginas " "por lo tanto sera 1." -#: models.py:316 +#: models.py:525 views.py:1353 msgid "filename" msgstr "nombre de archivo" -#: models.py:317 views.py:1010 +#: models.py:526 views.py:1181 msgid "enabled" msgstr "habilitado" -#: models.py:324 +#: models.py:533 msgid "document type quick rename filename" msgstr "nombre de archivo para cambio rápido de nombre para tipo de documento" -#: models.py:325 +#: models.py:534 msgid "document types quick rename filenames" msgstr "" "nombres de archivos para cambio rápido de nombre para tipo de documentos" -#: models.py:333 +#: models.py:545 msgid "content" msgstr "contenido" -#: models.py:334 +#: models.py:546 msgid "page label" msgstr "etiqueta de la página" -#: models.py:335 +#: models.py:547 msgid "page number" msgstr "número de página" -#: models.py:338 +#: models.py:550 #, python-format msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" msgstr "Pagína %(page_num)d de %(total_pages)d de %(document)s " -#: models.py:346 models.py:383 +#: models.py:558 models.py:604 msgid "document page" msgstr "página de documento" -#: models.py:347 +#: models.py:559 msgid "document pages" msgstr "páginas de documentos" -#: models.py:358 +#: models.py:579 msgid "Enter a valid value." msgstr "Introduzca un valor válido." -#: models.py:384 views.py:333 +#: models.py:605 views.py:449 msgid "order" msgstr "orden" -#: models.py:385 views.py:334 views.py:389 views.py:418 +#: models.py:606 views.py:450 views.py:511 views.py:542 msgid "transformation" msgstr "transformación" -#: models.py:386 views.py:335 +#: models.py:607 views.py:451 msgid "arguments" msgstr "argumentos" -#: models.py:386 +#: models.py:607 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Utilize diccionarios para indentificar argumentos, por ejemplo: %s" -#: models.py:394 +#: models.py:615 msgid "document page transformation" msgstr "transformación de página de documento" -#: models.py:395 +#: models.py:616 msgid "document page transformations" msgstr "transformaciones de páginas de documentos" -#: models.py:403 +#: models.py:624 msgid "user" msgstr "usuario" -#: models.py:405 +#: models.py:626 msgid "accessed" msgstr "accesado" -#: models.py:414 +#: models.py:635 msgid "recent document" msgstr "documento reciente" -#: models.py:420 +#: models.py:641 msgid "Document type" msgstr "Tipo de documento" -#: models.py:421 +#: models.py:642 msgid "MIME type" msgstr "Tipo MIME" -#: models.py:422 views.py:117 +#: models.py:643 views.py:132 msgid "Filename" msgstr "Nombre del archivo" -#: models.py:423 -msgid "Filename extension" -msgstr "Extensión de archivo" - -#: models.py:424 +#: models.py:644 msgid "Metadata value" msgstr "Valor de metadatos" -#: models.py:425 +#: models.py:645 msgid "Content" msgstr "Contenido" -#: models.py:426 +#: models.py:646 msgid "Description" msgstr "Descripción" -#: models.py:427 +#: models.py:647 msgid "Tags" msgstr "Etiquetas" -#: models.py:428 +#: models.py:648 msgid "Comments" msgstr "Comentarios" -#: statistics.py:38 +#: permissions.py:9 +msgid "Create documents" +msgstr "Crear documentos" + +#: permissions.py:10 +msgid "Edit document properties" +msgstr "Editar propiedades del documento" + +#: permissions.py:11 +msgid "Edit documents" +msgstr "Editar documentos" + +#: permissions.py:12 +msgid "View documents" +msgstr "Ver documentos" + +#: permissions.py:13 +msgid "Delete documents" +msgstr "Eliminar documentos" + +#: permissions.py:14 views.py:408 +msgid "Download documents" +msgstr "Descargar documentos" + +#: permissions.py:15 +msgid "Transform documents" +msgstr "Transformar documentos" + +#: permissions.py:16 +msgid "Execute document modifying tools" +msgstr "Ejecutar herramientas de modificación de documento" + +#: permissions.py:17 +msgid "Revert documents to a previous version" +msgstr "" + +#: permissions.py:18 +msgid "Create new document versions" +msgstr "" + +#: permissions.py:20 +msgid "Documents setup" +msgstr "Configuración de documentos" + +#: permissions.py:22 +msgid "View document types" +msgstr "" + +#: permissions.py:23 +msgid "Edit document types" +msgstr "Editar tipos de documentos" + +#: permissions.py:24 +msgid "Delete document types" +msgstr "Eliminar tipos de documentos" + +#: permissions.py:25 +msgid "Create document types" +msgstr "Crear tipos de documentos" + +#: statistics.py:40 #, python-format msgid "Document types: %d" msgstr "Tipos de documentos: %d" -#: statistics.py:39 +#: statistics.py:41 #, python-format msgid "Documents in database: %d" msgstr "Documentos en la base de datos: %d" -#: statistics.py:44 +#: statistics.py:46 #, python-format msgid "Documents in storage: %d" msgstr "Documentos en almacenamiento: %d" -#: statistics.py:46 +#: statistics.py:48 #, python-format msgid "" "Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" @@ -536,142 +641,153 @@ msgstr "" "Espacio utilizado en el almacenamiento: %(base_2)s (base 2), %(base_10)s " "(base 10), %(bytes)d bytes" -#: statistics.py:56 +#: statistics.py:58 #, python-format msgid "Document pages in database: %d" msgstr "Páginas de documentos en la base de datos: %d" -#: statistics.py:57 +#: statistics.py:59 #, python-format msgid "Minimum amount of pages per document: %(page_count__min)d" msgstr "Cantidad mínima de páginas por documento: %(page_count__min)d" -#: statistics.py:58 +#: statistics.py:60 #, python-format msgid "Maximum amount of pages per document: %(page_count__max)d" msgstr "Cantidad máxima de páginas por documento: %(page_count__max)d" -#: statistics.py:59 +#: statistics.py:61 #, python-format msgid "Average amount of pages per document: %(page_count__avg)f" msgstr "Promedio de páginas por documento: %(page_count__avg)f" -#: statistics.py:65 +#: statistics.py:67 msgid "Document statistics" msgstr "Estadísticas de documentos" -#: views.py:118 -msgid "File extension" -msgstr "Extensión de archivo" - -#: views.py:119 +#: views.py:133 msgid "File mimetype" msgstr "Tipo MIME del archivo" -#: views.py:120 +#: views.py:134 msgid "File mime encoding" msgstr "Codificación de archivos MIME" -#: views.py:121 +#: views.py:135 msgid "File size" msgstr "Tamaños del archivo" -#: views.py:122 +#: views.py:136 msgid "Exists in storage" msgstr "Existe en el almacenamiento" -#: views.py:123 +#: views.py:137 msgid "File path in storage" msgstr "Ruta de archivos en el almacenamiento" -#: views.py:124 +#: views.py:138 msgid "Date added" msgstr "Fecha en que se agregó" -#: views.py:125 +#: views.py:139 msgid "Time added" msgstr "El tiempo añadido" -#: views.py:126 +#: views.py:140 msgid "Checksum" msgstr "Suma de comprobación" -#: views.py:127 +#: views.py:141 msgid "UUID" msgstr "UUID" -#: views.py:128 +#: views.py:142 msgid "Pages" msgstr "Páginas" -#: views.py:137 +#: views.py:151 #, python-format msgid "document properties for: %s" msgstr "propiedades del documento: %s" -#: views.py:159 +#: views.py:173 msgid "document data" msgstr "datos del documento" -#: views.py:184 views.py:521 +#: views.py:197 views.py:646 msgid "Must provide at least one document." msgstr "Debe proveer al menos un documento." -#: views.py:200 -#, python-format -msgid "Document: %s deleted successfully." -msgstr "Documento: %s eliminado con éxito." +#: views.py:218 +msgid "Document deleted successfully." +msgstr "" -#: views.py:202 +#: views.py:220 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Documento: %(document)s, error de eliminación: %(error)s " -#: views.py:217 +#: views.py:235 #, python-format msgid "Are you sure you wish to delete the document: %s?" msgstr "¿Está seguro que desea eliminar el documento: %s?" -#: views.py:219 +#: views.py:237 #, python-format msgid "Are you sure you wish to delete the documents: %s?" msgstr "¿Está seguro que desea eliminar los documentos: %s?" -#: views.py:256 +#: views.py:276 #, python-format msgid "Document \"%s\" edited successfully." msgstr "Documento \"%s\" editado exitosamente." -#: views.py:329 +#: views.py:342 +msgid "documents to be downloaded" +msgstr "" + +#: views.py:352 views.py:1337 +msgid "version" +msgstr "" + +#: views.py:409 +msgid "Download" +msgstr "Descargar" + +#: views.py:411 +msgid "Return" +msgstr "Volver" + +#: views.py:445 #, python-format msgid "transformations for: %s" msgstr "transformaciones para: %s" -#: views.py:353 +#: views.py:472 msgid "Document page transformation created successfully." msgstr "Transformación de página de documento creada con exitosamente." -#: views.py:362 +#: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" msgstr "" "Crear nueva transformación de la página: %(page)s del documento: " "%(document)s " -#: views.py:378 +#: views.py:500 msgid "Document page transformation edited successfully." msgstr "Transformación de página de documento editada con exitosamente." -#: views.py:391 +#: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" msgstr "Editar transformación \" %(transformation)s\" para: %(document_page)s" -#: views.py:409 +#: views.py:533 msgid "Document page transformation deleted successfully." msgstr "Transformación de página de documento eliminada exitosamente." -#: views.py:420 +#: views.py:544 #, python-format msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " @@ -680,26 +796,26 @@ msgstr "" "¿Está seguro que desea eliminar la transformación \"%(transformation)s\" " "para: %(document_page)s" -#: views.py:434 +#: views.py:562 #, python-format msgid "duplicates of: %s" msgstr "duplicados de: %s" -#: views.py:446 +#: views.py:574 msgid "Are you sure you wish to find all duplicates?" msgstr "¿Está seguro que desea encontrar todos los duplicados?" -#: views.py:447 views.py:506 views.py:571 +#: views.py:575 views.py:633 views.py:701 msgid "On large databases this operation may take some time to execute." msgstr "" "En bases de datos de gran tamaño esta operación puede tardar algún tiempo en" " ejecutarse." -#: views.py:462 +#: views.py:598 msgid "duplicated documents" msgstr "documentos duplicados" -#: views.py:497 +#: views.py:624 #, python-format msgid "" "Page count update complete. Documents processed: %(total)d, documents with " @@ -708,7 +824,7 @@ msgstr "" "Actualización de número de páginas completado. Documentos procesados: " "%(total)d, documentos con el número de páginas actualizado: %(change)d" -#: views.py:505 +#: views.py:632 #, python-format msgid "" "Are you sure you wish to update the page count for the office documents " @@ -717,7 +833,7 @@ msgstr "" "¿Seguro que desea actualizar el número de páginas de los documentos de " "oficina (%d)?" -#: views.py:534 +#: views.py:664 #, python-format msgid "" "All the page transformations for document: %s, have been deleted " @@ -726,7 +842,7 @@ msgstr "" "Todas las transformaciones de la página de documento: %s, se han eliminado " "con éxito." -#: views.py:536 +#: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " @@ -735,11 +851,11 @@ msgstr "" "Error al eliminar las transformaciones de página para el documento: " "%(document)s; %(error)s." -#: views.py:542 +#: views.py:672 msgid "document transformation" msgstr "transformación de documento" -#: views.py:551 +#: views.py:681 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for document: " @@ -748,7 +864,7 @@ msgstr "" "¿Está seguro que desea eliminar todas las transformaciones de página del " "documento: %s?" -#: views.py:553 +#: views.py:683 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for documents: " @@ -757,73 +873,73 @@ msgstr "" "¿Está seguro que desea eliminar las transformaciones de página de los " "documentos: %s?" -#: views.py:581 +#: views.py:711 msgid "missing documents" msgstr "documentos perdidos" -#: views.py:594 views.py:632 +#: views.py:727 views.py:769 #, python-format msgid "details for: %s" msgstr "detalles para: %s" -#: views.py:647 +#: views.py:788 msgid "Document page edited successfully." msgstr "Página del documento se ha editado correctamente." -#: views.py:656 +#: views.py:797 #, python-format msgid "edit: %s" msgstr "editar: %s" -#: views.py:667 +#: views.py:814 msgid "There are no more pages in this document" msgstr "No hay más páginas en este documento" -#: views.py:680 +#: views.py:832 msgid "You are already at the first page of this document" msgstr "Usted ya está en la primera página de este documento" -#: views.py:823 +#: views.py:993 #, python-format msgid "print: %s" msgstr "Imprimir: %s" -#: views.py:894 +#: views.py:1066 #, python-format msgid "documents of type \"%s\"" msgstr "documentos de tipo \"%s\"" -#: views.py:914 +#: views.py:1086 msgid "Document type edited successfully" msgstr "Tipo de documento editado exitosamente" -#: views.py:917 +#: views.py:1089 #, python-format msgid "Error editing document type; %s" msgstr "Error al modificar el tipo de documento; %s" -#: views.py:922 +#: views.py:1094 #, python-format msgid "edit document type: %s" msgstr "editar tipo de documento: %s" -#: views.py:947 +#: views.py:1118 #, python-format msgid "Document type: %s deleted successfully." msgstr "Tipo de documento: %s eliminado exitosamente." -#: views.py:949 +#: views.py:1120 #, python-format msgid "Document type: %(document_type)s delete error: %(error)s" msgstr "" "Error de eliminación: %(error)s para tipo de documento: %(document_type)s " -#: views.py:964 +#: views.py:1135 #, python-format msgid "Are you sure you wish to delete the document type: %s?" msgstr "¿Está seguro que desea eliminar el tipo de documento: %s?" -#: views.py:965 +#: views.py:1136 msgid "" "The document type of all documents using this document type will be set to " "none." @@ -831,46 +947,46 @@ msgstr "" "El tipo de documento de todos los documentos que utilizan este tipo de " "documentos será borrado." -#: views.py:981 +#: views.py:1152 msgid "Document type created successfully" msgstr "Tipo de documento creado exitosamente." -#: views.py:984 +#: views.py:1155 #, python-format msgid "Error creating document type; %(error)s" msgstr "Error documento creando tipo de documento; %(error)s " -#: views.py:1002 +#: views.py:1173 #, python-format msgid "filenames for document type: %s" msgstr "nombres de archivo para tipo de documento: %s" -#: views.py:1033 +#: views.py:1204 msgid "Document type filename edited successfully" msgstr "Nombre de archivo de tipo de documento editado con exitosamente" -#: views.py:1036 +#: views.py:1207 #, python-format msgid "Error editing document type filename; %s" msgstr "Error al modificar el nombre de archivo para tipo de document; %s" -#: views.py:1041 +#: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" msgstr "" "editar nombre de archivo \"%(filename)s\" del tipo de documento " "\"%(document_type)s\"" -#: views.py:1050 views.py:1076 views.py:1084 +#: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" msgstr "nombre de archivo para tipo de documento" -#: views.py:1068 +#: views.py:1239 #, python-format msgid "Document type filename: %s deleted successfully." msgstr "Nombre de archivo para tipo de documento: %s eliminado exitosamente." -#: views.py:1070 +#: views.py:1241 #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" @@ -878,7 +994,7 @@ msgstr "" "Error de eliminación: %(error)s para nombre de archivo de tipo de documento:" " %(document_type_filename)s " -#: views.py:1086 +#: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " @@ -887,37 +1003,84 @@ msgstr "" "¿Está seguro que desea eliminar el nombre del archivo: %(filename)s, del " "tipo de documento \"%(document_type)s\"?" -#: views.py:1111 +#: views.py:1282 msgid "Document type filename created successfully" msgstr "Nombre de archivo de tipo de documento creado exitosamente." -#: views.py:1114 +#: views.py:1285 #, python-format msgid "Error creating document type filename; %(error)s" msgstr "Error al crear nombre de archivo para tipo de documento; %(error)s" -#: views.py:1120 +#: views.py:1291 #, python-format msgid "create filename for document type: %s" msgstr "crear nombre de archivo para tipo de documento: %s" -#: widgets.py:26 +#: views.py:1306 +msgid "Document image cache cleared successfully" +msgstr "" + +#: views.py:1308 +#, python-format +msgid "Error clearing document image cache; %s" +msgstr "" + +#: views.py:1314 +msgid "Are you sure you wish to clear the document image cache?" +msgstr "" + +#: views.py:1331 +#, python-format +msgid "versions for document: %s" +msgstr "" + +#: views.py:1341 +msgid "time and date" +msgstr "" + +#: views.py:1345 +msgid "mimetype" +msgstr "" + +#: views.py:1349 +msgid "encoding" +msgstr "" + +#: views.py:1380 +msgid "Document version reverted successfully" +msgstr "" + +#: views.py:1382 +#, python-format +msgid "Error reverting document version; %s" +msgstr "" + +#: views.py:1389 +msgid "Are you sure you wish to revert to this version?" +msgstr "" + +#: views.py:1390 +msgid "All later version after this one will be deleted too." +msgstr "" + +#: widgets.py:25 msgid "document page image" msgstr "imagen de página de documento" -#: wizards.py:34 +#: wizards.py:36 msgid "step 1 of 3: Document type" msgstr "paso 1 de 3: Tipo de documento" -#: wizards.py:35 +#: wizards.py:37 msgid "step 2 of 3: Metadata selection" msgstr "paso 2 de 3: Selección de metadatos" -#: wizards.py:36 +#: wizards.py:38 msgid "step 3 of 3: Document metadata" msgstr "paso 3 de 3: Metadatos de documento" -#: wizards.py:44 +#: wizards.py:46 msgid "Next step" msgstr "Siguiente paso" diff --git a/apps/documents/locale/it/LC_MESSAGES/django.mo b/apps/documents/locale/it/LC_MESSAGES/django.mo index e3790f11283091122005f747046decc0f1624b79..33d61db5c8d9a6b9661b27793b209810b67c2638 100644 GIT binary patch delta 4442 zcmYk<3s_e50mtz_cLZ@ zS$QeS7R%-h-^}T9Z3=Df*;db5t+}4nntSG^xee#qo@eF0zxNzA|BpXD|Nl9hbN;t; z)ULe&1G@q|zl#puXDEFnj?4-*CM>|1RYP^um@OlXsls-gi$B3KjEFL3F;=6_cViyj zz-*ipZA=cXz&h;0l{$|ZSTV|fy~jL6rH}*t7>>7b3Wkri+SwRJ+hMoo;TYPLNMDQ- z)gd=V;92{8pMCx^MsoZb>OP;NI(i$+jE4qyo56u?*p5ET!i=%T%)vEyH+Ca~GZ#<~ z{uPeEKicPSp+-C|#b8E zFGB8Z%5Vd&N1eZfHTWJDVk+~v6zfnOeFJN;A9X&CUQEPVWHn6(>OOmL4jw?w;BO~* zjM+?ObfUF+JhojJ!ts5m8yv(+>_t8J3k=33tk)8(LCru9sw3~9He(9wsu|5j{eCGP z!G)NM|L{=J2vX^;mY@JxCR2?$*oc~$Ze;N0RaD2`Mos0!VRi7>ko|8fs5?YN+ta8yD&|X+ymx+flo_3w7fIs0Y4m+lw06TgbAS_fQ@D8|uNs zd5V@Y9@*cf5OsYu@}iiv$e!?+HY#-1JdV2X81l!w$q$X}Q`805ZG%#*j>V!nmWCSH zbkt@m$6#EE{s&^1-QTI(kea$mad&_|uSPgo3V@xX*-SBDD6up32vty{G=|^?w z&!`c7iD4L&YK=G&KM3G=@IH=TOEabzOVf?nggdbmZ`kHewZ6C=Q<;B#P)>4S8vY(P zU{nUvhg&cc-^WE5Ohcd4Y7EC6s1EM3+b3}d?X$KQQG4L$I2^BFHQq$cROvM4U%R%J zr?VSP3u?+9Lp{KY`k)-bGW-A?7*DS|@m|cuU*minO7B<&Q;pg)?Wmc1!uBvSMso%= zLsvXh=2Dr+%g#MaJ!*}fL5-{z^`5?u8o^(Y7r}gq%(h9M&d$dweyC&HaUGt=*_c4@ z7T_A>Q)7DY3SL6ZjOX|a>#xIp)YSb4^}x_Pt0Rdxg7!>|!b;SPt+w5Y(X{uYX6Ptt z05_4zGQ;z&`xm2@wiTIu^O2>;MDiillsIrSHlS|!FlyI7X&-+cN6|io>gd~;jPGI< z-m;I+XT7%2u0qYok8wQ)($MwwsPpYusP}(>3ZH8;b*9yUD%1n&P$PN(>8yDjx8ilw zCwAj3YeqUTl=dFf%sh*$@HDQ#=pyTWn^9}tg1iXEhxhP&^Dz~Tcp7Kb!+EIJtQL>p z{m9@<2n(tiD#kcmhKcwf@tT|R0=b*K)uq8@x0$Kg>Ni~Xqke1w{rYpCblM0Gf< z#AAI@V@j-D8;{kTC_r_n3pLUss0W-zEzMhYyU+F)n8NW7F$Qm=9uPC%`t(jl&0H>O zQy1CoN)HuH)p88R2GqzJQJbn0wb>p;_52{}1}9M0okuOhFrXQ0J3vJ$Y0#RpqD~u0`zyH|oYaFd4gXBKDzfcoj9Z1E>xLlvzs?gSuY{ssk%g zQ}0C0z$OepyDEm;m7?o zt8+QjkJ;^WxSn+R+dTg%D*95fC;a6J+h=hB`5t+ZoFLgmqst^J-ynL`mJ!XGN+4P5 zul@grX6inow zqH>y)lkccOSw)tUU^0h1sek{exQJ>msX^(m@c-0in{`KfuzEk0LZVIi)xm>!fSe+m zh(12)q=7_{BczS|h&)LAPtAozM7v$(b@GTRltbj(q?u^m?DiY@kTrh(>qJ8zoFKA=e3J|%VMOIQ3v&h+k`}vNinGZQ@YaORZh`K0Z(GC9ja=?{0H8HoAPfi`NbD{%gT%@9Of5{{kE@-%J1i delta 4971 zcmZA23vg7`0mkt|NJ0__CIO6ugj^(&Kn!_EAOs?L5ER51;-f%(Ey*QWTy{ftK?KW! zilQP97kt#BLKUH6F+{D3ZIP%5N_7~q)^_Zav5GU+Qk;$`RQvyO4-WQBzWts1Jm;Qs z?#;=yeeT=XC;CZ7{ANQrOtQ&ciN*}+W6YNWwAYyGbYmK@25WEwPQxR3B@WH-j zwqL?h{3n)S?jU1YunFhtI2K|0;NI(_W(t*w?05i^@BkLz`*!!lnN662+mS!h#gEQEfc^0!>}R6Jd`d+<{}Oehk>?vzjtlTMd=g7A zE0fW{EAT>Gi)v^$>c+3*d3eMgKZY8CgbO??P$P2-G6-f14yS$7Wp})fsce6WYTzV} zz#&78DZ~jl23v3ju0wU~&sc#eS;pjJon#7cL5)akm@#8OfYGw{2tYj z8H|5CZox*}7Nw#g`Wn@Q*DuZ63!md<8XP zUm~Mz{)6h+po_c_9*XL4G@pu2EJgLW5;atfsMqc$)Ks(~f97_6v}U$pBEE)toqAB` zzlT~we?r~&bJUccuzrtvumPibzc*3iP*D%7Pz^Vu=5_({2AR82H+UR*6U{Ev8t6d= z!+eOk?mOh(CYcqeCo4vsKhfHV>R219W4Gd9z5gqzXf1Jq zYH{6zda`ZEn`ZW-I{J4^#?MeAbpkbYKcJ>4bBx!aNvICip{|=fhVfTVZ(v6fy7*Qf z8pb(nmtSnmrMMpb_(!bAiXzVys8979s1MM0Sd4{Zz3)OZUeES^@Ca3(gOKE;m} zGyZD$Fgtn|6KeZAOvb+4Ri>iWL?#Zzu{aB>P>XdvY7sw+X?W0Xe~enJr%)r>pH_AM zOwZzW zm8g*_o8bLdosR0jO4LYpp&H(cbSP?$QaO(uComoLz12`=SW7U2?FQ6H`A|=?1DPe$ zgS2VB#`!pgan)RJwC+QV%)f9jX7eWUFIpAhkrvgR6E%_ejU;W^B(f=z$91E9_^b#Dr%@2^@KB!!7v+f zIUd9zSkJ`jhRvvv3ZXi@3KQ`m%)u?FRlgU1h8Hkjx_<|<%Phk}dO@CID8k~yRI0qeEf(7_6>UG|Syus#e)T;j))!`pd9Z9eC-hyGZ zjQ=opfmxz!#nT-+=F@x-a*~x z7;0qxjhe!5Q5{Z=@;TGDIR~?FB+kN1Q61WVdeYsf2KHh+zG=4)SwFy0?EeHaF@c4o z26Au!7NJJ261CXt>~?e(6%Ex~)QuOSo~#oS@h;TjyC2o_t*9Hkh`O!^HH9CdI(QOw z{TWQefqW#ie+Z^vF6#Ig�M9MMKqqx}l3&3rkTqz8CZGX&i}%P&fR_dI~kfahH1? zO-D^pKK8?_QTJ~~b*R(szYUZ0{;#6ahXeNzMz44N^!jWfcMug$F?W*LWDQZ#&DD^~ z98y3IlDo*=L}d?Ar}aQ8uae)BpKF6Mf%bnaWz;mpZ;>9m_X=wpt{_|N_D)<)^2u-P zzG+sy(ki7ybFUId^a^XSs^~+MK%xPDZX(x_E6KT~la0A#66vr9)?yc-rkz`^E#BA1AHi-DEAf zmTVx;5Jf{tMC$A7a?2UZ_UCcTi=W45&d&1Aw@)GiAV2m z9lv_GedI-=@&nxUGvuaz2TXWkls^ z@+5hb=xaEgj3p0~WU`bzM0%I&B1j^CAor7Z$#Y~IQRz#X$uG%e$JQ6w)TiQch{}{)<}Ez%Y!Qt z<13wu!m+Nj%-HjpN!=&1GUAfmr4ct6_J@M8GuboK0&dW^&~<*?*hKkkjG|wzvWH!D$Hvo$%t87B?IY zb)PO@6_-&TwnOJSt!}`X?+?UIXII4bR16>Z(?i{dDqiS&$yMGcdX3n=O%F!g&LzG; qAau63Q~jKv@$oyY{_ZuCZ%$5jBmS0lHxhAUpV!}L$G3J`$^QVxscKvR diff --git a/apps/documents/locale/it/LC_MESSAGES/django.po b/apps/documents/locale/it/LC_MESSAGES/django.po index ac50b2183a..9df2284306 100644 --- a/apps/documents/locale/it/LC_MESSAGES/django.po +++ b/apps/documents/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-07 11:57+0000\n" -"Last-Translator: pippo64 \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,75 +18,67 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:49 __init__.py:159 -msgid "Documents" -msgstr "Documenti" - -#: __init__.py:60 -msgid "Documents setup" -msgstr "Setup Documenti" - -#: __init__.py:70 +#: __init__.py:63 msgid "all documents" msgstr "tutti i documenti" -#: __init__.py:71 models.py:415 views.py:709 +#: __init__.py:64 models.py:636 views.py:871 msgid "recent documents" msgstr "documenti recenti" -#: __init__.py:72 +#: __init__.py:65 msgid "upload new documents" msgstr "upload nuovi documenti" -#: __init__.py:73 +#: __init__.py:66 msgid "clone metadata" msgstr "clona i metadati" -#: __init__.py:74 +#: __init__.py:67 msgid "details" msgstr "dettagli" -#: __init__.py:75 +#: __init__.py:68 msgid "properties" msgstr "proprietà" -#: __init__.py:76 __init__.py:77 __init__.py:92 __init__.py:114 -#: __init__.py:120 +#: __init__.py:69 __init__.py:70 __init__.py:92 __init__.py:116 +#: __init__.py:122 msgid "delete" msgstr "cancella" -#: __init__.py:78 __init__.py:91 __init__.py:113 __init__.py:119 +#: __init__.py:71 __init__.py:91 __init__.py:115 __init__.py:121 msgid "edit" msgstr "edita" -#: __init__.py:79 +#: __init__.py:72 msgid "preview" msgstr "anteprima" -#: __init__.py:80 +#: __init__.py:73 __init__.py:74 __init__.py:75 msgid "download" msgstr "scarica" -#: __init__.py:81 +#: __init__.py:76 msgid "find duplicates" msgstr "trova duplicati" -#: __init__.py:82 +#: __init__.py:77 msgid "find all duplicates" msgstr "trova tutti i duplicati" -#: __init__.py:82 +#: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." msgstr "" "Cerca tutti i documenti con il checksum e restituisci una lista delle " "corrispondenze esatte." -#: __init__.py:83 +#: __init__.py:78 msgid "update office documents' page count" msgstr "update documenti di office numero di pagine" -#: __init__.py:83 +#: __init__.py:78 msgid "" "Update the page count of the office type documents. This is useful when " "enabling office document support after there were already office type " @@ -96,18 +88,32 @@ msgstr "" "enabling office document support after there were already office type " "documents in the database." -#: __init__.py:84 __init__.py:85 +#: __init__.py:79 __init__.py:80 msgid "clear transformations" msgstr "ripulisci le trasformazioni" -#: __init__.py:86 +#: __init__.py:81 msgid "print" msgstr "stampa" -#: __init__.py:87 +#: __init__.py:82 msgid "history" msgstr "versioni" +#: __init__.py:83 +msgid "Find missing document files" +msgstr "Trovare i file di documenti mancanti" + +#: __init__.py:86 +msgid "Clear the document image cache" +msgstr "" + +#: __init__.py:86 +msgid "" +"Clear the graphics representations used to speed up the documents' display " +"and interactive transformations results." +msgstr "" + #: __init__.py:89 msgid "page transformations" msgstr "trasformazioni della pagina" @@ -164,167 +170,146 @@ msgstr "ruotate a sinistra" msgid "reset view" msgstr "ripristino della vista" -#: __init__.py:107 -msgid "Find missing document files" -msgstr "Trovare i file di documenti mancanti" +#: __init__.py:108 +msgid "versions" +msgstr "" -#: __init__.py:110 +#: __init__.py:109 +msgid "revert" +msgstr "" + +#: __init__.py:112 msgid "document type list" msgstr "lista in base al tipo di documento" -#: __init__.py:111 views.py:877 +#: __init__.py:113 views.py:1050 msgid "document types" msgstr "tipi di documenti" -#: __init__.py:112 +#: __init__.py:114 msgid "documents of this type" msgstr "documenti di questo tipo" -#: __init__.py:115 views.py:990 +#: __init__.py:117 views.py:1161 msgid "create document type" msgstr "crea il tipo di documenti" -#: __init__.py:117 +#: __init__.py:119 msgid "filenames" msgstr "nome file" -#: __init__.py:118 +#: __init__.py:120 msgid "add filename to document type" msgstr "aggiungi il nome file al tipo di documento" -#: __init__.py:161 __init__.py:186 models.py:101 views.py:69 +#: __init__.py:164 permissions.py:7 +msgid "Documents" +msgstr "Documenti" + +#: __init__.py:166 __init__.py:179 models.py:90 views.py:79 msgid "documents" msgstr "documenti" -#: __init__.py:173 +#: __init__.py:169 msgid "thumbnail" msgstr "thumbnail" -#: __init__.py:176 -msgid "tags" -msgstr "etichette" - -#: __init__.py:179 +#: __init__.py:172 msgid "metadata" msgstr "metadata" -#: forms.py:60 +#: forms.py:63 msgid "Page image" msgstr "Immagine della pagina" -#: forms.py:70 forms.py:209 +#: forms.py:73 forms.py:270 msgid "Contents" msgstr "Contenuti" -#: forms.py:116 +#: forms.py:109 +msgid "Page" +msgstr "" + +#: forms.py:121 msgid "Details" msgstr "Dettagli" -#: forms.py:121 +#: forms.py:126 msgid "Click on the image for full size preview" msgstr "Click sull'immagine per l'anteprima" -#: forms.py:131 +#: forms.py:136 #, python-format msgid "Document pages (%s)" msgstr "Pagine nel documento (%s)" -#: forms.py:166 +#: forms.py:162 +msgid "Use the new version filename as the document filename" +msgstr "" + +#: forms.py:178 msgid "Quick document rename" msgstr "Rinomina del documento veloce" -#: forms.py:169 +#: forms.py:185 +msgid "Version update" +msgstr "" + +#: forms.py:190 +msgid "Release level" +msgstr "" + +#: forms.py:196 +msgid "Release level serial" +msgstr "" + +#: forms.py:204 +msgid "Comment" +msgstr "" + +#: forms.py:210 msgid "New document filename" msgstr "Nuovo nome documento" -#: forms.py:223 -msgid "Page size" -msgstr "Dimensioni di pagina" - -#: forms.py:224 -msgid "Custom page width" -msgstr "Personalizza larghezza pagina" - -#: forms.py:225 -msgid "Custom page height" -msgstr "Personalizza altezza pagina" - -#: forms.py:226 -msgid "Page orientation" -msgstr "Orientamento pagina" - -#: forms.py:227 +#: forms.py:288 msgid "Page range" msgstr "Intervallo pagina" -#: literals.py:8 -msgid "Create documents" -msgstr "Crea documenti" +#: forms.py:318 +msgid "Compress" +msgstr "" -#: literals.py:9 -msgid "Edit document properties" -msgstr "Modifica proprietà documento" +#: forms.py:318 +msgid "" +"Download the document in the original format or in a compressed manner. " +"This option is selectable only when downloading one document, for multiple " +"documents, the bundle will always be downloads as a compressed file." +msgstr "" #: literals.py:10 -msgid "Edit documents" -msgstr "Modifica documenti" - -#: literals.py:11 -msgid "View documents" -msgstr "Visualizza documenti" - -#: literals.py:12 -msgid "Delete documents" -msgstr "Cancella documenti" - -#: literals.py:13 -msgid "Download documents" -msgstr "Scarica documenti" - -#: literals.py:14 -msgid "Transform documents" -msgstr "Trasforma documenti" - -#: literals.py:15 -msgid "Execute document modifying tools" -msgstr "Esegui i tools per la modifica dei documenti" - -#: literals.py:17 -msgid "Edit document types" -msgstr "Modifica il tipo di documento" - -#: literals.py:18 -msgid "Delete document types" -msgstr "Cancella il tipo di documento" - -#: literals.py:19 -msgid "Create document types" -msgstr "Crea tipo di documento" - -#: literals.py:23 msgid "Document creation" msgstr "Creazione documento" -#: literals.py:24 +#: literals.py:11 #, python-format msgid "Document \"%(content_object)s\" created by %(fullname)s." msgstr "Documento \"%(content_object)s\" creato da by %(fullname)s." -#: literals.py:25 +#: literals.py:12 #, python-format msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." msgstr "Documento \"%(content_object)s\" creato il %(datetime)s da %(fullname)s." -#: literals.py:31 +#: literals.py:18 msgid "Document edited" msgstr "Documento modificato" -#: literals.py:32 +#: literals.py:19 #, python-format msgid "Document \"%(content_object)s\" edited by %(fullname)s." msgstr "Documento \"%(content_object)s\" modificato da %(fullname)s." -#: literals.py:33 +#: literals.py:20 #, python-format msgid "" "Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." @@ -333,58 +318,122 @@ msgstr "" "Documento \"%(content_object)s\" è stato modificato il %(datetime)s da " "%(fullname)s. Queste le seguenti modifiche: %(changes)s." -#: literals.py:42 +#: literals.py:29 msgid "Document deleted" msgstr "Documento cancellato" -#: literals.py:43 +#: literals.py:30 #, python-format msgid "Document \"%(document)s\" deleted by %(fullname)s." msgstr "Documento \"%(document)s\" cancellato da %(fullname)s." -#: literals.py:44 +#: literals.py:31 #, python-format msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." msgstr "Documento \"%(document)s\" cancellato il %(datetime)s da %(fullname)s." -#: models.py:63 +#: literals.py:42 +msgid "final" +msgstr "" + +#: literals.py:43 +msgid "alpha" +msgstr "" + +#: literals.py:44 +msgid "beta" +msgstr "" + +#: literals.py:45 +msgid "release candidate" +msgstr "" + +#: literals.py:46 +msgid "hotfix" +msgstr "" + +#: models.py:61 msgid "name" msgstr "nome" -#: models.py:69 models.py:78 models.py:315 views.py:896 views.py:926 -#: views.py:955 views.py:960 views.py:1003 views.py:1049 views.py:1083 +#: models.py:67 models.py:77 models.py:524 views.py:1068 views.py:1097 +#: views.py:1126 views.py:1131 views.py:1174 views.py:1220 views.py:1254 msgid "document type" msgstr "tipo documento" -#: models.py:70 +#: models.py:68 msgid "documents types" msgstr "documenti tipo" -#: models.py:79 -msgid "file" -msgstr "file" - -#: models.py:86 -msgid "added" -msgstr "ha aggiunto" - -#: models.py:87 -msgid "updated" -msgstr "updated" - -#: models.py:88 -msgid "checksum" -msgstr "checksum" - -#: models.py:89 +#: models.py:78 msgid "description" msgstr "descrizione" -#: models.py:100 models.py:332 models.py:404 models.py:419 views.py:209 +#: models.py:79 +msgid "added" +msgstr "ha aggiunto" + +#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: views.py:351 msgid "document" msgstr "documento" -#: models.py:181 +#: models.py:287 +#, python-format +msgid "Major %(major)i.%(minor)i, (new release)" +msgstr "" + +#: models.py:288 +#, python-format +msgid "Minor %(major)i.%(minor)i, (some updates)" +msgstr "" + +#: models.py:289 +#, python-format +msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" +msgstr "" + +#: models.py:301 +msgid "mayor" +msgstr "" + +#: models.py:302 +msgid "minor" +msgstr "" + +#: models.py:303 +msgid "micro" +msgstr "" + +#: models.py:304 +msgid "release level" +msgstr "" + +#: models.py:305 +msgid "serial" +msgstr "" + +#: models.py:306 +msgid "timestamp" +msgstr "" + +#: models.py:307 views.py:1357 +msgid "comment" +msgstr "" + +#: models.py:310 +msgid "file" +msgstr "file" + +#: models.py:314 +msgid "checksum" +msgstr "checksum" + +#: models.py:318 models.py:319 models.py:542 +msgid "document version" +msgstr "" + +#: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." @@ -392,140 +441,196 @@ msgstr "" "Questo tipo di formato file è sconosciuto, per cui il numero di pagine sarà " "1" -#: models.py:316 +#: models.py:525 views.py:1353 msgid "filename" msgstr "nome file" -#: models.py:317 views.py:1010 +#: models.py:526 views.py:1181 msgid "enabled" msgstr "abilitato" -#: models.py:324 +#: models.py:533 msgid "document type quick rename filename" msgstr "rinomina veloce del nome file del documento" -#: models.py:325 +#: models.py:534 msgid "document types quick rename filenames" msgstr "rinomina veloce del nome files del documento" -#: models.py:333 +#: models.py:545 msgid "content" msgstr "contenuto" -#: models.py:334 +#: models.py:546 msgid "page label" msgstr "etichetta di pagina" -#: models.py:335 +#: models.py:547 msgid "page number" msgstr "numero pagina" -#: models.py:338 +#: models.py:550 #, python-format msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" msgstr "Pagina %(page_num)d di %(total_pages)d del %(document)s" -#: models.py:346 models.py:383 +#: models.py:558 models.py:604 msgid "document page" msgstr "pagina del documento" -#: models.py:347 +#: models.py:559 msgid "document pages" msgstr "pagine di documento" -#: models.py:358 +#: models.py:579 msgid "Enter a valid value." msgstr "Inserisci un valore valido" -#: models.py:384 views.py:333 +#: models.py:605 views.py:449 msgid "order" msgstr "ordina" -#: models.py:385 views.py:334 views.py:389 views.py:418 +#: models.py:606 views.py:450 views.py:511 views.py:542 msgid "transformation" msgstr "trasformazione" -#: models.py:386 views.py:335 +#: models.py:607 views.py:451 msgid "arguments" msgstr "argomenti" -#: models.py:386 +#: models.py:607 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Usa dizionari per identificare gli argomenti, esempio:%s" -#: models.py:394 +#: models.py:615 msgid "document page transformation" msgstr "trasformazione della pagina del documento" -#: models.py:395 +#: models.py:616 msgid "document page transformations" msgstr "trasformazioni della pagina del documento" -#: models.py:403 +#: models.py:624 msgid "user" msgstr "utente" -#: models.py:405 +#: models.py:626 msgid "accessed" msgstr "accessi" -#: models.py:414 +#: models.py:635 msgid "recent document" msgstr "documenti recenti" -#: models.py:420 +#: models.py:641 msgid "Document type" msgstr "Tipo documento" -#: models.py:421 +#: models.py:642 msgid "MIME type" msgstr "Tipo MIME" -#: models.py:422 views.py:117 +#: models.py:643 views.py:132 msgid "Filename" msgstr "Nome file" -#: models.py:423 -msgid "Filename extension" -msgstr "Estensione del file" - -#: models.py:424 +#: models.py:644 msgid "Metadata value" msgstr "Valore del Metadato" -#: models.py:425 +#: models.py:645 msgid "Content" msgstr "Contenuto" -#: models.py:426 +#: models.py:646 msgid "Description" msgstr "Descrizione" -#: models.py:427 +#: models.py:647 msgid "Tags" msgstr "Etichette" -#: models.py:428 +#: models.py:648 msgid "Comments" msgstr "Commenti" -#: statistics.py:38 +#: permissions.py:9 +msgid "Create documents" +msgstr "Crea documenti" + +#: permissions.py:10 +msgid "Edit document properties" +msgstr "Modifica proprietà documento" + +#: permissions.py:11 +msgid "Edit documents" +msgstr "Modifica documenti" + +#: permissions.py:12 +msgid "View documents" +msgstr "Visualizza documenti" + +#: permissions.py:13 +msgid "Delete documents" +msgstr "Cancella documenti" + +#: permissions.py:14 views.py:408 +msgid "Download documents" +msgstr "Scarica documenti" + +#: permissions.py:15 +msgid "Transform documents" +msgstr "Trasforma documenti" + +#: permissions.py:16 +msgid "Execute document modifying tools" +msgstr "Esegui i tools per la modifica dei documenti" + +#: permissions.py:17 +msgid "Revert documents to a previous version" +msgstr "" + +#: permissions.py:18 +msgid "Create new document versions" +msgstr "" + +#: permissions.py:20 +msgid "Documents setup" +msgstr "Setup Documenti" + +#: permissions.py:22 +msgid "View document types" +msgstr "" + +#: permissions.py:23 +msgid "Edit document types" +msgstr "Modifica il tipo di documento" + +#: permissions.py:24 +msgid "Delete document types" +msgstr "Cancella il tipo di documento" + +#: permissions.py:25 +msgid "Create document types" +msgstr "Crea tipo di documento" + +#: statistics.py:40 #, python-format msgid "Document types: %d" msgstr "Tipi di documento: %d " -#: statistics.py:39 +#: statistics.py:41 #, python-format msgid "Documents in database: %d" msgstr "Documenti nel database:%d" -#: statistics.py:44 +#: statistics.py:46 #, python-format msgid "Documents in storage: %d" msgstr "Documenti nello storage:%d" -#: statistics.py:46 +#: statistics.py:48 #, python-format msgid "" "Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" @@ -534,142 +639,153 @@ msgstr "" "Spazio usato nello storage: %(base_2)s (base 2), %(base_10)s (base 10), " "%(bytes)d bytes" -#: statistics.py:56 +#: statistics.py:58 #, python-format msgid "Document pages in database: %d" msgstr "Pagine di documenti nel database:%d" -#: statistics.py:57 +#: statistics.py:59 #, python-format msgid "Minimum amount of pages per document: %(page_count__min)d" msgstr "Numero minimo di pagine per documento:%(page_count__min)d" -#: statistics.py:58 +#: statistics.py:60 #, python-format msgid "Maximum amount of pages per document: %(page_count__max)d" msgstr "Numero massimo di pagine per documento:%(page_count__max)d" -#: statistics.py:59 +#: statistics.py:61 #, python-format msgid "Average amount of pages per document: %(page_count__avg)f" msgstr "Media di pagine per documento:%(page_count__avg)f" -#: statistics.py:65 +#: statistics.py:67 msgid "Document statistics" msgstr "Statistiche del documento" -#: views.py:118 -msgid "File extension" -msgstr "Estensione del file" - -#: views.py:119 +#: views.py:133 msgid "File mimetype" msgstr "File mimetype" -#: views.py:120 +#: views.py:134 msgid "File mime encoding" msgstr "File mime encoding" -#: views.py:121 +#: views.py:135 msgid "File size" msgstr "Dimensioni del file" -#: views.py:122 +#: views.py:136 msgid "Exists in storage" msgstr "Esiste nello storage" -#: views.py:123 +#: views.py:137 msgid "File path in storage" msgstr "File path in storage" -#: views.py:124 +#: views.py:138 msgid "Date added" msgstr "Inserimento data" -#: views.py:125 +#: views.py:139 msgid "Time added" msgstr "Inserimento orario" -#: views.py:126 +#: views.py:140 msgid "Checksum" msgstr "Checksum" -#: views.py:127 +#: views.py:141 msgid "UUID" msgstr "UUID" -#: views.py:128 +#: views.py:142 msgid "Pages" msgstr "Pagine" -#: views.py:137 +#: views.py:151 #, python-format msgid "document properties for: %s" msgstr "Proprietà per il documento:%s" -#: views.py:159 +#: views.py:173 msgid "document data" msgstr "dati del documento" -#: views.py:184 views.py:521 +#: views.py:197 views.py:646 msgid "Must provide at least one document." msgstr "Devi indicare almeno un documento" -#: views.py:200 -#, python-format -msgid "Document: %s deleted successfully." -msgstr "Il documento %s è stato cancellato con successo" +#: views.py:218 +msgid "Document deleted successfully." +msgstr "" -#: views.py:202 +#: views.py:220 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Documento:%(document)s errore cancellazione: %(error)s" -#: views.py:217 +#: views.py:235 #, python-format msgid "Are you sure you wish to delete the document: %s?" msgstr "Sei sicuro di voler cancellare il documento: %s?" -#: views.py:219 +#: views.py:237 #, python-format msgid "Are you sure you wish to delete the documents: %s?" msgstr "Sei sicuro di voler cancellare i documenti: %s?" -#: views.py:256 +#: views.py:276 #, python-format msgid "Document \"%s\" edited successfully." msgstr "Il documento \"%s\" è ancora in modifica" -#: views.py:329 +#: views.py:342 +msgid "documents to be downloaded" +msgstr "" + +#: views.py:352 views.py:1337 +msgid "version" +msgstr "" + +#: views.py:409 +msgid "Download" +msgstr "" + +#: views.py:411 +msgid "Return" +msgstr "" + +#: views.py:445 #, python-format msgid "transformations for: %s" msgstr "trasformazioni per:%s" -#: views.py:353 +#: views.py:472 msgid "Document page transformation created successfully." msgstr "Trasformazioni per la pagina del documento creata con successo" -#: views.py:362 +#: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" msgstr "" "Crea una nuova trasformazione per la pagina: %(page)s del documento: " "%(document)s" -#: views.py:378 +#: views.py:500 msgid "Document page transformation edited successfully." msgstr "Document page trasformation edited successfully." -#: views.py:391 +#: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" msgstr "Modifica la trasformazione \"%(transformation)s\" per: %(document_page)s" -#: views.py:409 +#: views.py:533 msgid "Document page transformation deleted successfully." msgstr "Trasformazione della pagina di documento cancellata con successo." -#: views.py:420 +#: views.py:544 #, python-format msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " @@ -678,25 +794,25 @@ msgstr "" "Sei sicuro di voler cancellare la trasformazione \"%(transformation)s\" per:" " %(document_page)s" -#: views.py:434 +#: views.py:562 #, python-format msgid "duplicates of: %s" msgstr "duplicati di:%s" -#: views.py:446 +#: views.py:574 msgid "Are you sure you wish to find all duplicates?" msgstr "Sei sicuro di voler trovare tutti i duplicati?" -#: views.py:447 views.py:506 views.py:571 +#: views.py:575 views.py:633 views.py:701 msgid "On large databases this operation may take some time to execute." msgstr "" "In un grande database questa operazione potrebbe richiedere del tempo " -#: views.py:462 +#: views.py:598 msgid "duplicated documents" msgstr "documenti duplicati" -#: views.py:497 +#: views.py:624 #, python-format msgid "" "Page count update complete. Documents processed: %(total)d, documents with " @@ -705,7 +821,7 @@ msgstr "" "Update del numero di pagine completato. Il documenti processati " "%(total)d, con il numero di pagine cambiate: %(change)d" -#: views.py:505 +#: views.py:632 #, python-format msgid "" "Are you sure you wish to update the page count for the office documents " @@ -713,7 +829,7 @@ msgid "" msgstr "" "Sei sicuro di voler cambiare il numero di pagine deil documenti office (%d)?" -#: views.py:534 +#: views.py:664 #, python-format msgid "" "All the page transformations for document: %s, have been deleted " @@ -722,7 +838,7 @@ msgstr "" "Tutte le trasformazioni alle pagine del documento:%s, sono state cancellate " "con successo." -#: views.py:536 +#: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " @@ -731,136 +847,136 @@ msgstr "" "Errore nella cancellazione della trasformazione della pagina per il " "documento:%(document)s; %(error)s." -#: views.py:542 +#: views.py:672 msgid "document transformation" msgstr "trasformazione del documento" -#: views.py:551 +#: views.py:681 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for document: " "%s?" msgstr "Sei sicuro di voler cancellare le trasformazioni per il documento:%s?" -#: views.py:553 +#: views.py:683 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for documents: " "%s?" msgstr "Sei sicuro di voler cancellare le trasformazioni per il documenti:%s?" -#: views.py:581 +#: views.py:711 msgid "missing documents" msgstr "documenti mancanti" -#: views.py:594 views.py:632 +#: views.py:727 views.py:769 #, python-format msgid "details for: %s" msgstr "dettagli per:%s" -#: views.py:647 +#: views.py:788 msgid "Document page edited successfully." msgstr "Pagina di documento modificata con successo." -#: views.py:656 +#: views.py:797 #, python-format msgid "edit: %s" msgstr "modifica:%s" -#: views.py:667 +#: views.py:814 msgid "There are no more pages in this document" msgstr "Non ci sono più pagine in questo documento" -#: views.py:680 +#: views.py:832 msgid "You are already at the first page of this document" msgstr "Sei già alla prima pagina del documento" -#: views.py:823 +#: views.py:993 #, python-format msgid "print: %s" msgstr "stampa:%s" -#: views.py:894 +#: views.py:1066 #, python-format msgid "documents of type \"%s\"" msgstr "documenti di tipo \"%s\"" -#: views.py:914 +#: views.py:1086 msgid "Document type edited successfully" msgstr "Tipo di documento modificata con successo" -#: views.py:917 +#: views.py:1089 #, python-format msgid "Error editing document type; %s" msgstr "Errore nella modifica del tipo di documento;%s" -#: views.py:922 +#: views.py:1094 #, python-format msgid "edit document type: %s" msgstr "modifica tipo documento:%s" -#: views.py:947 +#: views.py:1118 #, python-format msgid "Document type: %s deleted successfully." msgstr "Tipo di documento: %s cancellata ." -#: views.py:949 +#: views.py:1120 #, python-format msgid "Document type: %(document_type)s delete error: %(error)s" msgstr "" "Tipo di documento: %(document_type)s errore di cancellazione: %(error)s" -#: views.py:964 +#: views.py:1135 #, python-format msgid "Are you sure you wish to delete the document type: %s?" msgstr "Sei sicuro di cancellare questo tipo di documento:%s?" -#: views.py:965 +#: views.py:1136 msgid "" "The document type of all documents using this document type will be set to " "none." msgstr "Il tipo di documento per tutti i documenti sarà messo a nullo" -#: views.py:981 +#: views.py:1152 msgid "Document type created successfully" msgstr "Tipo di documento creato con successo" -#: views.py:984 +#: views.py:1155 #, python-format msgid "Error creating document type; %(error)s" msgstr "Errore nella creazione del tipo di documento;%(error)s" -#: views.py:1002 +#: views.py:1173 #, python-format msgid "filenames for document type: %s" msgstr "tipo di documento per il nome file: %s" -#: views.py:1033 +#: views.py:1204 msgid "Document type filename edited successfully" msgstr "Tipo di documento per il nome file modificato con successo" -#: views.py:1036 +#: views.py:1207 #, python-format msgid "Error editing document type filename; %s" msgstr "Errore nella modifica del tipo di nome file;%s" -#: views.py:1041 +#: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" msgstr "" "modifica il nome file \"%(filename)s\" per il tipo di documento " "\"%(document_type)s\"" -#: views.py:1050 views.py:1076 views.py:1084 +#: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" msgstr "tipo di nome file per il documento" -#: views.py:1068 +#: views.py:1239 #, python-format msgid "Document type filename: %s deleted successfully." msgstr "Tipo di nome file per il documento: %s cancellato con successo." -#: views.py:1070 +#: views.py:1241 #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" @@ -868,7 +984,7 @@ msgstr "" "Tipo di nome file per il documento:%(document_type_filename)s errore di " "cancellazione: %(error)s" -#: views.py:1086 +#: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " @@ -877,37 +993,84 @@ msgstr "" "Sei sicuro che vuoi cancellare il nome file:%(filename)s, per il tipo di " "documento\"%(document_type)s\"?" -#: views.py:1111 +#: views.py:1282 msgid "Document type filename created successfully" msgstr "Tipo di nome file per nome file creato con successo" -#: views.py:1114 +#: views.py:1285 #, python-format msgid "Error creating document type filename; %(error)s" msgstr "Errore creando il tipo di nome file; %(error)s" -#: views.py:1120 +#: views.py:1291 #, python-format msgid "create filename for document type: %s" msgstr "crea il nome file per i documenti di tipo:%s" -#: widgets.py:26 +#: views.py:1306 +msgid "Document image cache cleared successfully" +msgstr "" + +#: views.py:1308 +#, python-format +msgid "Error clearing document image cache; %s" +msgstr "" + +#: views.py:1314 +msgid "Are you sure you wish to clear the document image cache?" +msgstr "" + +#: views.py:1331 +#, python-format +msgid "versions for document: %s" +msgstr "" + +#: views.py:1341 +msgid "time and date" +msgstr "" + +#: views.py:1345 +msgid "mimetype" +msgstr "" + +#: views.py:1349 +msgid "encoding" +msgstr "" + +#: views.py:1380 +msgid "Document version reverted successfully" +msgstr "" + +#: views.py:1382 +#, python-format +msgid "Error reverting document version; %s" +msgstr "" + +#: views.py:1389 +msgid "Are you sure you wish to revert to this version?" +msgstr "" + +#: views.py:1390 +msgid "All later version after this one will be deleted too." +msgstr "" + +#: widgets.py:25 msgid "document page image" msgstr "immagine della pagina del documento" -#: wizards.py:34 +#: wizards.py:36 msgid "step 1 of 3: Document type" msgstr "step 1 of 3: Tipo documento" -#: wizards.py:35 +#: wizards.py:37 msgid "step 2 of 3: Metadata selection" msgstr "step 2 of 3: Selezione dei Metadata " -#: wizards.py:36 +#: wizards.py:38 msgid "step 3 of 3: Document metadata" msgstr "step 3 of 3: Metadata del documento" -#: wizards.py:44 +#: wizards.py:46 msgid "Next step" msgstr "Next step" diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.mo b/apps/documents/locale/pt/LC_MESSAGES/django.mo index 4e663ecd4d79105fbf5d9d05d11733a347e85048..25d04b452092d5e45ff9b9def3f5271414b78284 100644 GIT binary patch delta 4408 zcmYk-J3AiFa<jx}Cj0_xEF`-|55a`+NL8 z{(jevJ{NX=cbNb8Nsj%7ZH!DO$x+6Hg&7kYtE0vwBp9;{6R{Q_!3I2nOYsx?e0icV z^Vr{o#rO`E;Ahx{SxLsU>pT|Vb*wbTZ{nvI6T^Wf%*9rFe+x#l|D?VDET*u(AF0!f zpc*oY6EPy$IvNmfnu$cq@!6JN|T59lB%)(EQPMFwK z>%n(pJo`@6`30z+cG~Vojlg?I+sqeuH^!w|`vo|e{aVbTe$zr>26`|bhj2E&i;M9l zs$uiKVoU}0;4C~OnX31Y(KMe=HKq_F?lNWqmLP{rHFAkrfoixLb-f?`IMaa{rNsPk)ZCLTg&&HNly(N(O$8(4w& z&|0mTRT+%G3cVbNL?7zLL2Smos0y#41D%=1EXPt*&v&94a0>ODNaj%^nSi=J8%r?{ z)!MR&Y6!;4Z4jQx-eFndJ>PiZYrvwS*QnBpjLS!YKU9# z9$bxD1J7U-9z(qqBdF{BXDMh=jG-R<0jk2^+J218hPj1mSR&)A3Z1AayAN5PrX6*k z2U+lDJ8JF^Ape;Y{Ly`vP!0PC>5$(cc}aRit6D%(Sf(^iMnAO>cKu#L$;wF z{JedB2qW1)h`Rrn?dzx^KZknG1yqNAjnUL^{zO4T_bEo=ZPbNfIo5+Fp&FKo`m*KN z$IDRH$-L5tZ(@ccCh~$K8($?jj6)ps6~APOEE2LT6@+=`l#w~oBT^=TJTQ7q(;eJgdQeR7cJt zk2Kd%4N9ap`flW*My?Tg^-TvR>HYUpi08mQ)KDHlFa8QO_chGV7F>+AcmY>q3?FxDwBxdYHs8rD6{1`uWHyQ-^AZANiP?J(Bv(X$o`kGKO9|CYtFqiKscO zM?JX3-tR&^s2?>o+b{u#Q6u&Wrr~MSb1tGfbO)m`jTNf5A_M)ZFrR|vycG3-2Gr0l zM-5>Y=He#I!^4<@@1uHh9jBwC#(K^S)LNK}s`w$)bzW3QhEeBF)G+?);RhVh1Fxc5 z{yFNx7$!6dr=!l#L^ZV1KHiL~xD}V78+HGA)N`-cUPtx(Z>Y6)3-ugFo!|N=Q)->H zN*7_M$EYFQgc_0Es2c;Q5j%=%;7QaRzl*y57pPD86;uV+P}lt(HKO5sRCHYmPQx5O z1uooo9=H?rzyqiUji5$m6xHzGUkg#3WCkO28U*-O4g zvWT|tQonhcJWLLf9}>OOFOp&M4yhyKn~TDu_Kp_NcgQm&XdmlCUh~j)lE3;8^^nlq zhmP{UaJKVN^@o1jBkY5VZ3VxQX1fYs+F~g0C%ehFNDKg;{f3&BDCq%>bJ}LP;b-$QbL|3 zVBivIyq6uppB7d`2PPCx3eK9hBRp`vVlcS0(jO7HQJor`Jb&thKz>7M JU|mDy{{U}G-1-0j delta 4803 zcmaLYdvH|c9merDun@xC5E2NNEEtlIG$ES+NfwX*Ay7;JX+TOMa3o8zk_%)v+>Bi; zH>H5k1uBRLf>4UcWi1x92&Pm^JECoc(qf&l#iH$4EKF^c8Tx(poH&es^h}<7-gDXa zyyy46XZOsLG5a^gg#H}w+HTn1CjCiOM`OCh7_+;pjvDiBPh+OydpHi=_ZU-(4`VqV zMxFlxM`CHbF&=yj^Y9ohz>jc_&i67V8~0(6F(Gr2Mkfx$B^Z-|@u>Y#7>gy&ei`;= ze}ij2Wr!p?Xdb^T4$^>OTU!DLjwX*iPmn;aVI$cH2FMO=X&VJ=oB z8dHp$a4^1uy3yyTj@u_0(*qMw=TlKnKFM(n?0KreEMDZvnZnYlFd z1j|q#T#q`w3pL^hcE`7HEM7vYY7$v68b}su09B~9um&}izrz%~jc)8ez^>dFRDaV3 zP=DQUE(cVBC8&-=sF7|%t%W_P>kc9JHm~AByo9=L4E3CelduS%#Tj@Rb)!s1F$;@O z=eOX!cp)WZFOttVppIN_d#<~qN;?g;n4Un*b=cWIfV%z|cEHofaxrh<{rEm=0E3uE z7Y1=Uu0U1h0%|}vLo{@QDNK+`Jrnf-KMuzR)D!GSP02}QI?b;!4?jj#s4tI0G0b4p zfQnHSEkzBq0(IS7)Ie)c{e~W+q1Ry}s`T4%2p&c)l8e|8KS8}dH&EB#My(lFs@-t{ z>V^Xxvyf>wMW}(zLftTkn!?q{3lK8T(a;B9LEb2H9^>&Uau4%Q)CYSpDh+Hf|MWzY zQPc&%% z3e~Vh2pP@<^Gt7R%Zdky6B2L1osDbUkb$Ai; zaaOJtoiQ6Q72gTb;59HeQH!YyzZ6;|DL528I0h?mEbhen@Cs_m`cNKm< z)L2J@X*Y*a1NZ=0C+1_+9QQ4@J5ELI7os|vfPHWV_QXY~3bvr0a2=|jJ*WqI5A}WV z57gUptC;%hhN`1V6Nl=cAF3ilP$exyzB^1g4#lOYU$MQY2RMcO@d~P+e`6|k8gJh? z8+F}eRD~9y&WFZ_>?b9j9Um>hob# zrH(kBLOuC8)FS*9s-G(%8aXunjsq~c#Cc*=Ny||cnTz^hEvjP6QBU$Xx^O${`dz5s zf+MIKoIqXIimK>k)ODX?KMZ|ELvxul(LRxex9E9QZB9{ZQCXq!<`-0l&K|}rjz7J@-+Do zQAPMIGDpZ@vW@u3JfeB;MzrD|B=bp_{DNe0e{+~<>tGWt=L57KarS4UD$(BA7ss6T z%Z{0jt*B}9Is4Dz8KSwLK_-*)WFz?@3GL&bwprvX(HFg5re->tHu5?ac?UE~zGmt>H~NZa;=(^&2J6ATi5 zTcYp3zC^THHqrlk`M;lRCvTCqEr~`Y8A&>lLOuT;8Y9RGqRmU(YOuXR=8~aAmD2Wo zGM#K8C8UPjy$y7Ba&Qtk;p{)^XvWpmxr4Pn_hPHY=Z*~Qd98iwgyul7vEDvX>+{#t z2F=}vmieoLwUKrSg&kd9_mDvNL}E(Bn;hRR&bK`1YY6xo8^Wdi%X-%N8mxMs`|E>| zr}}@`E~T-_?`sHJL9Q~>b;~BJp~h!71OAnfrj(M{_Et?G{Bqjx4%JrBR~^2VW`*n1 zle&4bJ)Z2mJh#W=%^Mlsn%?g|Pj+rmc7Coq&*SyvX63SVF0%r`>F9 z?`sM)HUt{2CSSlky4tri$2k=KZ~FYMW!%1*ad_Q}gW=g3m65X<2VBMD>VnNpmb=<= zFK*pe<8Q!dFIJs@rB!X2GOMZP|6LGSkX;lT{$pNpBs_dayIvEcg=yX2=&ts;t)?Z- z{-xpcf|gEgha)=*Hn#6N%`Q#rAubFjjv5?aVbxm=wS4I7VMGc>CC9mfs?YS25uL4I Nvpu55@R}0u{{S*2M7aO} diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.po b/apps/documents/locale/pt/LC_MESSAGES/django.po index 97034e32f9..bbd8ae7762 100644 --- a/apps/documents/locale/pt/LC_MESSAGES/django.po +++ b/apps/documents/locale/pt/LC_MESSAGES/django.po @@ -1,111 +1,116 @@ # 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-09-30 21:10+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-02 14:17-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" "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:49 __init__.py:159 -msgid "Documents" -msgstr "Documentos" - -#: __init__.py:60 -msgid "Documents setup" -msgstr "Configuração de documentos" - -#: __init__.py:70 +#: __init__.py:63 msgid "all documents" msgstr "todos os documentos" -#: __init__.py:71 models.py:415 views.py:709 +#: __init__.py:64 models.py:636 views.py:871 msgid "recent documents" msgstr "documentos recentes" -#: __init__.py:72 +#: __init__.py:65 msgid "upload new documents" msgstr "upload de novos documentos" -#: __init__.py:73 +#: __init__.py:66 msgid "clone metadata" msgstr "clonar metadados" -#: __init__.py:74 +#: __init__.py:67 msgid "details" msgstr "detalhes" -#: __init__.py:75 +#: __init__.py:68 msgid "properties" msgstr "propriedades" -#: __init__.py:76 __init__.py:77 __init__.py:92 __init__.py:114 -#: __init__.py:120 +#: __init__.py:69 __init__.py:70 __init__.py:92 __init__.py:116 +#: __init__.py:122 msgid "delete" msgstr "excluir" -#: __init__.py:78 __init__.py:91 __init__.py:113 __init__.py:119 +#: __init__.py:71 __init__.py:91 __init__.py:115 __init__.py:121 msgid "edit" msgstr "editar" -#: __init__.py:79 +#: __init__.py:72 msgid "preview" msgstr "visualização" -#: __init__.py:80 +#: __init__.py:73 __init__.py:74 __init__.py:75 msgid "download" msgstr "baixar" -#: __init__.py:81 +#: __init__.py:76 msgid "find duplicates" msgstr "encontrar duplicatas" -#: __init__.py:82 +#: __init__.py:77 msgid "find all duplicates" msgstr "encontrar todas as duplicatas" -#: __init__.py:82 +#: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." msgstr "" "Pesquisar todas as somas de verificação de documentos e retornar uma lista " "de correspondências exatas." -#: __init__.py:83 +#: __init__.py:78 msgid "update office documents' page count" msgstr "" -#: __init__.py:83 +#: __init__.py:78 msgid "" "Update the page count of the office type documents. This is useful when " "enabling office document support after there were already office type " "documents in the database." msgstr "" -#: __init__.py:84 __init__.py:85 +#: __init__.py:79 __init__.py:80 msgid "clear transformations" msgstr "remover transformações" -#: __init__.py:86 +#: __init__.py:81 msgid "print" msgstr "imprimir" -#: __init__.py:87 +#: __init__.py:82 msgid "history" msgstr "história" +#: __init__.py:83 +msgid "Find missing document files" +msgstr "Encontrar arquivos de documentos em falta" + +#: __init__.py:86 +msgid "Clear the document image cache" +msgstr "" + +#: __init__.py:86 +msgid "" +"Clear the graphics representations used to speed up the documents' display " +"and interactive transformations results." +msgstr "" + #: __init__.py:89 msgid "page transformations" msgstr "transformações de página" @@ -162,513 +167,621 @@ msgstr "girar para a esquerda" msgid "reset view" msgstr "redefinir visão" -#: __init__.py:107 -msgid "Find missing document files" -msgstr "Encontrar arquivos de documentos em falta" +#: __init__.py:108 +msgid "versions" +msgstr "" -#: __init__.py:110 +#: __init__.py:109 +msgid "revert" +msgstr "" + +#: __init__.py:112 msgid "document type list" msgstr "lista de tipo de documento" -#: __init__.py:111 views.py:877 +#: __init__.py:113 views.py:1050 msgid "document types" msgstr "tipos de documentos" -#: __init__.py:112 +#: __init__.py:114 msgid "documents of this type" msgstr "documentos deste tipo" -#: __init__.py:115 views.py:990 +#: __init__.py:117 views.py:1161 msgid "create document type" msgstr "criar tipo de documento" -#: __init__.py:117 +#: __init__.py:119 msgid "filenames" msgstr "nomes de arquivos" -#: __init__.py:118 +#: __init__.py:120 msgid "add filename to document type" msgstr "adicionar nome do arquivo para o tipo de documento" -#: __init__.py:161 __init__.py:186 models.py:101 views.py:69 +#: __init__.py:164 permissions.py:7 +msgid "Documents" +msgstr "Documentos" + +#: __init__.py:166 __init__.py:179 models.py:90 views.py:79 msgid "documents" msgstr "documentos" -#: __init__.py:173 +#: __init__.py:169 msgid "thumbnail" msgstr "miniatura" -#: __init__.py:176 -msgid "tags" -msgstr "tags" - -#: __init__.py:179 +#: __init__.py:172 msgid "metadata" msgstr "metadado" -#: forms.py:60 +#: forms.py:63 msgid "Page image" msgstr "Imagem da página" -#: forms.py:70 forms.py:209 +#: forms.py:73 forms.py:270 msgid "Contents" msgstr "Conteúdos" -#: forms.py:116 +#: forms.py:109 +msgid "Page" +msgstr "" + +#: forms.py:121 msgid "Details" msgstr "Detalhes" -#: forms.py:121 +#: forms.py:126 msgid "Click on the image for full size preview" msgstr "Clique na imagem para visualizar em tamanho completo" -#: forms.py:131 +#: forms.py:136 #, python-format msgid "Document pages (%s)" msgstr "Páginas do documento (%s)" -#: forms.py:166 +#: forms.py:162 +msgid "Use the new version filename as the document filename" +msgstr "" + +#: forms.py:178 msgid "Quick document rename" msgstr "Renomear documento rápido" -#: forms.py:169 +#: forms.py:185 +msgid "Version update" +msgstr "" + +#: forms.py:190 +msgid "Release level" +msgstr "" + +#: forms.py:196 +msgid "Release level serial" +msgstr "" + +#: forms.py:204 +msgid "Comment" +msgstr "" + +#: forms.py:210 msgid "New document filename" msgstr "Novo nome de arquivo" -#: forms.py:223 -msgid "Page size" -msgstr "Tamanho da página" - -#: forms.py:224 -msgid "Custom page width" -msgstr "Largura da página personalizada" - -#: forms.py:225 -msgid "Custom page height" -msgstr "Altura da página personalizada" - -#: forms.py:226 -msgid "Page orientation" -msgstr "Orientação da página" - -#: forms.py:227 +#: forms.py:288 msgid "Page range" msgstr "Intervalo de páginas" -#: literals.py:8 -msgid "Create documents" -msgstr "Criar documentos" +#: forms.py:318 +msgid "Compress" +msgstr "" -#: literals.py:9 -msgid "Edit document properties" -msgstr "Editar propriedades de documento" +#: forms.py:318 +msgid "" +"Download the document in the original format or in a compressed manner. " +"This option is selectable only when downloading one document, for multiple " +"documents, the bundle will always be downloads as a compressed file." +msgstr "" #: literals.py:10 -msgid "Edit documents" -msgstr "Editar documentos" - -#: literals.py:11 -msgid "View documents" -msgstr "Ver documentos" - -#: literals.py:12 -msgid "Delete documents" -msgstr "Excluir documentos" - -#: literals.py:13 -msgid "Download documents" -msgstr "Baixar documentos" - -#: literals.py:14 -msgid "Transform documents" -msgstr "Transformar documentos" - -#: literals.py:15 -msgid "Execute document modifying tools" -msgstr "Execute as ferramentas de modificação de documento" - -#: literals.py:17 -msgid "Edit document types" -msgstr "Editar tipos de documentos" - -#: literals.py:18 -msgid "Delete document types" -msgstr "Excluir tipos de documentos" - -#: literals.py:19 -msgid "Create document types" -msgstr "Criar tipos de documentos" - -#: literals.py:23 msgid "Document creation" msgstr "Criação de documentos" -#: literals.py:24 +#: literals.py:11 #, python-format msgid "Document \"%(content_object)s\" created by %(fullname)s." msgstr "Documento \"%(content_object)s\" criado por %(fullname)s." -#: literals.py:25 +#: literals.py:12 #, python-format -msgid "" -"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." -msgstr "" -"Documento \"%(content_object)s\" criado em %(datetime)s por %(fullname)s." +msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "Documento \"%(content_object)s\" criado em %(datetime)s por %(fullname)s." -#: literals.py:31 +#: literals.py:18 msgid "Document edited" msgstr "Documento editado" -#: literals.py:32 +#: literals.py:19 #, python-format msgid "Document \"%(content_object)s\" edited by %(fullname)s." msgstr "Documento \"%(content_object)s\" editado por %(fullname)s." -#: literals.py:33 +#: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " -"The following changes took place: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." +" The following changes took place: %(changes)s." msgstr "" "Documento \"%(content_object)s\" foi editado em %(datetime)s por " "%(fullname)s. As seguintes alterações foram realizadas: %(changes)s." -#: literals.py:42 +#: literals.py:29 msgid "Document deleted" msgstr "Documento excluído" -#: literals.py:43 +#: literals.py:30 #, python-format msgid "Document \"%(document)s\" deleted by %(fullname)s." msgstr "Documento \"%(document)s\" deletado por %(fullname)s." -#: literals.py:44 +#: literals.py:31 #, python-format msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." msgstr "Documento \"%(document)s\" deletado em %(datetime)s por %(fullname)s." -#: models.py:63 +#: literals.py:42 +msgid "final" +msgstr "" + +#: literals.py:43 +msgid "alpha" +msgstr "" + +#: literals.py:44 +msgid "beta" +msgstr "" + +#: literals.py:45 +msgid "release candidate" +msgstr "" + +#: literals.py:46 +msgid "hotfix" +msgstr "" + +#: models.py:61 msgid "name" msgstr "nome" -#: models.py:69 models.py:78 models.py:315 views.py:896 views.py:926 -#: views.py:955 views.py:960 views.py:1003 views.py:1049 views.py:1083 +#: models.py:67 models.py:77 models.py:524 views.py:1068 views.py:1097 +#: views.py:1126 views.py:1131 views.py:1174 views.py:1220 views.py:1254 msgid "document type" msgstr "tipo de documento" -#: models.py:70 +#: models.py:68 msgid "documents types" msgstr "tipos de documentos" -#: models.py:79 -msgid "file" -msgstr "arquivo" - -#: models.py:86 -msgid "added" -msgstr "adicionado" - -#: models.py:87 -msgid "updated" -msgstr "atualizado" - -#: models.py:88 -msgid "checksum" -msgstr "verificações" - -#: models.py:89 +#: models.py:78 msgid "description" msgstr "descrição" -#: models.py:100 models.py:332 models.py:404 models.py:419 views.py:209 +#: models.py:79 +msgid "added" +msgstr "adicionado" + +#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: views.py:351 msgid "document" msgstr "documento" -#: models.py:181 +#: models.py:287 +#, python-format +msgid "Major %(major)i.%(minor)i, (new release)" +msgstr "" + +#: models.py:288 +#, python-format +msgid "Minor %(major)i.%(minor)i, (some updates)" +msgstr "" + +#: models.py:289 +#, python-format +msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" +msgstr "" + +#: models.py:301 +msgid "mayor" +msgstr "" + +#: models.py:302 +msgid "minor" +msgstr "" + +#: models.py:303 +msgid "micro" +msgstr "" + +#: models.py:304 +msgid "release level" +msgstr "" + +#: models.py:305 +msgid "serial" +msgstr "" + +#: models.py:306 +msgid "timestamp" +msgstr "" + +#: models.py:307 views.py:1357 +msgid "comment" +msgstr "" + +#: models.py:310 +msgid "file" +msgstr "arquivo" + +#: models.py:314 +msgid "checksum" +msgstr "verificações" + +#: models.py:318 models.py:319 models.py:542 +msgid "document version" +msgstr "" + +#: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." msgstr "" -"Este formato de arquivo não é conhecida, a contagem de página, portanto, tem " -"o padrão 1." +"Este formato de arquivo não é conhecida, a contagem de página, portanto, tem" +" o padrão 1." -#: models.py:316 +#: models.py:525 views.py:1353 msgid "filename" msgstr "nome do arquivo" -#: models.py:317 views.py:1010 +#: models.py:526 views.py:1181 msgid "enabled" msgstr "habilitado" -#: models.py:324 +#: models.py:533 msgid "document type quick rename filename" msgstr "tipo de documento renomear rápido" -#: models.py:325 +#: models.py:534 msgid "document types quick rename filenames" msgstr "tipos de documentos renomear rápido" -#: models.py:333 +#: models.py:545 msgid "content" msgstr "conteúdo" -#: models.py:334 +#: models.py:546 msgid "page label" msgstr "etiqueta da página" -#: models.py:335 +#: models.py:547 msgid "page number" msgstr "número da página" -#: models.py:338 +#: models.py:550 #, python-format msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" msgstr "Pagina %(page_num)d de %(total_pages)d em %(document)s" -#: models.py:346 models.py:383 +#: models.py:558 models.py:604 msgid "document page" msgstr "página do documento" -#: models.py:347 +#: models.py:559 msgid "document pages" msgstr "páginas do documento" -#: models.py:358 +#: models.py:579 msgid "Enter a valid value." msgstr "Digite um valor válido." -#: models.py:384 views.py:333 +#: models.py:605 views.py:449 msgid "order" msgstr "ordem" -#: models.py:385 views.py:334 views.py:389 views.py:418 +#: models.py:606 views.py:450 views.py:511 views.py:542 msgid "transformation" msgstr "transformação" -#: models.py:386 views.py:335 +#: models.py:607 views.py:451 msgid "arguments" msgstr "argumentos" -#: models.py:386 +#: models.py:607 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Use dicionários para identificar os argumentos, exemplo: %s" -#: models.py:394 +#: models.py:615 msgid "document page transformation" msgstr "página de transformações do documento" -#: models.py:395 +#: models.py:616 msgid "document page transformations" msgstr "Página de transformações de documentos" -#: models.py:403 +#: models.py:624 msgid "user" msgstr "usuário" -#: models.py:405 +#: models.py:626 msgid "accessed" msgstr "acessado" -#: models.py:414 +#: models.py:635 msgid "recent document" msgstr "documento recente" -#: models.py:420 +#: models.py:641 msgid "Document type" msgstr "Tipo de documento" -#: models.py:421 +#: models.py:642 msgid "MIME type" msgstr "Tipo MIME" -#: models.py:422 views.py:117 +#: models.py:643 views.py:132 msgid "Filename" msgstr "Nome do arquivo" -#: models.py:423 -msgid "Filename extension" -msgstr "Extensão do arquivo" - -#: models.py:424 +#: models.py:644 msgid "Metadata value" msgstr "Valor de metadados" -#: models.py:425 +#: models.py:645 msgid "Content" msgstr "Conteúdo" -#: models.py:426 +#: models.py:646 msgid "Description" msgstr "Descrição" -#: models.py:427 +#: models.py:647 msgid "Tags" msgstr "Tags" -#: models.py:428 +#: models.py:648 msgid "Comments" msgstr "Comentários" -#: statistics.py:38 +#: permissions.py:9 +msgid "Create documents" +msgstr "Criar documentos" + +#: permissions.py:10 +msgid "Edit document properties" +msgstr "Editar propriedades de documento" + +#: permissions.py:11 +msgid "Edit documents" +msgstr "Editar documentos" + +#: permissions.py:12 +msgid "View documents" +msgstr "Ver documentos" + +#: permissions.py:13 +msgid "Delete documents" +msgstr "Excluir documentos" + +#: permissions.py:14 views.py:408 +msgid "Download documents" +msgstr "Baixar documentos" + +#: permissions.py:15 +msgid "Transform documents" +msgstr "Transformar documentos" + +#: permissions.py:16 +msgid "Execute document modifying tools" +msgstr "Execute as ferramentas de modificação de documento" + +#: permissions.py:17 +msgid "Revert documents to a previous version" +msgstr "" + +#: permissions.py:18 +msgid "Create new document versions" +msgstr "" + +#: permissions.py:20 +msgid "Documents setup" +msgstr "Configuração de documentos" + +#: permissions.py:22 +msgid "View document types" +msgstr "" + +#: permissions.py:23 +msgid "Edit document types" +msgstr "Editar tipos de documentos" + +#: permissions.py:24 +msgid "Delete document types" +msgstr "Excluir tipos de documentos" + +#: permissions.py:25 +msgid "Create document types" +msgstr "Criar tipos de documentos" + +#: statistics.py:40 #, python-format msgid "Document types: %d" msgstr "Tipos de documentos: %d" -#: statistics.py:39 +#: statistics.py:41 #, python-format msgid "Documents in database: %d" msgstr "Documentos no banco de dados: %d" -#: statistics.py:44 +#: statistics.py:46 #, python-format msgid "Documents in storage: %d" msgstr "Documentos no armazenamento: %d" -#: statistics.py:46 +#: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " -"bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" +" bytes" msgstr "" "Espaço usado no armazenamento: %(base_2)s (base 2), %(base_10)s (base 10), " "%(bytes)d bytes" -#: statistics.py:56 +#: statistics.py:58 #, python-format msgid "Document pages in database: %d" msgstr "Páginas do documento no banco de dados: %d" -#: statistics.py:57 +#: statistics.py:59 #, python-format msgid "Minimum amount of pages per document: %(page_count__min)d" msgstr "Quantidade mínima de páginas por documento: %(page_count__min)d" -#: statistics.py:58 +#: statistics.py:60 #, python-format msgid "Maximum amount of pages per document: %(page_count__max)d" msgstr "Quantidade máxima de páginas por documento: %(page_count__max)d" -#: statistics.py:59 +#: statistics.py:61 #, python-format msgid "Average amount of pages per document: %(page_count__avg)f" msgstr "Quantidade média de páginas por documento: %(page_count__avg)f" -#: statistics.py:65 +#: statistics.py:67 msgid "Document statistics" msgstr "Estatísticas do documento" -#: views.py:118 -msgid "File extension" -msgstr "Extensão de arquivo" - -#: views.py:119 +#: views.py:133 msgid "File mimetype" msgstr "Mimetype do arquivo" -#: views.py:120 +#: views.py:134 msgid "File mime encoding" msgstr "Codificação MIME do arquivo" -#: views.py:121 +#: views.py:135 msgid "File size" msgstr "Tamanho do arquivo" -#: views.py:122 +#: views.py:136 msgid "Exists in storage" msgstr "Existe no armazenamento" -#: views.py:123 +#: views.py:137 msgid "File path in storage" msgstr "Caminho do arquivo no armazenamento" -#: views.py:124 +#: views.py:138 msgid "Date added" msgstr "Data de adição" -#: views.py:125 +#: views.py:139 msgid "Time added" msgstr "Horario de adição" -#: views.py:126 +#: views.py:140 msgid "Checksum" msgstr "Verificação" -#: views.py:127 +#: views.py:141 msgid "UUID" msgstr "UUID" -#: views.py:128 +#: views.py:142 msgid "Pages" msgstr "Páginas" -#: views.py:137 +#: views.py:151 #, python-format msgid "document properties for: %s" msgstr "propriedades de documento para: %s" -#: views.py:159 +#: views.py:173 msgid "document data" msgstr "dados do documento" -#: views.py:184 views.py:521 +#: views.py:197 views.py:646 msgid "Must provide at least one document." msgstr "Deve fornecer pelo menos um documento." -#: views.py:200 -#, python-format -msgid "Document: %s deleted successfully." -msgstr "Documento: %s apagado com sucesso." +#: views.py:218 +msgid "Document deleted successfully." +msgstr "" -#: views.py:202 +#: views.py:220 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Erro ao excluir documento %(document)s: %(error)s" -#: views.py:217 +#: views.py:235 #, python-format msgid "Are you sure you wish to delete the document: %s?" msgstr "Tem certeza de que deseja excluir o documento: %s?" -#: views.py:219 +#: views.py:237 #, python-format msgid "Are you sure you wish to delete the documents: %s?" msgstr "Tem certeza de que deseja excluir os documentos: %s?" -#: views.py:256 +#: views.py:276 #, python-format msgid "Document \"%s\" edited successfully." msgstr "Documento \"%s\", editado com sucesso." -#: views.py:329 +#: views.py:342 +msgid "documents to be downloaded" +msgstr "" + +#: views.py:352 views.py:1337 +msgid "version" +msgstr "" + +#: views.py:409 +msgid "Download" +msgstr "" + +#: views.py:411 +msgid "Return" +msgstr "" + +#: views.py:445 #, python-format msgid "transformations for: %s" msgstr "transformações para: %s" -#: views.py:353 +#: views.py:472 msgid "Document page transformation created successfully." msgstr "Transformação para página do documento criada com sucesso." -#: views.py:362 +#: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" msgstr "" "Criar nova transformação para página: %(page)s do documento: %(document)s" -#: views.py:378 +#: views.py:500 msgid "Document page transformation edited successfully." msgstr "Transformação para página do documento editada com sucesso." -#: views.py:391 +#: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" msgstr "Editar transformação \"%(transformation)s\" para: %(document_page)s " -#: views.py:409 +#: views.py:533 msgid "Document page transformation deleted successfully." msgstr "Transformação para página do documento excluida com sucesso." -#: views.py:420 +#: views.py:544 #, python-format msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " @@ -677,38 +790,40 @@ msgstr "" "Tem certeza de que deseja excluir \"%(transformation)s\" para: " "%(document_page)s " -#: views.py:434 +#: views.py:562 #, python-format msgid "duplicates of: %s" msgstr "duplicatas de: %s" -#: views.py:446 +#: views.py:574 msgid "Are you sure you wish to find all duplicates?" msgstr "Tem certeza de que deseja encontrar todas as duplicatas?" -#: views.py:447 views.py:506 views.py:571 +#: views.py:575 views.py:633 views.py:701 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." +"Em grandes bases de dados esta operação pode levar algum tempo para " +"executar." -#: views.py:462 +#: views.py:598 msgid "duplicated documents" msgstr "documentos duplicados" -#: views.py:497 +#: views.py:624 #, python-format msgid "" "Page count update complete. Documents processed: %(total)d, documents with " "changed page count: %(change)d" msgstr "" -#: views.py:505 -#, fuzzy, python-format +#: views.py:632 +#, python-format msgid "" -"Are you sure you wish to update the page count for the office documents (%d)?" -msgstr "Tem certeza de que deseja excluir os documentos: %s?" +"Are you sure you wish to update the page count for the office documents " +"(%d)?" +msgstr "" -#: views.py:534 +#: views.py:664 #, python-format msgid "" "All the page transformations for document: %s, have been deleted " @@ -717,7 +832,7 @@ msgstr "" "Todas as transformações de página para o documento: %s, foram excluídas com " "sucesso." -#: views.py:536 +#: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " @@ -726,19 +841,20 @@ msgstr "" "Erro ao excluir as transformações de página para o documento: %(document)s; " "%(error)s ." -#: views.py:542 +#: views.py:672 msgid "document transformation" msgstr "transformação de documento" -#: views.py:551 +#: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: %s?" +"Are you sure you wish to clear all the page transformations for document: " +"%s?" msgstr "" "Tem certeza de que deseja limpar todas as transformações de página para o " "documento: %s?" -#: views.py:553 +#: views.py:683 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for documents: " @@ -747,72 +863,72 @@ msgstr "" "Tem certeza de que deseja limpar todas as transformações de página para os " "documentos: %s?" -#: views.py:581 +#: views.py:711 msgid "missing documents" msgstr "documentos em falta" -#: views.py:594 views.py:632 +#: views.py:727 views.py:769 #, python-format msgid "details for: %s" msgstr "detalhes para: %s" -#: views.py:647 +#: views.py:788 msgid "Document page edited successfully." msgstr "Página do documento editado com sucesso." -#: views.py:656 +#: views.py:797 #, python-format msgid "edit: %s" msgstr "editar: %s" -#: views.py:667 +#: views.py:814 msgid "There are no more pages in this document" msgstr "Não há mais páginas neste documento" -#: views.py:680 +#: views.py:832 msgid "You are already at the first page of this document" msgstr "Você já está na primeira página deste documento" -#: views.py:823 +#: views.py:993 #, python-format msgid "print: %s" msgstr "imprimir: %s" -#: views.py:894 +#: views.py:1066 #, python-format msgid "documents of type \"%s\"" msgstr "documentos do tipo \"%s\"" -#: views.py:914 +#: views.py:1086 msgid "Document type edited successfully" msgstr "Tipo de documento editado com sucesso" -#: views.py:917 +#: views.py:1089 #, python-format msgid "Error editing document type; %s" msgstr "Erro ao editar tipo de documento; %s" -#: views.py:922 +#: views.py:1094 #, python-format msgid "edit document type: %s" msgstr "editar tipo de documento: %s" -#: views.py:947 +#: views.py:1118 #, python-format msgid "Document type: %s deleted successfully." msgstr "Tipo de documento: %s apagado com sucesso." -#: views.py:949 +#: views.py:1120 #, python-format msgid "Document type: %(document_type)s delete error: %(error)s" msgstr "Tipo de documento: %(document_type)s erro ao excluir: %(error)s " -#: views.py:964 +#: views.py:1135 #, python-format msgid "Are you sure you wish to delete the document type: %s?" msgstr "Tem certeza de que deseja excluir o tipo de documento: %s?" -#: views.py:965 +#: views.py:1136 msgid "" "The document type of all documents using this document type will be set to " "none." @@ -820,46 +936,46 @@ msgstr "" "O tipo de documento de todos os documentos usando este tipo de documento " "será definido como \"nenhum\"." -#: views.py:981 +#: views.py:1152 msgid "Document type created successfully" msgstr "Tipo de documento criado com sucesso" -#: views.py:984 +#: views.py:1155 #, python-format msgid "Error creating document type; %(error)s" msgstr "Erro ao criar tipo de documento; %(error)s " -#: views.py:1002 +#: views.py:1173 #, python-format msgid "filenames for document type: %s" msgstr "nomes de arquivos para o tipo de documento: %s" -#: views.py:1033 +#: views.py:1204 msgid "Document type filename edited successfully" msgstr "Nome de arquivo para tipo de documento editado com sucesso" -#: views.py:1036 +#: views.py:1207 #, python-format msgid "Error editing document type filename; %s" msgstr "Erro ao editar nome de arquivo do tipo de documento: %s" -#: views.py:1041 +#: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" msgstr "" "Editar nome de arquivo \"%(filename)s\" do tipo de documento " "\"%(document_type)s\"" -#: views.py:1050 views.py:1076 views.py:1084 +#: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" msgstr "nome de arquivo do tipo de documento" -#: views.py:1068 +#: views.py:1239 #, python-format msgid "Document type filename: %s deleted successfully." msgstr "Nome de arquivo do tipo de documento: %s excluido com sucesso." -#: views.py:1070 +#: views.py:1241 #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" @@ -867,7 +983,7 @@ msgstr "" "Nome de arquivo do tipo de documento: %(document_type_filename)s erro ao " "excluir: %(error)s" -#: views.py:1086 +#: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " @@ -876,45 +992,91 @@ msgstr "" "Tem certeza de que deseja excluir o nome do arquivo: %(filename)s , do tipo " "de documento \" %(document_type)s \"?" -#: views.py:1111 +#: views.py:1282 msgid "Document type filename created successfully" msgstr "Nome de arquivo do tipo de documento criado com sucesso" -#: views.py:1114 +#: views.py:1285 #, python-format msgid "Error creating document type filename; %(error)s" msgstr "Erro ao criar nome de arquivo do tipo de documento; %(error)s" -#: views.py:1120 +#: views.py:1291 #, python-format msgid "create filename for document type: %s" msgstr "criar nome de arquivo para o tipo de documento: %s" -#: widgets.py:26 -#, fuzzy -msgid "document page image" -msgstr "página do documento" +#: views.py:1306 +msgid "Document image cache cleared successfully" +msgstr "" -#: wizards.py:34 +#: views.py:1308 +#, python-format +msgid "Error clearing document image cache; %s" +msgstr "" + +#: views.py:1314 +msgid "Are you sure you wish to clear the document image cache?" +msgstr "" + +#: views.py:1331 +#, python-format +msgid "versions for document: %s" +msgstr "" + +#: views.py:1341 +msgid "time and date" +msgstr "" + +#: views.py:1345 +msgid "mimetype" +msgstr "" + +#: views.py:1349 +msgid "encoding" +msgstr "" + +#: views.py:1380 +msgid "Document version reverted successfully" +msgstr "" + +#: views.py:1382 +#, python-format +msgid "Error reverting document version; %s" +msgstr "" + +#: views.py:1389 +msgid "Are you sure you wish to revert to this version?" +msgstr "" + +#: views.py:1390 +msgid "All later version after this one will be deleted too." +msgstr "" + +#: widgets.py:25 +msgid "document page image" +msgstr "" + +#: wizards.py:36 msgid "step 1 of 3: Document type" msgstr "passo 1 de 3: Tipo de documento" -#: wizards.py:35 +#: wizards.py:37 msgid "step 2 of 3: Metadata selection" msgstr "passo 2 de 3: seleção de Metadados" -#: wizards.py:36 +#: wizards.py:38 msgid "step 3 of 3: Document metadata" msgstr "passo 3 de 3: Metadados do documento" -#: wizards.py:44 +#: wizards.py:46 msgid "Next step" msgstr "Próximo passo" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per " -"user." +"Maximum number of recent (created, edited, viewed) documents to remember per" +" user." msgstr "" "Número máximo de documentos recentes (criado, editado, visualizado) à ser " "lembrado, por usuário." @@ -958,9 +1120,9 @@ msgid "" "creation, as well as assigning default metadata types and sets to it." msgstr "" "Tipos de documentos definir uma classe que representa um grupo de " -"documentos, tais como: notas fiscais, regulamentos ou manuais. A vantagem de " -"usar os tipos de documentos são: a atribuição de uma lista de nomes típicos " -"para renomear rápidamente durante a criação, bem como atribuir tipos de " +"documentos, tais como: notas fiscais, regulamentos ou manuais. A vantagem de" +" usar os tipos de documentos são: a atribuição de uma lista de nomes típicos" +" para renomear rápidamente durante a criação, bem como atribuir tipos de " "padrão de metadados e conjuntos para ele." #: templates/recent_document_list_help.html:3 @@ -976,5 +1138,4 @@ msgstr "" "Aqui você encontrará os últimos %(recent_count)s documentos que você tenha " "criado ou editado de alguma maneira." -#~ msgid "Page" -#~ msgstr "Página" + diff --git a/apps/documents/locale/ru/LC_MESSAGES/django.mo b/apps/documents/locale/ru/LC_MESSAGES/django.mo index af8dc744537c35975c64e1a036120c6e16f2f5c1..91ed59aa69fa1dc179d0519aca3fceabec98b6c9 100644 GIT binary patch delta 4446 zcmZYCe^izA0mtz#0)qS!5S0)RSc0G+Ao43z5Jdrh016ap2Bc&IS%8?NUQX9rNs**euU#D`zvu$@Rxhw)f{gk2{{T@8NS_-{*PmeV*^n zd-a=BZhKC;IX(^c=roi85>9f48{_3>%rZZnHRkC+V;16i%)^UVfIdOSEWlFK^&U*e zTbP0qf{jVVO030ptkQK%#KKXo&pXUIDp{PkfZq56PDJkz>o^6yIL@|@XW?j$i;=dN zYE*-o&<9W3*9YwDgXqioo2dJIhid2#SYR9+aJOlk*of=ViOHBa#+Y1u6l1Ul>6|%_ zdhk^oiGQ=N-$C^_bgX4DY9uxxeKN-}5(n(#&(WXfoA0RT0iL18MB_x9ghiNutyqKy zQ4RYVGcn=;W8$zvGG&{P(KWqc#w6is9D!dUm&_3IQR6qxYWM_n=mXQJ=)ycyORF&e z*WygvhK!aOKsDeK)PsFkFq->R)RaAo?Z0t-=jYUMp*ZYj9~oL!l|6l z+)qdDZ3=J|)}XFm!gBl=voM}4-8|ps0F&Dc~Blzd> z4r89A5)x%C9*1o^dUC!Kb%R&27*C)c{5^VL3G-Eg<){(pMK$D)sKpq|ylO;KQ173E zeOQEP_^pGAdJs=@H3gZ-G?`LN#d_4p^dOx#M^Fv>Eovw)qk1-odfykQ2LBUvU-t*C zRUeF+!Z4hGQ&4NdQBH*|ZyHhCq!qPIwxCvbJL<+=s0Y4jdji$7v&giXk5LW0je2kZ zPtjCHAnV&?p*~-VY!tHsSrZP^N`=On7f>HOhWwfLcu~*(iu%CUw(hZ3!@^JvOF;E( zDr&LKLl3M%*Ml&h<5txD&!9ec3B9!cuTaqk2JH)`+75aa=a1s`K^-Yo0q6)=wCtI=rF2B@1PeBplhyCHyA{{ z?>g#6|3EeD4hEvOmWj zKAJ9^jTdnR`a9B%nNOtw7vdRYbj^qi>*qEV8CBDQ+OOTnXU)6FpSi_L3C8kuwglH< zCtk)%tl{gh9M7N{8pz9Xrm7fYICk{qSU;baF_;shrdvZ6i)wKtG8^VORL}Zx1`eWb z_y7lb-x93CEvN=w!)hEg)B5IIi&_KcQ0I$s*)iJxN2$ZAp8UJXRh&!JA z+E&R0JQN?oT>J=sg+X(zU%yK@p5uR^)=Ur!Kply}owyV=B{xv_n?ZM5u@H0d1KiB> zja!j*qbWiY z=U^N@hPk){nH_U!5#z5n__2hOFd3)d3e;-fg=yG_lkrpBgubQLwra<%93MgTY;qYp z0cT{%ZLhPG~3t7hC@xC`9$RA0zQ52BQxX>WvW?gt0gl zGm!;vO7KD4g&N|1R0IBmYQVRs4!g4_Lom)kC7wzS4#!ofH#DF=um{!RH&8#P7j3_= z)xS10a^a|vD@JY8XHZjf5CidT+q0;KeS~_SV~EOVDxrK^sHI7$RXraQupX0fKWc<7 zqDI2)Ve5B41l7P4oQsd3-hU87@e1nwH*N2t8^?Ch`nSF?cH3vpqCTkkR(X!lS@R;< zPF9h9)ZXC^c2PLQ!=Bxxd#lRe}RxxZNB&zaL?n|0S=_9S=9Qg@xJv9yH6KyY*ezI8=%4_6j zq?u^nZy@pH{<4vSm1GThg`6ibM5T~8T{Y`>e=2oP`}h>Dv-;0}ojA}JjXQao>>z%` zi>Ms1aQy%kQE#!2=ip3ILOvk9c1{nP z?cwYloiY4mc<``}=*R+RTjX4KkEZH1b@^5&$9q2ez8rKn0 T6y+={8XDQLsH%JK(#HP+{@C<* delta 4955 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 diff --git a/apps/documents/locale/ru/LC_MESSAGES/django.po b/apps/documents/locale/ru/LC_MESSAGES/django.po index b6a7aeb2e8..1d01185b53 100644 --- a/apps/documents/locale/ru/LC_MESSAGES/django.po +++ b/apps/documents/locale/ru/LC_MESSAGES/django.po @@ -4,14 +4,14 @@ # # Translators: # Roberto Rosario , 2011. -# Sergey Glita , 2011. +# Sergey Glita , 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 19:16+0000\n" -"Last-Translator: gsv70 \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,74 +19,66 @@ 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:49 __init__.py:159 -msgid "Documents" -msgstr "Документы" - -#: __init__.py:60 -msgid "Documents setup" -msgstr "Настройки для документов" - -#: __init__.py:70 +#: __init__.py:63 msgid "all documents" msgstr "все документы" -#: __init__.py:71 models.py:415 views.py:709 +#: __init__.py:64 models.py:636 views.py:871 msgid "recent documents" msgstr "последние документы" -#: __init__.py:72 +#: __init__.py:65 msgid "upload new documents" msgstr "загрузить новые документы" -#: __init__.py:73 +#: __init__.py:66 msgid "clone metadata" msgstr "клонировать метаданные" -#: __init__.py:74 +#: __init__.py:67 msgid "details" msgstr "детали" -#: __init__.py:75 +#: __init__.py:68 msgid "properties" msgstr "свойства" -#: __init__.py:76 __init__.py:77 __init__.py:92 __init__.py:114 -#: __init__.py:120 +#: __init__.py:69 __init__.py:70 __init__.py:92 __init__.py:116 +#: __init__.py:122 msgid "delete" msgstr "удалить" -#: __init__.py:78 __init__.py:91 __init__.py:113 __init__.py:119 +#: __init__.py:71 __init__.py:91 __init__.py:115 __init__.py:121 msgid "edit" msgstr "редактировать" -#: __init__.py:79 +#: __init__.py:72 msgid "preview" msgstr "предварительный просмотр" -#: __init__.py:80 +#: __init__.py:73 __init__.py:74 __init__.py:75 msgid "download" msgstr "скачать" -#: __init__.py:81 +#: __init__.py:76 msgid "find duplicates" msgstr "поиска дубликатов" -#: __init__.py:82 +#: __init__.py:77 msgid "find all duplicates" msgstr "найти все дубликаты" -#: __init__.py:82 +#: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." msgstr "" "Искать все контрольные суммы документов и вернуть список точных совпадений." -#: __init__.py:83 +#: __init__.py:78 msgid "update office documents' page count" msgstr "обновить количество страниц документа" -#: __init__.py:83 +#: __init__.py:78 msgid "" "Update the page count of the office type documents. This is useful when " "enabling office document support after there were already office type " @@ -95,18 +87,32 @@ msgstr "" "Пересчитать количество страниц. Это полезно для включения поддержки уже " "существующих офисных документов." -#: __init__.py:84 __init__.py:85 +#: __init__.py:79 __init__.py:80 msgid "clear transformations" msgstr "очистить преобразования" -#: __init__.py:86 +#: __init__.py:81 msgid "print" msgstr "печать" -#: __init__.py:87 +#: __init__.py:82 msgid "history" msgstr "история" +#: __init__.py:83 +msgid "Find missing document files" +msgstr "Найти недостающие файлы документов" + +#: __init__.py:86 +msgid "Clear the document image cache" +msgstr "" + +#: __init__.py:86 +msgid "" +"Clear the graphics representations used to speed up the documents' display " +"and interactive transformations results." +msgstr "" + #: __init__.py:89 msgid "page transformations" msgstr " преобразования страницы" @@ -163,169 +169,148 @@ msgstr "повернуть влево" msgid "reset view" msgstr "вернуть вид" -#: __init__.py:107 -msgid "Find missing document files" -msgstr "Найти недостающие файлы документов" +#: __init__.py:108 +msgid "versions" +msgstr "" -#: __init__.py:110 +#: __init__.py:109 +msgid "revert" +msgstr "" + +#: __init__.py:112 msgid "document type list" msgstr "Список типов документов" -#: __init__.py:111 views.py:877 +#: __init__.py:113 views.py:1050 msgid "document types" msgstr "типы документов" -#: __init__.py:112 +#: __init__.py:114 msgid "documents of this type" msgstr "документы этого типа" -#: __init__.py:115 views.py:990 +#: __init__.py:117 views.py:1161 msgid "create document type" msgstr "создать тип документа" -#: __init__.py:117 +#: __init__.py:119 msgid "filenames" msgstr "Имена файлов" -#: __init__.py:118 +#: __init__.py:120 msgid "add filename to document type" msgstr "добавить имя файла для типа документа" -#: __init__.py:161 __init__.py:186 models.py:101 views.py:69 +#: __init__.py:164 permissions.py:7 +msgid "Documents" +msgstr "Документы" + +#: __init__.py:166 __init__.py:179 models.py:90 views.py:79 msgid "documents" msgstr "документы" -#: __init__.py:173 +#: __init__.py:169 msgid "thumbnail" msgstr "миниатюра" -#: __init__.py:176 -msgid "tags" -msgstr "метки" - -#: __init__.py:179 +#: __init__.py:172 msgid "metadata" msgstr "метаданные" -#: forms.py:60 +#: forms.py:63 msgid "Page image" -msgstr "Страница изображения" +msgstr "Изображение страницы" -#: forms.py:70 forms.py:209 +#: forms.py:73 forms.py:270 msgid "Contents" msgstr "Содержание" -#: forms.py:116 +#: forms.py:109 +msgid "Page" +msgstr "" + +#: forms.py:121 msgid "Details" msgstr "Детали" -#: forms.py:121 +#: forms.py:126 msgid "Click on the image for full size preview" msgstr "Нажмите на изображение для полного просмотра размера" -#: forms.py:131 +#: forms.py:136 #, python-format msgid "Document pages (%s)" msgstr "Страницы документа (%s)" -#: forms.py:166 +#: forms.py:162 +msgid "Use the new version filename as the document filename" +msgstr "" + +#: forms.py:178 msgid "Quick document rename" msgstr "Быстро переименовать документ" -#: forms.py:169 +#: forms.py:185 +msgid "Version update" +msgstr "" + +#: forms.py:190 +msgid "Release level" +msgstr "" + +#: forms.py:196 +msgid "Release level serial" +msgstr "" + +#: forms.py:204 +msgid "Comment" +msgstr "" + +#: forms.py:210 msgid "New document filename" msgstr "Новое имя файла документа" -#: forms.py:223 -msgid "Page size" -msgstr "Размер страницы" - -#: forms.py:224 -msgid "Custom page width" -msgstr "Своя ширина страницы" - -#: forms.py:225 -msgid "Custom page height" -msgstr "Своя высота страницы" - -#: forms.py:226 -msgid "Page orientation" -msgstr "Ориентация страницы" - -#: forms.py:227 +#: forms.py:288 msgid "Page range" msgstr "Диапазон страниц" -#: literals.py:8 -msgid "Create documents" -msgstr "Создание документов" +#: forms.py:318 +msgid "Compress" +msgstr "" -#: literals.py:9 -msgid "Edit document properties" -msgstr "Редактирование свойств документа" +#: forms.py:318 +msgid "" +"Download the document in the original format or in a compressed manner. " +"This option is selectable only when downloading one document, for multiple " +"documents, the bundle will always be downloads as a compressed file." +msgstr "" #: literals.py:10 -msgid "Edit documents" -msgstr "Редактировать документы" - -#: literals.py:11 -msgid "View documents" -msgstr "Просмотр документов" - -#: literals.py:12 -msgid "Delete documents" -msgstr "Удаление документов" - -#: literals.py:13 -msgid "Download documents" -msgstr "Загрузка документов" - -#: literals.py:14 -msgid "Transform documents" -msgstr "Преобразование документов" - -#: literals.py:15 -msgid "Execute document modifying tools" -msgstr "Выполнить изменения документа" - -#: literals.py:17 -msgid "Edit document types" -msgstr "Редактировать типы документов" - -#: literals.py:18 -msgid "Delete document types" -msgstr "Удалить типы документов" - -#: literals.py:19 -msgid "Create document types" -msgstr "Создание типов документов" - -#: literals.py:23 msgid "Document creation" msgstr "Создание документов" -#: literals.py:24 +#: literals.py:11 #, python-format msgid "Document \"%(content_object)s\" created by %(fullname)s." msgstr "Документ \"%(content_object)s\", создан %(fullname)s ." -#: literals.py:25 +#: literals.py:12 #, python-format msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." msgstr "" "Документ \"%(content_object)s\" создан %(datetime)s пользователем " "%(fullname)s." -#: literals.py:31 +#: literals.py:18 msgid "Document edited" msgstr "Документ отредактирован" -#: literals.py:32 +#: literals.py:19 #, python-format msgid "Document \"%(content_object)s\" edited by %(fullname)s." msgstr "Документ \"%(content_object)s\" редактировал %(fullname)s. " -#: literals.py:33 +#: literals.py:20 #, python-format msgid "" "Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." @@ -334,198 +319,318 @@ msgstr "" "Документ \"%(content_object)s\" был изменён %(datetime)s %(fullname)s. Были" " внесены изменения: %(changes)s." -#: literals.py:42 +#: literals.py:29 msgid "Document deleted" msgstr "Документ удален" -#: literals.py:43 +#: literals.py:30 #, python-format msgid "Document \"%(document)s\" deleted by %(fullname)s." msgstr "Документ \"%(document)s\" удалил %(fullname)s." -#: literals.py:44 +#: literals.py:31 #, python-format msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." msgstr "Документ\"%(document)s\" удалил %(datetime)s %(fullname)s." -#: models.py:63 +#: literals.py:42 +msgid "final" +msgstr "" + +#: literals.py:43 +msgid "alpha" +msgstr "" + +#: literals.py:44 +msgid "beta" +msgstr "" + +#: literals.py:45 +msgid "release candidate" +msgstr "" + +#: literals.py:46 +msgid "hotfix" +msgstr "" + +#: models.py:61 msgid "name" msgstr "имя" -#: models.py:69 models.py:78 models.py:315 views.py:896 views.py:926 -#: views.py:955 views.py:960 views.py:1003 views.py:1049 views.py:1083 +#: models.py:67 models.py:77 models.py:524 views.py:1068 views.py:1097 +#: views.py:1126 views.py:1131 views.py:1174 views.py:1220 views.py:1254 msgid "document type" msgstr "тип документа" -#: models.py:70 +#: models.py:68 msgid "documents types" msgstr "типы документов" -#: models.py:79 -msgid "file" -msgstr "файл" - -#: models.py:86 -msgid "added" -msgstr "добавлено" - -#: models.py:87 -msgid "updated" -msgstr "обновлено" - -#: models.py:88 -msgid "checksum" -msgstr "Контрольная сумма" - -#: models.py:89 +#: models.py:78 msgid "description" msgstr "описание" -#: models.py:100 models.py:332 models.py:404 models.py:419 views.py:209 +#: models.py:79 +msgid "added" +msgstr "добавлено" + +#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: views.py:351 msgid "document" msgstr "документ" -#: models.py:181 +#: models.py:287 +#, python-format +msgid "Major %(major)i.%(minor)i, (new release)" +msgstr "" + +#: models.py:288 +#, python-format +msgid "Minor %(major)i.%(minor)i, (some updates)" +msgstr "" + +#: models.py:289 +#, python-format +msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" +msgstr "" + +#: models.py:301 +msgid "mayor" +msgstr "" + +#: models.py:302 +msgid "minor" +msgstr "" + +#: models.py:303 +msgid "micro" +msgstr "" + +#: models.py:304 +msgid "release level" +msgstr "" + +#: models.py:305 +msgid "serial" +msgstr "" + +#: models.py:306 +msgid "timestamp" +msgstr "" + +#: models.py:307 views.py:1357 +msgid "comment" +msgstr "" + +#: models.py:310 +msgid "file" +msgstr "файл" + +#: models.py:314 +msgid "checksum" +msgstr "Контрольная сумма" + +#: models.py:318 models.py:319 models.py:542 +msgid "document version" +msgstr "" + +#: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." msgstr "" "Этот формат файла документа не известен, количество страниц поэтому 1." -#: models.py:316 +#: models.py:525 views.py:1353 msgid "filename" msgstr "имя файла" -#: models.py:317 views.py:1010 +#: models.py:526 views.py:1181 msgid "enabled" msgstr "разрешено" -#: models.py:324 +#: models.py:533 msgid "document type quick rename filename" msgstr "имя файла для быстрого переименования документа определённого типа " -#: models.py:325 +#: models.py:534 msgid "document types quick rename filenames" msgstr "имена файлов для быстрого переименования документа определённых типов" -#: models.py:333 +#: models.py:545 msgid "content" msgstr "содержание" -#: models.py:334 +#: models.py:546 msgid "page label" msgstr "метка страницы" -#: models.py:335 +#: models.py:547 msgid "page number" msgstr "номер страницы" -#: models.py:338 +#: models.py:550 #, python-format msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" msgstr "Страница %(page_num)d из %(total_pages)d %(document)s" -#: models.py:346 models.py:383 +#: models.py:558 models.py:604 msgid "document page" msgstr "страница документа" -#: models.py:347 +#: models.py:559 msgid "document pages" msgstr "страницы документа" -#: models.py:358 +#: models.py:579 msgid "Enter a valid value." msgstr "Введите допустимое значение." -#: models.py:384 views.py:333 +#: models.py:605 views.py:449 msgid "order" msgstr "порядок" -#: models.py:385 views.py:334 views.py:389 views.py:418 +#: models.py:606 views.py:450 views.py:511 views.py:542 msgid "transformation" msgstr "преобразование" -#: models.py:386 views.py:335 +#: models.py:607 views.py:451 msgid "arguments" msgstr "аргументы" -#: models.py:386 +#: models.py:607 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Использовать словари для идентификации аргументов, например %s" -#: models.py:394 +#: models.py:615 msgid "document page transformation" msgstr "преобразование страницы документа" -#: models.py:395 +#: models.py:616 msgid "document page transformations" msgstr "преобразования документов страницу" -#: models.py:403 +#: models.py:624 msgid "user" msgstr "пользователь" -#: models.py:405 +#: models.py:626 msgid "accessed" msgstr "допущен" -#: models.py:414 +#: models.py:635 msgid "recent document" msgstr "недавний документ" -#: models.py:420 +#: models.py:641 msgid "Document type" msgstr "Тип документа" -#: models.py:421 +#: models.py:642 msgid "MIME type" msgstr "MIME-тип" -#: models.py:422 views.py:117 +#: models.py:643 views.py:132 msgid "Filename" msgstr "Имя файла" -#: models.py:423 -msgid "Filename extension" -msgstr "Расширение файла" - -#: models.py:424 +#: models.py:644 msgid "Metadata value" msgstr "Метаданны значение" -#: models.py:425 +#: models.py:645 msgid "Content" msgstr "Содержимое" -#: models.py:426 +#: models.py:646 msgid "Description" msgstr "Описание" -#: models.py:427 +#: models.py:647 msgid "Tags" msgstr "Метки" -#: models.py:428 +#: models.py:648 msgid "Comments" msgstr "Комментарии" -#: statistics.py:38 +#: permissions.py:9 +msgid "Create documents" +msgstr "Создание документов" + +#: permissions.py:10 +msgid "Edit document properties" +msgstr "Редактирование свойств документа" + +#: permissions.py:11 +msgid "Edit documents" +msgstr "Редактировать документы" + +#: permissions.py:12 +msgid "View documents" +msgstr "Просмотр документов" + +#: permissions.py:13 +msgid "Delete documents" +msgstr "Удаление документов" + +#: permissions.py:14 views.py:408 +msgid "Download documents" +msgstr "Загрузка документов" + +#: permissions.py:15 +msgid "Transform documents" +msgstr "Преобразование документов" + +#: permissions.py:16 +msgid "Execute document modifying tools" +msgstr "Выполнить изменения документа" + +#: permissions.py:17 +msgid "Revert documents to a previous version" +msgstr "" + +#: permissions.py:18 +msgid "Create new document versions" +msgstr "" + +#: permissions.py:20 +msgid "Documents setup" +msgstr "Настройки для документов" + +#: permissions.py:22 +msgid "View document types" +msgstr "" + +#: permissions.py:23 +msgid "Edit document types" +msgstr "Редактировать типы документов" + +#: permissions.py:24 +msgid "Delete document types" +msgstr "Удалить типы документов" + +#: permissions.py:25 +msgid "Create document types" +msgstr "Создание типов документов" + +#: statistics.py:40 #, python-format msgid "Document types: %d" msgstr "Типы документов: %d." -#: statistics.py:39 +#: statistics.py:41 #, python-format msgid "Documents in database: %d" msgstr "Документы в базе данных: %d." -#: statistics.py:44 +#: statistics.py:46 #, python-format msgid "Documents in storage: %d" msgstr "Документы в хранилище: %d." -#: statistics.py:46 +#: statistics.py:48 #, python-format msgid "" "Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" @@ -533,141 +638,152 @@ msgid "" msgstr "" "Использовано:%(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d bytes" -#: statistics.py:56 +#: statistics.py:58 #, python-format msgid "Document pages in database: %d" msgstr "Страниц документов в базе данных: %d." -#: statistics.py:57 +#: statistics.py:59 #, python-format msgid "Minimum amount of pages per document: %(page_count__min)d" msgstr "Минимальное количество страниц в документе: %(page_count__min)d" -#: statistics.py:58 +#: statistics.py:60 #, python-format msgid "Maximum amount of pages per document: %(page_count__max)d" msgstr "Максимальное количество страниц в документе: %(page_count__max)d" -#: statistics.py:59 +#: statistics.py:61 #, python-format msgid "Average amount of pages per document: %(page_count__avg)f" msgstr "Среднее количество страниц в документе: %(page_count__avg)f" -#: statistics.py:65 +#: statistics.py:67 msgid "Document statistics" msgstr "Статистика документов" -#: views.py:118 -msgid "File extension" -msgstr "Расширение файла" - -#: views.py:119 +#: views.py:133 msgid "File mimetype" msgstr "Mime тип файла" -#: views.py:120 +#: views.py:134 msgid "File mime encoding" msgstr "Mime-кодировка файла" -#: views.py:121 +#: views.py:135 msgid "File size" msgstr "Размер" -#: views.py:122 +#: views.py:136 msgid "Exists in storage" msgstr "Существует в хранилище" -#: views.py:123 +#: views.py:137 msgid "File path in storage" msgstr "Путь к файлу в хранилище" -#: views.py:124 +#: views.py:138 msgid "Date added" msgstr "Дата добавления" -#: views.py:125 +#: views.py:139 msgid "Time added" msgstr "Время добавления" -#: views.py:126 +#: views.py:140 msgid "Checksum" msgstr "Контрольная сумма" -#: views.py:127 +#: views.py:141 msgid "UUID" msgstr "UUID" -#: views.py:128 +#: views.py:142 msgid "Pages" msgstr "Страницы" -#: views.py:137 +#: views.py:151 #, python-format msgid "document properties for: %s" msgstr "Свойства документа для: %s" -#: views.py:159 +#: views.py:173 msgid "document data" msgstr "данные документа" -#: views.py:184 views.py:521 +#: views.py:197 views.py:646 msgid "Must provide at least one document." msgstr "Необходимо предоставить хотя бы один документ." -#: views.py:200 -#, python-format -msgid "Document: %s deleted successfully." -msgstr "Документ: %s успешно удален. " +#: views.py:218 +msgid "Document deleted successfully." +msgstr "" -#: views.py:202 +#: views.py:220 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Документ:%(document)s ошибка удаления: %(error)s" -#: views.py:217 +#: views.py:235 #, python-format msgid "Are you sure you wish to delete the document: %s?" msgstr "Вы действительно хотите удалить документ: %s?" -#: views.py:219 +#: views.py:237 #, python-format msgid "Are you sure you wish to delete the documents: %s?" msgstr "Вы действительно хотите удалить документы: %s?" -#: views.py:256 +#: views.py:276 #, python-format msgid "Document \"%s\" edited successfully." msgstr "Документ \"%s\" изменен." -#: views.py:329 +#: views.py:342 +msgid "documents to be downloaded" +msgstr "" + +#: views.py:352 views.py:1337 +msgid "version" +msgstr "" + +#: views.py:409 +msgid "Download" +msgstr "" + +#: views.py:411 +msgid "Return" +msgstr "" + +#: views.py:445 #, python-format msgid "transformations for: %s" msgstr "преобразования для: %s" -#: views.py:353 +#: views.py:472 msgid "Document page transformation created successfully." msgstr "Преобразование страницы документа создано успешно." -#: views.py:362 +#: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" msgstr "" "Создать новое преобразование для страницы: %(page)s документа: %(document)s" -#: views.py:378 +#: views.py:500 msgid "Document page transformation edited successfully." msgstr "Преобразование страницы успешно изменено." -#: views.py:391 +#: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" msgstr "Изменить преобразования \"%(transformation)s\" for: %(document_page)s" -#: views.py:409 +#: views.py:533 msgid "Document page transformation deleted successfully." msgstr "Преобразование страницы успешно удалено." -#: views.py:420 +#: views.py:544 #, python-format msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " @@ -676,26 +792,26 @@ msgstr "" "Вы действительно хотите удалить преобразования \"%(transformation)s\" for: " "%(document_page)s\"" -#: views.py:434 +#: views.py:562 #, python-format msgid "duplicates of: %s" msgstr "дубликатов: %s" -#: views.py:446 +#: views.py:574 msgid "Are you sure you wish to find all duplicates?" msgstr "Вы действительно хотите найти все дубликаты?" -#: views.py:447 views.py:506 views.py:571 +#: views.py:575 views.py:633 views.py:701 msgid "On large databases this operation may take some time to execute." msgstr "" "В больших базах данных эта операция может занять некоторое время для " "выполнения." -#: views.py:462 +#: views.py:598 msgid "duplicated documents" msgstr "дубликаты документов" -#: views.py:497 +#: views.py:624 #, python-format msgid "" "Page count update complete. Documents processed: %(total)d, documents with " @@ -704,7 +820,7 @@ msgstr "" "Страницы посчитаны. Всего обработано %(total)d документов, из них количество" " страниц изменилось у %(change)d" -#: views.py:505 +#: views.py:632 #, python-format msgid "" "Are you sure you wish to update the page count for the office documents " @@ -713,14 +829,14 @@ msgstr "" "Вы действительно хотите пересчитать количество страниц для офисных " "документов (%d)?" -#: views.py:534 +#: views.py:664 #, python-format msgid "" "All the page transformations for document: %s, have been deleted " "successfully." msgstr "Все преобразования страницы для документа: %s успешно удалены." -#: views.py:536 +#: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " @@ -729,11 +845,11 @@ msgstr "" "Ошибка при удалении страницы для преобразования документов: %(document)s; " "%(error)s." -#: views.py:542 +#: views.py:672 msgid "document transformation" msgstr "преобразование документа" -#: views.py:551 +#: views.py:681 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for document: " @@ -741,7 +857,7 @@ msgid "" msgstr "" "Вы действительно хотите удалить все преобразования странице документа: %s?" -#: views.py:553 +#: views.py:683 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for documents: " @@ -750,115 +866,115 @@ msgstr "" "Вы действительно хотите удалить все преобразования страницы для документов: " "%s?" -#: views.py:581 +#: views.py:711 msgid "missing documents" msgstr "недостающие документы" -#: views.py:594 views.py:632 +#: views.py:727 views.py:769 #, python-format msgid "details for: %s" msgstr "подробности: %s" -#: views.py:647 +#: views.py:788 msgid "Document page edited successfully." msgstr "Страница документа успешно изменена." -#: views.py:656 +#: views.py:797 #, python-format msgid "edit: %s" msgstr "редактировать: %s" -#: views.py:667 +#: views.py:814 msgid "There are no more pages in this document" msgstr " Нет более страниц в этом документе" -#: views.py:680 +#: views.py:832 msgid "You are already at the first page of this document" msgstr "Вы уже на первой странице этого документа" -#: views.py:823 +#: views.py:993 #, python-format msgid "print: %s" msgstr "печать: %s" -#: views.py:894 +#: views.py:1066 #, python-format msgid "documents of type \"%s\"" msgstr "документы типа \"%s\"" -#: views.py:914 +#: views.py:1086 msgid "Document type edited successfully" msgstr "Тип документа успешно изменен" -#: views.py:917 +#: views.py:1089 #, python-format msgid "Error editing document type; %s" msgstr "Ошибка редактирования типа документа; %s" -#: views.py:922 +#: views.py:1094 #, python-format msgid "edit document type: %s" msgstr "редактировать тип документа: %s" -#: views.py:947 +#: views.py:1118 #, python-format msgid "Document type: %s deleted successfully." msgstr "Вид документа: %s успешно удален." -#: views.py:949 +#: views.py:1120 #, python-format msgid "Document type: %(document_type)s delete error: %(error)s" msgstr "Тип документа: %(document_type)s ошибка удаления: %(error)s" -#: views.py:964 +#: views.py:1135 #, python-format msgid "Are you sure you wish to delete the document type: %s?" msgstr "Вы действительно хотите удалить тип документа: %s?" -#: views.py:965 +#: views.py:1136 msgid "" "The document type of all documents using this document type will be set to " "none." msgstr "Тип документа всех документов этого типа станет неопределённым." -#: views.py:981 +#: views.py:1152 msgid "Document type created successfully" msgstr "Тип документа успешно создан" -#: views.py:984 +#: views.py:1155 #, python-format msgid "Error creating document type; %(error)s" msgstr "Ошибка при создании типа документа; %(error)s" -#: views.py:1002 +#: views.py:1173 #, python-format msgid "filenames for document type: %s" msgstr "имена файлов для типа документа: %s" -#: views.py:1033 +#: views.py:1204 msgid "Document type filename edited successfully" msgstr "Имя файла для типа документа успешно изменено" -#: views.py:1036 +#: views.py:1207 #, python-format msgid "Error editing document type filename; %s" msgstr "Ошибка редактирования документа введите имя файла; %s" -#: views.py:1041 +#: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" msgstr "редактирование файла \"%(filename)s из типа документа \"%(document_type)s\"" -#: views.py:1050 views.py:1076 views.py:1084 +#: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" msgstr "имя файла для типа документа" -#: views.py:1068 +#: views.py:1239 #, python-format msgid "Document type filename: %s deleted successfully." msgstr "Имя файла для типа документа: %s успешно удалено." -#: views.py:1070 +#: views.py:1241 #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" @@ -866,7 +982,7 @@ msgstr "" "При удалении имени файла для типа документа %(document_type_filename)s " "произошла ошибка %(error)s" -#: views.py:1086 +#: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " @@ -875,37 +991,84 @@ msgstr "" "Вы действительно хотите удалить имя файла: %(filename)s из типа документа " "\"%(document_type)s\"?" -#: views.py:1111 +#: views.py:1282 msgid "Document type filename created successfully" msgstr "Имя файла для типа документа успешно создан" -#: views.py:1114 +#: views.py:1285 #, python-format msgid "Error creating document type filename; %(error)s" msgstr "Ошибка создания имени файла для типа документа; %(error)s" -#: views.py:1120 +#: views.py:1291 #, python-format msgid "create filename for document type: %s" msgstr "создание имени файла для типа документа: %s" -#: widgets.py:26 +#: views.py:1306 +msgid "Document image cache cleared successfully" +msgstr "" + +#: views.py:1308 +#, python-format +msgid "Error clearing document image cache; %s" +msgstr "" + +#: views.py:1314 +msgid "Are you sure you wish to clear the document image cache?" +msgstr "" + +#: views.py:1331 +#, python-format +msgid "versions for document: %s" +msgstr "" + +#: views.py:1341 +msgid "time and date" +msgstr "" + +#: views.py:1345 +msgid "mimetype" +msgstr "" + +#: views.py:1349 +msgid "encoding" +msgstr "" + +#: views.py:1380 +msgid "Document version reverted successfully" +msgstr "" + +#: views.py:1382 +#, python-format +msgid "Error reverting document version; %s" +msgstr "" + +#: views.py:1389 +msgid "Are you sure you wish to revert to this version?" +msgstr "" + +#: views.py:1390 +msgid "All later version after this one will be deleted too." +msgstr "" + +#: widgets.py:25 msgid "document page image" msgstr "изображение страницы" -#: wizards.py:34 +#: wizards.py:36 msgid "step 1 of 3: Document type" msgstr "Шаг 1 из 3: Тип документа" -#: wizards.py:35 +#: wizards.py:37 msgid "step 2 of 3: Metadata selection" msgstr "шаг 2 из 3: Выбор Метаданных" -#: wizards.py:36 +#: wizards.py:38 msgid "step 3 of 3: Document metadata" msgstr "шаг 3 из 3: Метаданные документа" -#: wizards.py:44 +#: wizards.py:46 msgid "Next step" msgstr "Далее" diff --git a/apps/dynamic_search/locale/en/LC_MESSAGES/django.po b/apps/dynamic_search/locale/en/LC_MESSAGES/django.po index 9cea6f8909..376f359baf 100644 --- a/apps/dynamic_search/locale/en/LC_MESSAGES/django.po +++ b/apps/dynamic_search/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/apps/dynamic_search/locale/es/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/es/LC_MESSAGES/django.mo index 7512e7945d1f4feba10f0e3ce08f7812e08e3eac..d881ae086a31978942268523d48d3aa353c96c8d 100644 GIT binary patch delta 233 zcmZn@>=m4FrG7Uf1A`n31A`6&1H&y=28KC6nw^b-0mx)n0;HXQ^eQ0j4y4}#X-*(* z%Fe(b2BhtQv=opIgYpZ3v=ETr0i;EM^lTsvL<}2%1P74b0i;3l2Z1z5{t7#T8G{Ot z@e(M&1*G|as(gU7B#;JKlm?{vfph_o2D*`<0Z0RtGPG{)WPHfPYou!cLJEc^R)*%2 d%USICgYuJ7i%Rkpg7S+Ki!$>!?_)W^3;>0TAld)` delta 226 zcmXZWzY0NN7{~D+4hJP2$zYJdhKJ4pi!vz1$Ye6=nC!}8;szL8 zhwmx%^nRXy^}K6m>1\n" +"Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" "mayan-edms/team/es/)\n" "Language: es\n" diff --git a/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo index 85cbc415e440be5601d59a996af9523e87cdfca2..9e527654a7f93a6cc12fa76f18a4ce9c9a138b97 100644 GIT binary patch delta 257 zcmWm8Eo(w?6vy$O;`Irq7Zo(g4JP4&SHyuP(IQMV*bI7uieU=lE-x&IO|WnE=GiTS z4a|E9ON+h%_x;0x&*2=-!=PNTw(`9H1%IB;vbgq zhIuR{BpYjZhaIG)0cLTGIh>)H+a}bKL$afg!Vrh}f##5sQU>D4k1C*9SU&9|muNLT z9!=cd)4~td+l|}zgGJkE)V+pVH{p2Aws(Jgi=8tM{$};;uV}A>pF delta 294 zcmXZWJxjx25C`yoOJmyj7KLW|l>MFl6frxKD3c_Dd1>Eu@FAQTFM zli$FlyQ70k78k#SpTU1XIQZQicgMY%pXU7gv1$N&E#MHquLi_)cLiXICwfYs=?Sg= z`>Q&z&3cRO(0$saeQMHMx=u%wE6C^u9n(!ZrS;y6jvg!~?`(8vMX%@&tsgjO18dZ# z{1G0l4-S^I##i$qR4Vg?2qG1hqoap37I|98JW6vB%ZW@xR1~FO7&q5<_Id706{U$i ml*;!k_t, 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" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2011-12-09 15:32+0000\n" "Last-Translator: Pierpaolo Baldan \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:5 @@ -62,8 +63,7 @@ msgstr "risultati della ricerca" #, python-format msgid "results, (showing only %(shown_result_count)s out of %(result_count)s)" msgstr "" -"risultati, (mostra esclusivamente %(shown_result_count)s di " -"%(result_count)s)" +"risultati, (mostra esclusivamente %(shown_result_count)s di %(result_count)s)" #: views.py:37 msgid "results" @@ -117,5 +117,3 @@ msgstr "Tempo trascorso: %(time_delta)s in secondi" #, python-format msgid "recent searches (maximum of %d)" msgstr "ricerche recenti (maximum of %d)" - - diff --git a/apps/dynamic_search/locale/pt/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/pt/LC_MESSAGES/django.mo index 85a80a99c71658b10fdbcf576875bca63bdd8daa..ef93575b86874ef102d4eadc19df50b14238c051 100644 GIT binary patch delta 26 fcmca6a7|!C77MSDt^o)s7@Alanr|*=xz7v$YGVg~ delta 26 hcmca6a7|!C77MSTuA!l>k&%L-p_P%@=5m(%%m8Xq2Ymnl diff --git a/apps/dynamic_search/locale/pt/LC_MESSAGES/django.po b/apps/dynamic_search/locale/pt/LC_MESSAGES/django.po index cd156fba16..cd10f88f38 100644 --- a/apps/dynamic_search/locale/pt/LC_MESSAGES/django.po +++ b/apps/dynamic_search/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-02 14:17-0400\n" "PO-Revision-Date: 2011-11-03 02:32+0000\n" "Last-Translator: emersonsoares \n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" diff --git a/apps/dynamic_search/locale/ru/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/ru/LC_MESSAGES/django.mo index 00f56a26ed56225c95075b9e7fc132c773a3ff9f..a8b96f88e7876582b22418cafb7b7b5eec223a81 100644 GIT binary patch delta 230 zcmZ1`vQ}immHLN_3=DEC3=ED8K)}YpunR~z0cjo}{TE2L0%e8|LWq-y{|3Wg?DhUSyY ZS?qa&Q;X75D;3;xGD{LS?`Fwn1ptlwANT+O delta 223 zcmXZWJqtl`6vy!&?)4Pg9Yk)FGI{vlfntys;9ZEpU{DMOli@B>HZQ=Yl+EZh7-S-& z#iVS$w@jb&JDqbnduQjYFN<49axJMV>1#_TY)7ROesGDAn6yP7lURyNd8}a(d+6f$ zpI2BWA267|VsP(?IecTVmrAIiCPg(NIXJ*R&M{cLV-{b?FN)I4VEX8X9^tg97*p}Q Vf-x&LS-vVStJ9g6?} diff --git a/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po b/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po index 758ddcbf0e..2fabd8f0dd 100644 --- a/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po +++ b/apps/dynamic_search/locale/ru/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-02 14:17-0400\n" "PO-Revision-Date: 2011-11-03 22:40+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" diff --git a/apps/feedback/locale/en/LC_MESSAGES/django.po b/apps/feedback/locale/en/LC_MESSAGES/django.po index 81ae2b76c0..0321894c73 100644 --- a/apps/feedback/locale/en/LC_MESSAGES/django.po +++ b/apps/feedback/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: 2012-02-02 12:46-0400\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/apps/feedback/locale/es/LC_MESSAGES/django.mo b/apps/feedback/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1dad760209edc084a46d2fe62dda6c8d4463fd41 GIT binary patch literal 3198 zcma)8OK%)S5FQ{9FoZ`CLI@%?ugDgjUE9jRn&24XI4B|}iS1zJ*gMm^+i_3#&<}6c z2PAI%0nR8Amk1&S1x^SBvf{vnD;IM!d%y@y;cs++-90^0LV0o}sXs`OLvSvpXQg@iKtWsQS`rn)33&AQb3+6&q z8S7aaLTkLwHCsKkwy~V7n6l!!&onPZw)fN%Ehl|k2&!Ox6POoDvEUeIE$JC=nc!L1 z^x``Xg9=e8)1NSdOsE$p4rJ5kHf9;A7j{S3S(Ymkil#C-SF^0kZP6oTt`fPMSx#21 zg}pAcO6f^8tS^tVH(et+Ekx1c`E~+lppO;O!S_CyV_81o6g$e4=@=$8qgO-E7$;8x ztYD@+XM)3oQg#|dN}_tI$EH4Dr+`7$n(%@ zpi-LFIBun}&64^;Q#u!fn>v4PGhMMrC#X$NAultwFgL%D&e0#6KbFlergO*U<{+4^ ziycYF|A*XSwy^lt9ImOe-1&6Va_x}i#%65Yw1h>tWw{5-97#h^*7`@At*nOu% zM3Ai~phb5A?}&6$@G@f?XkOBF+4KsuOA5dYn;yE@>-8E)d!%(+Txn?Gn`o6pm}^$G zuc;_X*YwcT6s|clwRUE0bxh@aV{U52Ak{SN?pGkdiz`r~xYWlP!f2iFOBXj!r;B4b zIuG@nuIk)SQ_k2T`sJS486#>{uw135(JfrYbQK@n(!z1HZ+f#dt=X$fY<^}cxqWLD z#l%p%fh#H`!O+;zLrt^FksHcOa;HELtx<6)ju4NLMiV4QAtDW2+%dLtIe8BwKtc#z0fIyzSweDqbTwe@ zg)q3ra^w)^1rh;em1EQ09+O=l=rVGGC=|P(mc}W!isC<-C0MQ3h=m8yi;RNmuG}@O z99+ezvOTz-OHhDRLq%yEN*@iF@A&$mX@$W)nlaq&e+;yC0u4Q)5+5EDy9#)Rm`^fQ zS6!6FrZ{Edz@h4bXh2HPn5csns}3cq%w=AH4upx<8GILKWE<7;18OA~l|bp=Q_bw7 zK=Th{s4pn#=)1>Iw(Z2Mq+t~62)toDng2a?SpG, YEAR. -# -#, fuzzy +# +# Translators: +# Roberto Rosario , 2012. msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 12:46-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18: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" "Content-Transfer-Encoding: 8bit\n" +"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:9 msgid "Feedback" -msgstr "" +msgstr "Comentarios" #: forms.py:16 msgid "" "What features of Mayan EDMS attracted you to start using it or consider " "using it?" msgstr "" +"¿Qué características de Mayan EDMS le atrajo a empezar a usarlo o considerar" +" usarlo?" #: forms.py:24 msgid "What features would you like to see implemented in Mayan EDMS?" -msgstr "" +msgstr "¿Qué características le gustaría ver implementadas en Mayan EDMS?" #: forms.py:32 msgid "" "Could you tell us a bit about how you are deploying or plan to deploy Mayan " "EDMS (OS, webserver, cloud/local, hardware specs)?" msgstr "" +"¿Podría hablarnos un poco acerca de cómo se está implementando o planea " +"implementar Mayan EDMS (sistema operativo, servidor web, nube / locales, " +"hardware)?" #: forms.py:40 msgid "" "What features of Mayan EDMS did you find hardest to understand or implement?" msgstr "" +"¿Qué características de Mayan EDMS se le hizo más difícil de encontrar, " +"comprender o implementar?" #: forms.py:45 msgid "Would you be interested in purchasing paid support for Mayan EDMS?" msgstr "" +"¿Estaría usted interesado en la compra de apoyo técnico pagado para Mayan " +"EDMS?" #: forms.py:50 msgid "" "Are currently providing or planning to provide paid support for Mayan EDMS?" -msgstr "" +msgstr "¿Esta actualmente o planifica proveer apoyo pagado para Mayan EDMS?" #: forms.py:55 msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" msgstr "" +"¿Estaría usted interesado en una solución pagada alojada en la nube de Mayan" +" EDMS?" #: forms.py:60 msgid "" "Would you be interested in a turn-key solution for Mayan EDMS that included " "a physical server appliance?" msgstr "" +"¿Estaría usted interesado en una solución completa para Mayan EDMS que " +"incluye un dispositivo de servidor físico?" #: forms.py:65 msgid "Your name:" -msgstr "" +msgstr "Su nombre:" #: forms.py:70 msgid "Your email:" -msgstr "" +msgstr "Su correo electrónico:" #: forms.py:75 msgid "Company name:" -msgstr "" +msgstr "Nombre de la empresa:" #: forms.py:80 msgid "Company website:" -msgstr "" +msgstr "Web de la compañía:" #: forms.py:85 msgid "" "May we display your company name & logo in our website as a user of Mayan " "EDMS with a link back to your website?" msgstr "" +"¿Podemos usar el nombre de su empresa y logotipo en nuestra página web como " +"usuario de Mayan EDMS con un enlace a su sitio web?" #: forms.py:90 msgid "" "May we keep your contact information to keep you up to date with " "developments or oferings related to Mayan EDMS?" msgstr "" +"¿Podemos mantener su información de contacto para mantenerle al día con los " +"ultimos desarollos u ofertas relacionados con Mayan EDMS?" #: views.py:20 msgid "Thank you for submiting your feedback." -msgstr "" +msgstr "Gracias por remitir sus comentarios." #: views.py:23 #, python-format msgid "Error submiting form; %s." -msgstr "" +msgstr "Error remitiendo el formulario; %s." #: views.py:28 msgid "feedback form" -msgstr "" +msgstr "formulario de comentarios" + + diff --git a/apps/feedback/locale/it/LC_MESSAGES/django.mo b/apps/feedback/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a84cfa37468edc5fa96767e7630fafb949777025 GIT binary patch literal 528 zcmZut!A`?43>|_~kDNIKi31a)X)6vTFof8KG>M976z6VZeO{7pIa?b$`vx=Qqd9*8=e0GGW$Hs2 zHXLM6!31jSkY~QobAHzpp66Dw1!66QC^RmbX*jc$aMmlQtrJz7E423w_+b2)^S%Rx zRF)4Ef@Db)Cp>Boi!WrH^5`Oph{z}KuG{wi@KTw?XAxQOpgi*2DdS6p)=4(8Q*da> z|Mh3rZv7B$1cik)pQ?n<+oDpsY_;A{6;m{-0G@-YBpabBH4S{a8Ed&*hS>JdudoUY zps3eN@}geP$6;Q1fs`#Yif)jNvf*xhaTo=CYY+@+{itbZgcTJjl{QywwouLk_MY>5 zp6+;UzgKX4Xl8bU3IQ~!m&mt3*+wRdXRagW8_pz{k9 C_n@r+ literal 0 HcmV?d00001 diff --git a/apps/feedback/locale/it/LC_MESSAGES/django.po b/apps/feedback/locale/it/LC_MESSAGES/django.po index 364afdffd9..11bbe41317 100644 --- a/apps/feedback/locale/it/LC_MESSAGES/django.po +++ b/apps/feedback/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,20 @@ # 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: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 12:46-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:21+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:9 @@ -102,3 +101,5 @@ msgstr "" #: views.py:28 msgid "feedback form" msgstr "" + + diff --git a/apps/feedback/locale/pt/LC_MESSAGES/django.mo b/apps/feedback/locale/pt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..83a3dfda3af6f2d1e67de126de0126b12807d1db GIT binary patch literal 531 zcmZutJx{|h5G{f!BQt}M7(n1SsThJw5uzU#ObeZg?rwJjtQvrG5l?|mr=OvrE8F+LQ zH}%=2-(JK&hGOmPyDH)RT35=Ht=B8cVs)c5@B&mN*@QZ5H2DQ~{L|Tby^gUhW0vq5 zTR>57=M+S}ZIQ#G3IZvCs8O6m`8Xf_O)!m, YEAR. -# -#, fuzzy +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 12:46-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:21+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:9 @@ -102,3 +101,5 @@ msgstr "" #: views.py:28 msgid "feedback form" msgstr "" + + diff --git a/apps/feedback/locale/ru/LC_MESSAGES/django.mo b/apps/feedback/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..72be997423a6aec7613a6f803691788f5d711adc GIT binary patch literal 602 zcmZutO;6k~5Z!*9a_qT>K`Mw9b!>+{q-FzEVUds;vDyai-d&S*mDrK(bOG@<`uF-< zI^IyYbmXU*vEQ2y|M~F#_XzC`;v?b{;vM2MB3h1sx1-S)^pW#ob7z05RUlVua;u!z z)(9x&gETO^D1Rgi)maxv>1(|v-}>5<$_m(o&!s7y(Kc$S_P$p> znO|4r+$kBbEV+_o-2VcEcxm+70^=wQfBPsHU!`YuPgun literal 0 HcmV?d00001 diff --git a/apps/feedback/locale/ru/LC_MESSAGES/django.po b/apps/feedback/locale/ru/LC_MESSAGES/django.po index a53b9861e5..29e1f02967 100644 --- a/apps/feedback/locale/ru/LC_MESSAGES/django.po +++ b/apps/feedback/locale/ru/LC_MESSAGES/django.po @@ -1,23 +1,21 @@ # 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: msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 12:46-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"Project-Id-Version: Mayan EDMS\n" +"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" +"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"PO-Revision-Date: 2012-02-02 18:21+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/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:9 msgid "Feedback" @@ -103,3 +101,5 @@ msgstr "" #: views.py:28 msgid "feedback form" msgstr "" + + diff --git a/apps/folders/locale/en/LC_MESSAGES/django.po b/apps/folders/locale/en/LC_MESSAGES/django.po index f44a557331..9915a91111 100644 --- a/apps/folders/locale/en/LC_MESSAGES/django.po +++ b/apps/folders/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,44 +17,44 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:10 +#: __init__.py:18 msgid "folder list" msgstr "" -#: __init__.py:11 views.py:53 +#: __init__.py:19 views.py:77 msgid "create folder" msgstr "" -#: __init__.py:12 +#: __init__.py:20 msgid "edit" msgstr "" -#: __init__.py:13 +#: __init__.py:21 msgid "delete" msgstr "" -#: __init__.py:14 +#: __init__.py:22 msgid "remove from folder" msgstr "" -#: __init__.py:15 +#: __init__.py:23 msgid "folder documents" msgstr "" -#: __init__.py:16 +#: __init__.py:24 msgid "add to a folder" msgstr "" -#: __init__.py:17 __init__.py:25 models.py:31 views.py:21 +#: __init__.py:25 __init__.py:35 models.py:43 views.py:34 msgid "folders" msgstr "" -#: forms.py:20 -msgid "Existing folders" +#: __init__.py:27 +msgid "ACLs" msgstr "" -#: forms.py:22 -msgid "New folder" +#: forms.py:38 +msgid "Folder" msgstr "" #: models.py:11 @@ -69,124 +69,143 @@ msgstr "" msgid "datetime created" msgstr "" -#: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 +#: models.py:42 models.py:47 views.py:108 views.py:137 views.py:162 msgid "folder" msgstr "" -#: models.py:36 +#: models.py:48 msgid "document" msgstr "" -#: models.py:42 views.py:257 +#: models.py:54 views.py:261 msgid "folder document" msgstr "" -#: models.py:43 +#: models.py:55 msgid "folders documents" msgstr "" -#: views.py:24 +#: permissions.py:7 +msgid "Folders" +msgstr "" + +#: permissions.py:9 +msgid "Create new folders" +msgstr "" + +#: permissions.py:10 +msgid "Edit new folders" +msgstr "" + +#: permissions.py:11 +msgid "Delete new folders" +msgstr "" + +#: permissions.py:12 +msgid "Remove documents from folders" +msgstr "" + +#: permissions.py:13 +msgid "View existing folders" +msgstr "" + +#: permissions.py:14 +msgid "Add documents to existing folders" +msgstr "" + +#: views.py:37 msgid "created" msgstr "" -#: views.py:25 +#: views.py:38 msgid "documents" msgstr "" -#: views.py:45 views.py:152 +#: views.py:69 msgid "Folder created successfully" msgstr "" -#: views.py:48 views.py:154 views.py:188 +#: views.py:72 #, python-format msgid "A folder named: %s, already exists." msgstr "" -#: views.py:71 +#: views.py:97 msgid "Folder edited successfully" msgstr "" -#: views.py:74 +#: views.py:100 #, python-format msgid "Error editing folder; %s" msgstr "" -#: views.py:79 +#: views.py:105 #, python-format msgid "edit folder: %s" msgstr "" -#: views.py:101 +#: views.py:129 #, python-format msgid "Folder: %s deleted successfully." msgstr "" -#: views.py:103 +#: views.py:131 #, python-format msgid "Folder: %(folder)s delete error: %(error)s" msgstr "" -#: views.py:114 +#: views.py:142 #, python-format msgid "Are you sure you with to delete the folder: %s?" msgstr "" -#: views.py:131 +#: views.py:168 #, python-format msgid "documents in folder: %s" msgstr "" -#: views.py:157 views.py:191 -msgid "Must specify a new folder or an existing one." -msgstr "" - -#: views.py:162 views.py:196 +#: views.py:188 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." msgstr "" -#: views.py:165 views.py:199 +#: views.py:191 #, python-format msgid "Document: %(document)s is already in folder: %(folder)s." msgstr "" -#: views.py:186 -#, python-format -msgid "Folder \"%s\" created successfully" -msgstr "" - -#: views.py:207 +#: views.py:199 #, python-format msgid "add document \"%s\" to a folder" msgstr "" -#: views.py:223 +#: views.py:219 #, python-format msgid "folders containing: %s" msgstr "" -#: views.py:239 +#: views.py:235 msgid "Must provide at least one folder document." msgstr "" -#: views.py:249 +#: views.py:253 #, python-format msgid "Document: %s removed successfully." msgstr "" -#: views.py:251 +#: views.py:255 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "" -#: views.py:265 +#: views.py:269 #, python-format msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " "\"%(folder)s\"?" msgstr "" -#: views.py:268 +#: views.py:272 #, python-format msgid "" "Are you sure you wish to remove the documents: %(documents)s from the folder " diff --git a/apps/folders/locale/es/LC_MESSAGES/django.mo b/apps/folders/locale/es/LC_MESSAGES/django.mo index 8d12b0b0e1e651b9085d9f3a84174bddac99d1ef..5f0a7d43ab026bd7836abd166a737f72b56b4f2a 100644 GIT binary patch delta 1057 zcmZ9~O-vI(6u|Lk3utQrr9%CtfKrh3i&TYTjK;4E5mPZ3;NU`P+bCV_ZZ#$*O>Dg3 zg+`BD^q?0mO-~vRl9;H8i8q7MgW;qHqZf|&f7`}`lb!kPOm=79yqT{(AG=H6I+`8} zB}Cm%o!laF6c=4IlxuF0J~VJQKE$iIjMKP*QA{<7oWchf!Brf=KiG>y&Gr8;;y(Hr z+$&O&GA~CMSjHf}YxIBMCjHJ9k)7&RkpmdQc07lzcm;W6o@NK$Kz@SqyM>c4>a1%A4E@tn*0VGx#L!J0EekY6PaghF? zSEL&+;}lvrgC8)#`VwN53pk6%@EMNb7d(UkpOY#%fqUprHTt*FIV$X7{0(aA*Kv#h z{G>;ZY@)3`PZm4rKSJHWQ!MGuYrO2jS4hzE2{mPFNRYCQdN+Qde(xjyx^q8jX8KY8 zkDxAi26cg1)cNwrS<7A20G1j)*Zk`QuNhF^B7r+acY2Vj0feY}A2q!?p=L$D*TOH- z@4VF~*TD4nbU`gar>!@dB@I+Bpl*m;Q@<2?J{q~7+DFx0YSDB3zc^>#7}P9jIZP$% z&V|%VN}`-w&k2gVT623{mEX-P)z2;0U7@UP-%3WKnVg+1&PC?Ug=oRFj6%*VL>G*E zMn0OetYX@#ob&`{hQl#^g7HK$emopY#A4n{6X8_)PR`1i`S4l8PA7xIvG~95Mw0Q- zp%}$GZdi7BvS8$`n}%%`lEIWYmoC^QI;&M)c*>Pg@3e2+$Y+X1hKbTvb;)bEDg&*x JYH!<1*IzGvdvgE) delta 1305 zcmZA0OGs2v7{Kw<_-Mwo%%-%|JWgpo7@IK_A4P#?5SC$K4=KFqbr{M!HutKz2p58@ zS`D=-qD?`BizeuS6-2u-Y7tamwCqJ7K}+lZU9T=Wc>T@2_nhyX?>pzdDVr~!{9KTE zRncm>O1PX=O10r@AOC2NGL+hekFf~n@dW`>-Dya25~X0ybew?$Q>G;CAlsp;Yc2 zZor?YQPSTG`I?~u0jii403;oH2Z6xD~WGWb#%Iz|&*r*XBrfH|H z1^Uv9fqq}uURslBIi{`JjpT^w7;a8_fQ1Yi^4cNHu=Ggv=05G{FwdHVaFdJ=7)d>9 g85-S@)~GpV=!E-h!X0coGLmH7H(tMVLEfzIAJ$8|3jhEB diff --git a/apps/folders/locale/es/LC_MESSAGES/django.po b/apps/folders/locale/es/LC_MESSAGES/django.po index 39c54e00b2..87573a5dce 100644 --- a/apps/folders/locale/es/LC_MESSAGES/django.po +++ b/apps/folders/locale/es/LC_MESSAGES/django.po @@ -1,62 +1,61 @@ # 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: \n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 05:10+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:19+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:10 +#: __init__.py:18 msgid "folder list" msgstr "lista de carpetas" -#: __init__.py:11 views.py:53 +#: __init__.py:19 views.py:77 msgid "create folder" msgstr "crear una carpeta" -#: __init__.py:12 +#: __init__.py:20 msgid "edit" msgstr "editar" -#: __init__.py:13 +#: __init__.py:21 msgid "delete" msgstr "eliminar" -#: __init__.py:14 +#: __init__.py:22 msgid "remove from folder" msgstr "Remover de la carpeta" -#: __init__.py:15 +#: __init__.py:23 msgid "folder documents" msgstr "documentos en la carpeta" -#: __init__.py:16 +#: __init__.py:24 msgid "add to a folder" msgstr "Añadir a una carpeta" -#: __init__.py:17 __init__.py:25 models.py:31 views.py:21 +#: __init__.py:25 __init__.py:35 models.py:43 views.py:34 msgid "folders" msgstr "carpetas" -#: forms.py:20 -msgid "Existing folders" -msgstr "Carpetas existentes" +#: __init__.py:27 +msgid "ACLs" +msgstr "" -#: forms.py:22 -msgid "New folder" -msgstr "Nueva carpeta" +#: forms.py:38 +msgid "Folder" +msgstr "" #: models.py:11 msgid "title" @@ -70,118 +69,137 @@ msgstr "usuario" msgid "datetime created" msgstr "fecha y hora creados" -#: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 +#: models.py:42 models.py:47 views.py:108 views.py:137 views.py:162 msgid "folder" msgstr "carpeta" -#: models.py:36 +#: models.py:48 msgid "document" msgstr "documento" -#: models.py:42 views.py:257 +#: models.py:54 views.py:261 msgid "folder document" msgstr "documento de carpeta" -#: models.py:43 +#: models.py:55 msgid "folders documents" msgstr "documentos de carpeta" -#: views.py:24 +#: permissions.py:7 +msgid "Folders" +msgstr "" + +#: permissions.py:9 +msgid "Create new folders" +msgstr "" + +#: permissions.py:10 +msgid "Edit new folders" +msgstr "" + +#: permissions.py:11 +msgid "Delete new folders" +msgstr "" + +#: permissions.py:12 +msgid "Remove documents from folders" +msgstr "" + +#: permissions.py:13 +msgid "View existing folders" +msgstr "" + +#: permissions.py:14 +msgid "Add documents to existing folders" +msgstr "" + +#: views.py:37 msgid "created" msgstr "creado" -#: views.py:25 +#: views.py:38 msgid "documents" msgstr "documentos" -#: views.py:45 views.py:152 +#: views.py:69 msgid "Folder created successfully" msgstr "Carpeta creada con éxito" -#: views.py:48 views.py:154 views.py:188 +#: views.py:72 #, python-format msgid "A folder named: %s, already exists." msgstr "Una carpeta con el nombre: %s, ya existe." -#: views.py:71 +#: views.py:97 msgid "Folder edited successfully" msgstr "Carpeta editada con éxito" -#: views.py:74 +#: views.py:100 #, python-format msgid "Error editing folder; %s" msgstr "Error editando carpeta; %s" -#: views.py:79 +#: views.py:105 #, python-format msgid "edit folder: %s" msgstr "editar carpeta: %s" -#: views.py:101 +#: views.py:129 #, python-format msgid "Folder: %s deleted successfully." msgstr "Carpeta: %s eliminada con éxito." -#: views.py:103 +#: views.py:131 #, python-format msgid "Folder: %(folder)s delete error: %(error)s" msgstr "Carpeta: %(folder)s error de eliminación: %(error)s " -#: views.py:114 +#: views.py:142 #, python-format msgid "Are you sure you with to delete the folder: %s?" msgstr "¿Está seguro de que desea eliminar la carpeta: %s?" -#: views.py:131 +#: views.py:168 #, python-format msgid "documents in folder: %s" msgstr "documentos en la carpeta: %s" -#: views.py:157 views.py:191 -msgid "Must specify a new folder or an existing one." -msgstr "Debe especificar una carpeta nueva o una ya existente." - -#: views.py:162 views.py:196 +#: views.py:188 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." msgstr "" "Documento: %(document)s agregado a la carpeta: %(folder)s exitosamente." -#: views.py:165 views.py:199 +#: views.py:191 #, python-format msgid "Document: %(document)s is already in folder: %(folder)s." msgstr "Documento: %(document)s ya está en la carpeta: %(folder)s." -#: views.py:186 -#, python-format -msgid "Folder \"%s\" created successfully" -msgstr "Carpeta \"%s\" creada exitosamente" - -#: views.py:207 +#: views.py:199 #, python-format msgid "add document \"%s\" to a folder" msgstr "Agregar documento \"%s\" a una carpeta" -#: views.py:223 +#: views.py:219 #, python-format msgid "folders containing: %s" msgstr "carpetas que contienen: %s" -#: views.py:239 +#: views.py:235 msgid "Must provide at least one folder document." msgstr "Debe proveer al menos un documento de carpeta." -#: views.py:249 +#: views.py:253 #, python-format msgid "Document: %s removed successfully." msgstr "Documento: %s removido exitosamente." -#: views.py:251 +#: views.py:255 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Documento: %(document)s error de remoción: %(error)s " -#: views.py:265 +#: views.py:269 #, python-format msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " @@ -190,11 +208,11 @@ msgstr "" "¿Está seguro que desea remover el documento: %(document)s de la carpeta " "\"%(folder)s\"?" -#: views.py:268 +#: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder " -"\"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" msgstr "" "¿Está seguro que desea eliminar los documentos: %(documents)s de la carpeta " "\"%(folder)s\"?" @@ -219,3 +237,5 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Agregar documento a una carpeta" + + diff --git a/apps/folders/locale/it/LC_MESSAGES/django.mo b/apps/folders/locale/it/LC_MESSAGES/django.mo index 6b70cfac007cbe73553babe3a78b2f685e612a53..e6f9907b6ffcaf05145a06e205e77b6d0fbf03af 100644 GIT binary patch delta 978 zcmZ9~OGs2v9LMp$chnqfG%cOV%xk_fYo_UeHWukZZPj8(=&@-`kx;xawvu2XF$i2W zR6AD{1R=#GTouGDqIPW}3R<}`TGYliVc*}q7lID=oX@Di@z72L!$<|@sG@D8T1j05-!4`N?c`2GcKVLXld z%!;;1=P(m1=;Hfmyn$Pco2tzkN3LO-|678;oX4}6#k)9&Z?PNypgz>OBiy1fbQw=#KQ5u3dyPkM9n%ERKzg*| z;kxktWz+(0qcZmhi(2^;I$F_lBxrksO4+-}kEpZpHM;*Bn;2KH4|+a{%7hzv0(UbW zjqYDX_Sz<+`$beB_mzJI@Qexh0tq}Qdub0)$x?7Q9aMVt!%nKUM1@y^)vK?d6o|G@ zKU8spHf-8Kf$0EhL7bW}MQwC-x_41Ks0v0!`}%(g_CA_amQ=c^WIaf$4k-x=wv3&# znExtP>y&<0t@@v)9h(`)g2F}6 zE+U3DLDZ&%7H)T%qA{gaM6v96-x0_LH@ef;U1KXOp^u~Z~-O4+sF{L zfRdTlC=q`^f>hs8GWt7bG3k9e-Y(uT+ZFU zg|d;yC>wZ}^CPnF%$W5k!AOzwBt?SI)J|%)kbl{^ydNoSIJ1yMEr+s=N>($4xih=2 zM~SAHD(_u3%A3i2C2}y=Q9G!7AWKC~e!fU%Hsl&rz4=~jp|(<2Q6;K;kuOmWjud&% za>^z8^7K(>siSfCNh_YP>Ud#O$}XG@4o<}rIzDNRTH~j* zp>13=4sO~c&V=UA=neXu)%k-qZCE8hU zYBNq4rk$|VE+dvOBM~DTLAb0rHC*\n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,45 +18,45 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:10 +#: __init__.py:18 msgid "folder list" msgstr "lista delle cartelle" -#: __init__.py:11 views.py:53 +#: __init__.py:19 views.py:77 msgid "create folder" msgstr "crea cartella" -#: __init__.py:12 +#: __init__.py:20 msgid "edit" msgstr "modifica" -#: __init__.py:13 +#: __init__.py:21 msgid "delete" msgstr "cancella" -#: __init__.py:14 +#: __init__.py:22 msgid "remove from folder" msgstr "rimuovi dalla cartella" -#: __init__.py:15 +#: __init__.py:23 msgid "folder documents" msgstr "cartella documenti" -#: __init__.py:16 +#: __init__.py:24 msgid "add to a folder" msgstr "aggiungi alla cartella" -#: __init__.py:17 __init__.py:25 models.py:31 views.py:21 +#: __init__.py:25 __init__.py:35 models.py:43 views.py:34 msgid "folders" msgstr "cartelle" -#: forms.py:20 -msgid "Existing folders" -msgstr "Cartelle esistenti" +#: __init__.py:27 +msgid "ACLs" +msgstr "" -#: forms.py:22 -msgid "New folder" -msgstr "Nuova cartella" +#: forms.py:38 +msgid "Folder" +msgstr "" #: models.py:11 msgid "title" @@ -70,118 +70,137 @@ msgstr "utente" msgid "datetime created" msgstr "data di creazione" -#: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 +#: models.py:42 models.py:47 views.py:108 views.py:137 views.py:162 msgid "folder" msgstr "cartella" -#: models.py:36 +#: models.py:48 msgid "document" msgstr "documento" -#: models.py:42 views.py:257 +#: models.py:54 views.py:261 msgid "folder document" msgstr "cartella documento" -#: models.py:43 +#: models.py:55 msgid "folders documents" msgstr "cartelle documento" -#: views.py:24 +#: permissions.py:7 +msgid "Folders" +msgstr "" + +#: permissions.py:9 +msgid "Create new folders" +msgstr "" + +#: permissions.py:10 +msgid "Edit new folders" +msgstr "" + +#: permissions.py:11 +msgid "Delete new folders" +msgstr "" + +#: permissions.py:12 +msgid "Remove documents from folders" +msgstr "" + +#: permissions.py:13 +msgid "View existing folders" +msgstr "" + +#: permissions.py:14 +msgid "Add documents to existing folders" +msgstr "" + +#: views.py:37 msgid "created" msgstr "creata" -#: views.py:25 +#: views.py:38 msgid "documents" msgstr "documenti" -#: views.py:45 views.py:152 +#: views.py:69 msgid "Folder created successfully" msgstr "Cartella creata con successo" -#: views.py:48 views.py:154 views.py:188 +#: views.py:72 #, python-format msgid "A folder named: %s, already exists." msgstr "Il nome cartella: %s, già esiste." -#: views.py:71 +#: views.py:97 msgid "Folder edited successfully" msgstr "Cartella modificata con successo" -#: views.py:74 +#: views.py:100 #, python-format msgid "Error editing folder; %s" msgstr "Errore modificando la cartella; %s" -#: views.py:79 +#: views.py:105 #, python-format msgid "edit folder: %s" msgstr "Modifica cartella: %s" -#: views.py:101 +#: views.py:129 #, python-format msgid "Folder: %s deleted successfully." msgstr "Cartella : %s cancellata con successo." -#: views.py:103 +#: views.py:131 #, python-format msgid "Folder: %(folder)s delete error: %(error)s" msgstr "Cartella: %(folder)s errore di cancellazione: %(error)s" -#: views.py:114 +#: views.py:142 #, python-format msgid "Are you sure you with to delete the folder: %s?" msgstr "Sei sicuro di voler cancellare la cartella: %s?" -#: views.py:131 +#: views.py:168 #, python-format msgid "documents in folder: %s" msgstr "documenti nella cartella: %s" -#: views.py:157 views.py:191 -msgid "Must specify a new folder or an existing one." -msgstr "Devi indicare una nuova cartella o una già esistente" - -#: views.py:162 views.py:196 +#: views.py:188 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." msgstr "" "Documento: %(document)s aggiunto alla cartella: %(folder)s successfully." -#: views.py:165 views.py:199 +#: views.py:191 #, python-format msgid "Document: %(document)s is already in folder: %(folder)s." msgstr "Documento: %(document)s è già nella cartella: %(folder)s." -#: views.py:186 -#, python-format -msgid "Folder \"%s\" created successfully" -msgstr "Cartella \"%s\" creata con successo" - -#: views.py:207 +#: views.py:199 #, python-format msgid "add document \"%s\" to a folder" msgstr "aggiungo il dcumento\"%s\" alla cartella" -#: views.py:223 +#: views.py:219 #, python-format msgid "folders containing: %s" msgstr "le cartelle contengono: %s" -#: views.py:239 +#: views.py:235 msgid "Must provide at least one folder document." msgstr "Devi almeno indicare una cartella documenti." -#: views.py:249 +#: views.py:253 #, python-format msgid "Document: %s removed successfully." msgstr "Documento: %s cancellato con successo." -#: views.py:251 +#: views.py:255 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Documento: %(document)s errore di cancellazione: %(error)s" -#: views.py:265 +#: views.py:269 #, python-format msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " @@ -190,7 +209,7 @@ msgstr "" "Sei sicuro di voler rimuovere il documento: %(document)s dalla cartella " "\"%(folder)s\"?" -#: views.py:268 +#: views.py:272 #, python-format msgid "" "Are you sure you wish to remove the documents: %(documents)s from the folder" diff --git a/apps/folders/locale/pt/LC_MESSAGES/django.mo b/apps/folders/locale/pt/LC_MESSAGES/django.mo index d91efb95dde59c9a822f3889f3f52d13545c19c1..a3a65a47c9cc5f770502db75ff3b6f6c8eeb5d24 100644 GIT binary patch delta 1092 zcmZ9~O-vI(6u|Lk`A`Z7qI~#;tEeTCc3VV+`h@{G7@`J|5aPiFYuQM#>RtsBp&qYMLlTZQBJ4{i5L98ZR5eo&i-~LJ2P+I%$o71J^!_-^081N z)Lqok4I)QyA;gPvwL+u=Eo{RFIF5@rfoo{uNToo4C;Ec5xPm;g#;XO_Q3GmW_9pB^VwK~l6Q9A)WN`>PXdB_u z#s={c?G%pTYmBkJG_uMNp2oxY5c}{A>IA=0Q{PrsGJ)G^pTj6#!#(&2^(bEANdowe z&9sfpA_wp&YWoT@rMQ^ao!{jnI9t@6E~2LF84{$tKuz6S)c-$XkRjBaub^gP6}Ms~ z=c7l|#!LV2MC~_m8xEk3AJ_crf;JswOKu{82Ss<-PSpS+RK1UyUj1)BRmW*zh#U;Q zO1slQbaF0NP>iz5UaAJ57f>%dx2Ci+O`m2!qtujZ)LL|R|CiwG%bl7fEt+1k9b8Dg zq$DD^^_u32;;V{qsIXeKRQyzZJrtSt{n?~xrfq*ZHyN99GN$WzmTNn%nXztLS=08s zT*@n)s%g!4N8|b!iJoNQSTx=fkB2W_h>oOg*`DoWql1>8N*dkq#J~S~lZn2rI3+x6 zd46=%wX)ufQsS b!&Ww(v(hX!Tf7$@2o-+SJuiN%e;WD={2z$7 delta 1315 zcmZY8Pe>F|9Ki9{s^!|6W&g~yo|;zHZmSz%W>{nfVJTUWMbNZ8mkFJ*o!PDEAQg1$ zv~-9NiKrm3Ltd;yL0t_Dg8o27wb`L*h&9)4e5 zcumnZ(5vYF9HqA5WPm@~M1fLu_z)}b9Uj3Scoe$}mD+^&a0kA{2(Bzrss;CAEnY^s z{|+w1C#aPgR#P0TWa2AUV(DC^8gU(Rf$GhTeGD@m#S(mufABRf66YyZji0d$i;Gzc zE08JGfD$-@+@jjCnE0xbgCG;#xE%YCB-9y{h0-WDT*-~EqAWCm^YK1PfJe9tpQ3E& z4VL2&zXXkRT8Ank{`x3Xa!wYUmo1rWLYf4Xmr!;qFQsHn^|DO@ zO7>Dp`BGNVCAe%zsv(a;vRy-8N9O~XZBm_llgg~m4a(c{vnbD`hAx>(*7+u1qP#fL zzIhzKYMz7$=pPstE8v, 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-03 03:33+0000\n" -"Last-Translator: renataoliveira \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-02 14:17-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" "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:10 +#: __init__.py:18 msgid "folder list" msgstr "lista de pastas" -#: __init__.py:11 views.py:53 +#: __init__.py:19 views.py:77 msgid "create folder" msgstr "criar pasta" -#: __init__.py:12 +#: __init__.py:20 msgid "edit" msgstr "editar" -#: __init__.py:13 +#: __init__.py:21 msgid "delete" msgstr "excluir" -#: __init__.py:14 +#: __init__.py:22 msgid "remove from folder" msgstr "remover da pasta" -#: __init__.py:15 +#: __init__.py:23 msgid "folder documents" msgstr "pasta de documentos" -#: __init__.py:16 +#: __init__.py:24 msgid "add to a folder" msgstr "adicionar a uma pasta" -#: __init__.py:17 __init__.py:25 models.py:31 views.py:21 +#: __init__.py:25 __init__.py:35 models.py:43 views.py:34 msgid "folders" msgstr "pastas" -#: forms.py:20 -msgid "Existing folders" -msgstr "Pastas existentes" +#: __init__.py:27 +msgid "ACLs" +msgstr "" -#: forms.py:22 -msgid "New folder" -msgstr "Nova pasta" +#: forms.py:38 +msgid "Folder" +msgstr "" #: models.py:11 msgid "title" @@ -71,117 +70,136 @@ msgstr "usuário" msgid "datetime created" msgstr "data e hora da criação" -#: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 +#: models.py:42 models.py:47 views.py:108 views.py:137 views.py:162 msgid "folder" msgstr "pasta" -#: models.py:36 +#: models.py:48 msgid "document" msgstr "documento" -#: models.py:42 views.py:257 +#: models.py:54 views.py:261 msgid "folder document" msgstr "pasta de documento" -#: models.py:43 +#: models.py:55 msgid "folders documents" msgstr "pastas de documentos" -#: views.py:24 +#: permissions.py:7 +msgid "Folders" +msgstr "" + +#: permissions.py:9 +msgid "Create new folders" +msgstr "" + +#: permissions.py:10 +msgid "Edit new folders" +msgstr "" + +#: permissions.py:11 +msgid "Delete new folders" +msgstr "" + +#: permissions.py:12 +msgid "Remove documents from folders" +msgstr "" + +#: permissions.py:13 +msgid "View existing folders" +msgstr "" + +#: permissions.py:14 +msgid "Add documents to existing folders" +msgstr "" + +#: views.py:37 msgid "created" msgstr "criado" -#: views.py:25 +#: views.py:38 msgid "documents" msgstr "documentos" -#: views.py:45 views.py:152 +#: views.py:69 msgid "Folder created successfully" msgstr "Pasta criada com sucesso" -#: views.py:48 views.py:154 views.py:188 +#: views.py:72 #, python-format msgid "A folder named: %s, already exists." msgstr "A pasta com o nome: %s, já existe." -#: views.py:71 +#: views.py:97 msgid "Folder edited successfully" msgstr "Pasta editada com sucesso" -#: views.py:74 +#: views.py:100 #, python-format msgid "Error editing folder; %s" msgstr "Erro ao editar pasta; %s" -#: views.py:79 +#: views.py:105 #, python-format msgid "edit folder: %s" msgstr "editar pasta: %s" -#: views.py:101 +#: views.py:129 #, python-format msgid "Folder: %s deleted successfully." msgstr "Pasta: %s removido com sucesso." -#: views.py:103 +#: views.py:131 #, python-format msgid "Folder: %(folder)s delete error: %(error)s" msgstr "Pasta: %(folder)s erro ao deletar: %(error)s " -#: views.py:114 +#: views.py:142 #, python-format msgid "Are you sure you with to delete the folder: %s?" msgstr "Tem certeza de que deseja excluir a pasta: %s?" -#: views.py:131 +#: views.py:168 #, python-format msgid "documents in folder: %s" msgstr "documentos na pasta: %s" -#: views.py:157 views.py:191 -msgid "Must specify a new folder or an existing one." -msgstr "Deve especificar uma nova pasta ou um já existente." - -#: views.py:162 views.py:196 +#: views.py:188 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." msgstr "Documento: %(document)s adicionados à pasta: %(folder)s com sucesso." -#: views.py:165 views.py:199 +#: views.py:191 #, python-format msgid "Document: %(document)s is already in folder: %(folder)s." msgstr "Documento: %(document)s já está na pasta: %(folder)s ." -#: views.py:186 -#, python-format -msgid "Folder \"%s\" created successfully" -msgstr "Pasta \"%s\" criada com sucesso" - -#: views.py:207 +#: views.py:199 #, python-format msgid "add document \"%s\" to a folder" msgstr "adicionar documento \"%s\" à uma pasta" -#: views.py:223 +#: views.py:219 #, python-format msgid "folders containing: %s" msgstr "pastas contendo: %s" -#: views.py:239 +#: views.py:235 msgid "Must provide at least one folder document." msgstr "Deve fornecer pelo menos um documento da pasta." -#: views.py:249 +#: views.py:253 #, python-format msgid "Document: %s removed successfully." msgstr "Documento: %s removido com sucesso." -#: views.py:251 +#: views.py:255 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Documento: %(document)s erro ao deletar: %(error)s " -#: views.py:265 +#: views.py:269 #, python-format msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " @@ -190,11 +208,11 @@ msgstr "" "Tem certeza de que deseja remover o documento: %(document)s da pasta " "\"%(folder)s\"?" -#: views.py:268 +#: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder " -"\"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" msgstr "" "Tem certeza de que deseja remover os documentos: %(documents)s da pasta " "\"%(folder)s\"?" @@ -210,8 +228,8 @@ msgid "" "created by one user and the documents contained by them don't affect any " "other user folders or documents." msgstr "" -"Estas pastas também podem ser descritas como pastas de usuário. Elas são uma " -"maneira de permitir que os usuários individuais criem os seus próprios " +"Estas pastas também podem ser descritas como pastas de usuário. Elas são uma" +" maneira de permitir que os usuários individuais criem os seus próprios " "métodos de organização do documento. Pastas criadas por um usuário e os " "documentos contidos nelas não afetam todas as pastas de outros usuários ou " "documentos." @@ -219,3 +237,5 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Adicionar documento à uma pasta" + + diff --git a/apps/folders/locale/ru/LC_MESSAGES/django.mo b/apps/folders/locale/ru/LC_MESSAGES/django.mo index 17af131f95395544501b41ad993927e63603aa58..4e552decf85d4f2b299eafd9f82d139cf95ea9b9 100644 GIT binary patch delta 1098 zcmZ9~&r1|x7{KvIS1q^AElbU^nzCBSc6U}b(oMpkJlU_!qJ*GPwslEoWM((ef`zOO zA#_*@>>%ME;AQdBEhMN;5d`5O=n_kKj){ zgGQ6cBaYEV&DbB(mBbEqwFfU?J5FJdZ{#7J2+pI9Um%aXrO_RJ!UOmVIWuWz`x;0R z*^FF6J=1a21@EDzda?TZbL?dN67?>8K@B9-O#XGDZdTFD)sF=37mZLq(gid)GU}(7 ztop%l3VzYMaH!gEK@C{v)IhZuep_kw!FH+!tCyWyQ;BphT@7FxRU_5=pheI1|3dKo zJ<#`hv9uhda!US%)C_1Ab*FlN0_EjEu(tHQeyRMS;YMv_JfELR#pBsre!MUm8*?V( zuH#v5&T-?D*0g2EbDmeoc%>7KZN;9bsgIFJrV_`ZX3{i+=g&pcnOiw8=h)FxRz8z5 zdd$SX?|M^-zHXBe9J0K8blA0QZ^FtuZpuhIqZv2vpud{Y?^a&Ks>{c+jy+>dWM&4k tlU8m*BP%U8UM#f)M?yoEoh?{d7IO<_J9s%zGMn1VMpL+^{4D%A@D~;hjN$+Q delta 1386 zcmZY8TS!zv7{KxInrqr+Gc~(SmR+=6cegULBBAmjGNTLKsils~g0AJRRzyfjfzjnb zdgwuf`M#O)?He%0z=W8SkPj@EA++B}zb_ z(TyWWZt5?}ytyp)g}h3!cH(DE*s@2nxHf3EyKQmXe+y_uv}r zM>(ojI1hi~Qp}%{+R<8+quYZ#f=lpCx;=`rLs_IRJK*NA2&+(zcneBkmYe;Tv%Erw+=1&T3l5_k#Rrt%M^G{w zL%B>9Gg5)9M_K3~%H?WD;^tga0ZDLDs#B=NsHrvSw%kAGtmJ&8kgyY>EG_|6QQ2*$ z$U?F^lDYh+$WF+)mryw=CqM~SGL`K32gwu(ZoJ4{Tb6FP*Nyk$eCh%!NjMh{oRZB` zE{+t*UUo<>T5;k~PGR<(&8NcASU3{WtsQO0tj?%va@3Vo(aM4LytxCByj%6nUD241 z9=DE$TTkntj#wwtpX-iJ9gJvee3Ficp|L#} zZu53_4b;1K7HthiLS4ZS^V4zBbs#b7+MN@)VfWenX4pPw_nP~>U!j#W!`i$saq44} zRAwms8c!vDxVSoTq\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-02 14:17-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" "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:10 +#: __init__.py:18 msgid "folder list" msgstr "список папок" -#: __init__.py:11 views.py:53 +#: __init__.py:19 views.py:77 msgid "create folder" msgstr "создать папку" -#: __init__.py:12 +#: __init__.py:20 msgid "edit" msgstr "редактировать" -#: __init__.py:13 +#: __init__.py:21 msgid "delete" msgstr "удалить" -#: __init__.py:14 +#: __init__.py:22 msgid "remove from folder" msgstr "удалить из папки" -#: __init__.py:15 +#: __init__.py:23 msgid "folder documents" msgstr "документы папки" -#: __init__.py:16 +#: __init__.py:24 msgid "add to a folder" msgstr "добавить в папку" -#: __init__.py:17 __init__.py:25 models.py:31 views.py:21 +#: __init__.py:25 __init__.py:35 models.py:43 views.py:34 msgid "folders" msgstr "папки" -#: forms.py:20 -msgid "Existing folders" -msgstr "Существующие папки" +#: __init__.py:27 +msgid "ACLs" +msgstr "" -#: forms.py:22 -msgid "New folder" -msgstr "Новая папка" +#: forms.py:38 +msgid "Folder" +msgstr "" #: models.py:11 msgid "title" @@ -71,130 +69,149 @@ msgstr "пользователь" msgid "datetime created" msgstr "даты и время создания" -#: models.py:30 models.py:35 views.py:82 views.py:109 views.py:134 +#: models.py:42 models.py:47 views.py:108 views.py:137 views.py:162 msgid "folder" msgstr "папка" -#: models.py:36 +#: models.py:48 msgid "document" msgstr "документ" -#: models.py:42 views.py:257 +#: models.py:54 views.py:261 msgid "folder document" msgstr "документ папки" -#: models.py:43 +#: models.py:55 msgid "folders documents" msgstr "документы из папок" -#: views.py:24 +#: permissions.py:7 +msgid "Folders" +msgstr "" + +#: permissions.py:9 +msgid "Create new folders" +msgstr "" + +#: permissions.py:10 +msgid "Edit new folders" +msgstr "" + +#: permissions.py:11 +msgid "Delete new folders" +msgstr "" + +#: permissions.py:12 +msgid "Remove documents from folders" +msgstr "" + +#: permissions.py:13 +msgid "View existing folders" +msgstr "" + +#: permissions.py:14 +msgid "Add documents to existing folders" +msgstr "" + +#: views.py:37 msgid "created" msgstr "создано" -#: views.py:25 +#: views.py:38 msgid "documents" msgstr "документы" -#: views.py:45 views.py:152 +#: views.py:69 msgid "Folder created successfully" msgstr "Папка успешно создана" -#: views.py:48 views.py:154 views.py:188 +#: views.py:72 #, python-format msgid "A folder named: %s, already exists." msgstr "Папку с именем %s уже существует." -#: views.py:71 +#: views.py:97 msgid "Folder edited successfully" msgstr "Папка успешно изменена" -#: views.py:74 +#: views.py:100 #, python-format msgid "Error editing folder; %s" msgstr "Ошибка редактирования папки; %s." -#: views.py:79 +#: views.py:105 #, python-format msgid "edit folder: %s" msgstr "редактировать папку %s" -#: views.py:101 +#: views.py:129 #, python-format msgid "Folder: %s deleted successfully." msgstr "Папка %s успешно удалена." -#: views.py:103 +#: views.py:131 #, python-format msgid "Folder: %(folder)s delete error: %(error)s" msgstr "При удалении папки %(folder)s произошла ошибка: %(error)s" -#: views.py:114 +#: views.py:142 #, python-format msgid "Are you sure you with to delete the folder: %s?" msgstr "Вы хотите удалить папку %s?" -#: views.py:131 +#: views.py:168 #, python-format msgid "documents in folder: %s" msgstr "документы в папке: %s" -#: views.py:157 views.py:191 -msgid "Must specify a new folder or an existing one." -msgstr "Необходимо указать новую илисуществующую папку ." - -#: views.py:162 views.py:196 +#: views.py:188 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." msgstr "Документ: %(document)s добавлен в папку: %(folder)s успешно." -#: views.py:165 views.py:199 +#: views.py:191 #, python-format msgid "Document: %(document)s is already in folder: %(folder)s." msgstr "Документ: %(document)s is already in folder: %(folder)s." -#: views.py:186 -#, python-format -msgid "Folder \"%s\" created successfully" -msgstr "Папка \"%s\" создана" - -#: views.py:207 +#: views.py:199 #, python-format msgid "add document \"%s\" to a folder" msgstr "добавить документ \"%s\" в папку" -#: views.py:223 +#: views.py:219 #, python-format msgid "folders containing: %s" msgstr "папки, содержащие %s" -#: views.py:239 +#: views.py:235 msgid "Must provide at least one folder document." msgstr "Должна быть хотя бы одна папка документов." -#: views.py:249 +#: views.py:253 #, python-format msgid "Document: %s removed successfully." msgstr "Документ: %s успешно удален." -#: views.py:251 +#: views.py:255 #, python-format msgid "Document: %(document)s delete error: %(error)s" msgstr "Документ:%(document)s ошибка удаления: %(error)s" -#: views.py:265 +#: views.py:269 #, python-format msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " "\"%(folder)s\"?" msgstr "" -"Вы действительно хотите удалить документ: %(document)s из папки \"%(folder)s " -"\"?" +"Вы действительно хотите удалить документ: %(document)s из папки \"%(folder)s" +" \"?" -#: views.py:268 +#: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder " -"\"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" msgstr "" "Вы действительно хотите удалить документы: %(documents)s из папки " "\"%(folder)s\"?" @@ -217,3 +234,5 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Добавить документ в папку" + + diff --git a/apps/history/locale/en/LC_MESSAGES/django.po b/apps/history/locale/en/LC_MESSAGES/django.po index c16d3cc85d..5d192a1598 100644 --- a/apps/history/locale/en/LC_MESSAGES/django.po +++ b/apps/history/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,88 +17,88 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:6 -msgid "Access the history app" -msgstr "" - -#: __init__.py:8 -msgid "History" -msgstr "" - -#: __init__.py:12 models.py:69 +#: __init__.py:10 models.py:71 msgid "history" msgstr "" -#: models.py:16 +#: models.py:18 msgid "namespace" msgstr "" -#: models.py:17 +#: models.py:19 msgid "name" msgstr "" -#: models.py:25 models.py:34 +#: models.py:27 models.py:36 msgid "history type" msgstr "" -#: models.py:26 +#: models.py:28 msgid "history types" msgstr "" -#: models.py:30 +#: models.py:32 msgid "date time" msgstr "" -#: models.py:35 +#: models.py:37 msgid "dictionary" msgstr "" -#: models.py:70 +#: models.py:72 msgid "histories" msgstr "" -#: views.py:23 +#: permissions.py:7 +msgid "History" +msgstr "" + +#: permissions.py:8 +msgid "Access the history of an object" +msgstr "" + +#: views.py:27 msgid "history events" msgstr "" -#: views.py:26 views.py:60 +#: views.py:30 views.py:67 msgid "date and time" msgstr "" -#: views.py:30 +#: views.py:34 msgid "object" msgstr "" -#: views.py:34 views.py:64 +#: views.py:38 views.py:71 msgid "summary" msgstr "" -#: views.py:56 +#: views.py:63 #, python-format msgid "history events for: %s" msgstr "" -#: views.py:81 +#: views.py:91 msgid "Date" msgstr "" -#: views.py:82 +#: views.py:92 msgid "Time" msgstr "" -#: views.py:83 +#: views.py:93 msgid "Object" msgstr "" -#: views.py:84 +#: views.py:94 msgid "Event type" msgstr "" -#: views.py:85 +#: views.py:95 msgid "Event details" msgstr "" -#: views.py:89 +#: views.py:99 #, python-format msgid "details for: %s" msgstr "" diff --git a/apps/history/locale/es/LC_MESSAGES/django.mo b/apps/history/locale/es/LC_MESSAGES/django.mo index f5c1c8a299e275e83e434e940e1959bdbf6f48c2..69f4e6c347f25e8763faea4563f4f854a03834d6 100644 GIT binary patch delta 671 zcmZwEzb^w}7{KwX9;K}o^+1`YMlX>*!(gg3%WR!NQS9rHEXygxsJsBR5csH6$bDjUd>`>$>d(8>O|8b$46$T;KE@*VDJn zJ+r7gzF)HZ_~OEnHse`l;J8I?)(otCcGSp?YKDBWxv_k1Tr`_Y3+N?l3Ln?<{1+LW^VimeXUZq=^HFEiLz A#{d8T delta 691 zcmZ9}ziSg=9LMqJ%-O^y^+&DkV1;LC7dg2*+kzPc(V;^@DQ>06V|ug)X|CKwMJ!|x z$GRL2{sG+t!MHe85S>aL1ji!I4lUiBe1FnRe#vvMdy?<-eZGA2zJ5^e9gh2N3^B=? zX6>`Cv9>)P#1ZPZWAw3h#+Wf2!%@77Rh-2Uyn)J_N98r~94_JoTt=OHeENOQZ1SQ4 z&+t6Vl^`JecaCJ%9jeM$0J{DhZr4^{sM>ilmUF+F4c z3|@>mL0$NFXqD5K*iT>`XNSh90=IDj7f};iMdiQ1DcnIdxQpZXZn)n=HT(@d?jM8_ zRa8-7sZ({WP*HNt6>SI=(}XT+Luj08T+Jxxe-JgEYMg-#Ca6pG7nnP(R#FtUyOG%X zMp|^U{JC{oTm4^N!&@4CaQ|U&H&0wQ%{sw7*G-x>4x=dG6UR1+n(;yq&V?a~!E*96 zE&j_3Zv{6)8_qYQuzXaRs^wYX@-)lKSCyBICD&Ph;?}8|6lK+4DKr22jQUwia_el{ a(MUUOxmNn6-?3|nJ?$@b?fzST()$P3r(6sG diff --git a/apps/history/locale/es/LC_MESSAGES/django.po b/apps/history/locale/es/LC_MESSAGES/django.po index 1d198465b4..965b386e56 100644 --- a/apps/history/locale/es/LC_MESSAGES/django.po +++ b/apps/history/locale/es/LC_MESSAGES/django.po @@ -1,105 +1,106 @@ # 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: \n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-09-30 05:10+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:19+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:6 -msgid "Access the history app" -msgstr "Acceder a la aplicación de historial" - -#: __init__.py:8 -msgid "History" -msgstr "Historial" - -#: __init__.py:12 models.py:69 +#: __init__.py:10 models.py:71 msgid "history" msgstr "historial" -#: models.py:16 +#: models.py:18 msgid "namespace" msgstr "espacio de nombres" -#: models.py:17 +#: models.py:19 msgid "name" msgstr "nombre" -#: models.py:25 models.py:34 +#: models.py:27 models.py:36 msgid "history type" msgstr "tipo de historial" -#: models.py:26 +#: models.py:28 msgid "history types" msgstr "tipos de la historiales" -#: models.py:30 +#: models.py:32 msgid "date time" msgstr "fecha y hora" -#: models.py:35 +#: models.py:37 msgid "dictionary" msgstr "diccionario" -#: models.py:70 +#: models.py:72 msgid "histories" msgstr "historiales" -#: views.py:23 +#: permissions.py:7 +msgid "History" +msgstr "Historial" + +#: permissions.py:8 +msgid "Access the history of an object" +msgstr "" + +#: views.py:27 msgid "history events" msgstr "eventos de historial" -#: views.py:26 views.py:60 +#: views.py:30 views.py:67 msgid "date and time" msgstr "fecha y hora" -#: views.py:30 +#: views.py:34 msgid "object" msgstr "objeto" -#: views.py:34 views.py:64 +#: views.py:38 views.py:71 msgid "summary" msgstr "resumen" -#: views.py:56 +#: views.py:63 #, python-format msgid "history events for: %s" msgstr "eventos de historial para: %s" -#: views.py:81 +#: views.py:91 msgid "Date" msgstr "Fecha" -#: views.py:82 +#: views.py:92 msgid "Time" msgstr "Tiempo" -#: views.py:83 +#: views.py:93 msgid "Object" msgstr "Objeto" -#: views.py:84 +#: views.py:94 msgid "Event type" msgstr "Tipo de evento" -#: views.py:85 +#: views.py:95 msgid "Event details" msgstr "Detalles del evento" -#: views.py:89 +#: views.py:99 #, python-format msgid "details for: %s" msgstr "Detalles para: %s" + + diff --git a/apps/history/locale/it/LC_MESSAGES/django.mo b/apps/history/locale/it/LC_MESSAGES/django.mo index 62c400c776fa49ec09ef36f69d8a563ba38b3953..34020bf60cd3b5b2165c05fdb157688369a0b8b0 100644 GIT binary patch delta 597 zcmX}pze@sP9LMp;A7yD;X|@h#WxJ&7l!Z`2QlRL*2Pfk5;%-$9K{T3-%@{m71`f08w_GR*v2WW;Rqg}5*?xn zI6);mMICsKD&PWp6mgAOcSJXaU5wxv4&fzg{S9jW9Y#6dJTl-iJvwcCLRI?S_ZyYK zKVZx_Mlg*@RDmm~eI;b6DWeLlpbp$a?cYc0bc3NgXDSRR+)WgBA9=}?Xrh0wL-l*~ z85K&dH%sV-2za=Msc?n9px#nn_A2CG^F?Q~d0nZ(T(L0UEeEDc|1%54!eS;*gx9TR xE4$@bjb`0y*-kOFY422>mW@rz*|k&4jyI8Wyop@RZnUj>wcWi9d~|!k&p#BlLuUX0 delta 659 zcmXxhze^lJ7{>A4+!^(ZKcY!2j4~>C)ynST89fA1QizRWIvZKffm_&k%iUp!2v=HZ zb68txBUl(x25e#_*jb8yKtSzMg?yhgd13CeGdJ)1&d&bHU3E3?`m;w4@s9DHam^TJ z?7939kEs8iFpC{89H$$*F^5CgjuZG2CsF$fsC`B3#3k&-HB{c_^ZL5;nFkg4f<4$k zH9W*uc!DZ)fhv57D)b%v2=x69k)I_1f>1y6+La3=iJ@mrdKqS6>rV%#I?Ax?R|{uwrE11O+o1SvnKdZEX*`F zGJ|8Qv8|?2C8?OjDA|g(&0P9_WpcB%(mc*Q#6p diff --git a/apps/history/locale/it/LC_MESSAGES/django.po b/apps/history/locale/it/LC_MESSAGES/django.po index d83692c47b..8a4b7a3f6a 100644 --- a/apps/history/locale/it/LC_MESSAGES/django.po +++ b/apps/history/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-09 17:58+0000\n" -"Last-Translator: Pierpaolo Baldan \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,88 +18,88 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:6 -msgid "Access the history app" -msgstr "Accedi all'applicazione per le versioni" - -#: __init__.py:8 -msgid "History" -msgstr "Versioni" - -#: __init__.py:12 models.py:69 +#: __init__.py:10 models.py:71 msgid "history" msgstr "versioni" -#: models.py:16 +#: models.py:18 msgid "namespace" msgstr "namespace" -#: models.py:17 +#: models.py:19 msgid "name" msgstr "nome" -#: models.py:25 models.py:34 +#: models.py:27 models.py:36 msgid "history type" msgstr "Tipo versione" -#: models.py:26 +#: models.py:28 msgid "history types" msgstr "Tipi di versioni" -#: models.py:30 +#: models.py:32 msgid "date time" msgstr "data" -#: models.py:35 +#: models.py:37 msgid "dictionary" msgstr "dizionario" -#: models.py:70 +#: models.py:72 msgid "histories" msgstr "cronologie" -#: views.py:23 +#: permissions.py:7 +msgid "History" +msgstr "Versioni" + +#: permissions.py:8 +msgid "Access the history of an object" +msgstr "" + +#: views.py:27 msgid "history events" msgstr "eventi cronologia" -#: views.py:26 views.py:60 +#: views.py:30 views.py:67 msgid "date and time" msgstr "data e orario" -#: views.py:30 +#: views.py:34 msgid "object" msgstr "oggetto" -#: views.py:34 views.py:64 +#: views.py:38 views.py:71 msgid "summary" msgstr "sommario" -#: views.py:56 +#: views.py:63 #, python-format msgid "history events for: %s" msgstr "cronologia per gli eventi per: %s" -#: views.py:81 +#: views.py:91 msgid "Date" msgstr "Data" -#: views.py:82 +#: views.py:92 msgid "Time" msgstr "Orario" -#: views.py:83 +#: views.py:93 msgid "Object" msgstr "Oggetto" -#: views.py:84 +#: views.py:94 msgid "Event type" msgstr "Tipo evento" -#: views.py:85 +#: views.py:95 msgid "Event details" msgstr "Dettaglio evento" -#: views.py:89 +#: views.py:99 #, python-format msgid "details for: %s" msgstr "dettaglio per:%s" diff --git a/apps/history/locale/pt/LC_MESSAGES/django.mo b/apps/history/locale/pt/LC_MESSAGES/django.mo index 75258a208b2ef07766852d06c38ea9cae01aad7a..a3d5e1b9e2fae56457324f750d635d6470253aa8 100644 GIT binary patch delta 695 zcmZwEu}>3W7{~F0o>qGZ0%}46Nf`~f-j$G`)lK8nMABel7z{7ua$JBO-d#yxpl%K> zn2RPR>I{>EgU*J9iP@MCUHA(aSPXuD*N#5vd!M)OJ@5NGef!bbceYStJjU=n>fA%rzVE1gKky13qeFe`go!%) zg`;>@ys)f`{<=-J4j92(IDxvM8Y;huD)<7~V!cG=Z=(vn!fW^%>9Yu?#hSIsgvN_s zszVev89GSC6e^;>N7ty(;SOV5Ux-qV;x_a{6uLnb*A09v4-O4<*RpJ@;dx<{t#wvv ztMR6n#HmT5IPo^kj%j;Qns$P;vhZ}#eUt$g%1QGhYms^9fA(^s870qJIl;u1jT}9 z5n(#!#nYnh+{VuDPHIq2jus5lsj+rJGVS3LUD@A^JgF$k7ezmh=~x>4gPf6t-OU zw!Yjh$}E3jUAMdcBWMJ(gZJ*lB&GePM4c`qhb(rE078xH0QGOV8XAr*zBeZ|!0A bB)s07R)a3L&Z@un`+3{h#Y|1^Y=*%<75iRH diff --git a/apps/history/locale/pt/LC_MESSAGES/django.po b/apps/history/locale/pt/LC_MESSAGES/django.po index 6ed4ecd216..81bac85b14 100644 --- a/apps/history/locale/pt/LC_MESSAGES/django.po +++ b/apps/history/locale/pt/LC_MESSAGES/django.po @@ -1,106 +1,107 @@ # 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-03 03:22+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-02 14:17-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" "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:6 -msgid "Access the history app" -msgstr "Acessar a história do app" - -#: __init__.py:8 -msgid "History" -msgstr "História" - -#: __init__.py:12 models.py:69 +#: __init__.py:10 models.py:71 msgid "history" msgstr "história" -#: models.py:16 +#: models.py:18 msgid "namespace" msgstr "namespace" -#: models.py:17 +#: models.py:19 msgid "name" msgstr "nome" -#: models.py:25 models.py:34 +#: models.py:27 models.py:36 msgid "history type" msgstr "tipo de história" -#: models.py:26 +#: models.py:28 msgid "history types" msgstr "tipos de história" -#: models.py:30 +#: models.py:32 msgid "date time" msgstr "hora, data" -#: models.py:35 +#: models.py:37 msgid "dictionary" msgstr "dicionário" -#: models.py:70 +#: models.py:72 msgid "histories" msgstr "histórias" -#: views.py:23 +#: permissions.py:7 +msgid "History" +msgstr "História" + +#: permissions.py:8 +msgid "Access the history of an object" +msgstr "" + +#: views.py:27 msgid "history events" msgstr "eventos da história" -#: views.py:26 views.py:60 +#: views.py:30 views.py:67 msgid "date and time" msgstr "data e hora" -#: views.py:30 +#: views.py:34 msgid "object" msgstr "objeto" -#: views.py:34 views.py:64 +#: views.py:38 views.py:71 msgid "summary" msgstr "sumário" -#: views.py:56 +#: views.py:63 #, python-format msgid "history events for: %s" msgstr "eventos de história para: %s" -#: views.py:81 +#: views.py:91 msgid "Date" msgstr "Data" -#: views.py:82 +#: views.py:92 msgid "Time" msgstr "Tempo" -#: views.py:83 +#: views.py:93 msgid "Object" msgstr "Objeto" -#: views.py:84 +#: views.py:94 msgid "Event type" msgstr "Tipo de evento" -#: views.py:85 +#: views.py:95 msgid "Event details" msgstr "Detalhes do evento" -#: views.py:89 +#: views.py:99 #, python-format msgid "details for: %s" msgstr "detalhes para: %s" + + diff --git a/apps/history/locale/ru/LC_MESSAGES/django.mo b/apps/history/locale/ru/LC_MESSAGES/django.mo index 20fe9c37ee7b05d3916fd59fdab9b44cc48c77ec..2a8e1de8960701dee237cd020b5140ff5c721ac8 100644 GIT binary patch delta 707 zcmZwDKSh z9_o02vd|}#2EL*!c#Kl;1f_vfG|2B{7w;ELeu>v8n<_p^*B?V!_Z3Pb(>O$ZZ9aL> zv<-a0K#0=N=ggzbZ<#;vIpe=j3f$l@-k~(s$88)(PzpLI1s9RSN`k3Lv)UF9G@k6V zKN-@rUX&d_%ijA?3du1_$SHJ_1M))TQcLX;0ZU z6V0l->qq~e_tvRQPuN6hNky@_+WwI5eq9YV-7pS}YFgQt3DXbdtd+7CH1<`^-JkX9 i%CAY6?Zf;^`)__-Us4UPsXW>Vo9(&6-r2vx$J_(jMP-)& delta 714 zcmZY6ziSg=9LMoH6ScP2sD^2Zv&%x`=|D;Yb6v4Y{-`3h~F_ zrbF-_5F8w}D6wMN#jVgM4hjyz%}KCJDRlAuxn}br-+MjZyXU^&=bn7?etY%KVD^>6 zI7W;S>%i z=hPi%l8JV71=aXQ*9smde~#MN>#py*u65nO5uSHY4YqL@2iTo9IL_rH`lt_@M)kXe zF8$NNJpC#q8A1(@C}A8XsF@a5K1gVzhmOofM(Fmy^9`uaYC14&O%r=-8YnJgCL zBr&zw*!0boliEV{fr%=W3qzC36~eQA za5@NB=+DGU<>dc$LEeP%k6$kT$Ub!c0ri4( A5C8xG diff --git a/apps/history/locale/ru/LC_MESSAGES/django.po b/apps/history/locale/ru/LC_MESSAGES/django.po index 78cf703a30..3ba217a895 100644 --- a/apps/history/locale/ru/LC_MESSAGES/django.po +++ b/apps/history/locale/ru/LC_MESSAGES/django.po @@ -1,106 +1,106 @@ # 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: \n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" -"PO-Revision-Date: 2011-11-03 23:30+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-02 14:17-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" "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:6 -msgid "Access the history app" -msgstr "Доступ к истории приложения" - -#: __init__.py:8 -msgid "History" -msgstr "История" - -#: __init__.py:12 models.py:69 +#: __init__.py:10 models.py:71 msgid "history" msgstr "история" -#: models.py:16 +#: models.py:18 msgid "namespace" msgstr "пространство имен" -#: models.py:17 +#: models.py:19 msgid "name" msgstr "имя" -#: models.py:25 models.py:34 +#: models.py:27 models.py:36 msgid "history type" msgstr "тип истории" -#: models.py:26 +#: models.py:28 msgid "history types" msgstr "типы истории" -#: models.py:30 +#: models.py:32 msgid "date time" msgstr "дата и время" -#: models.py:35 +#: models.py:37 msgid "dictionary" msgstr "словарь" -#: models.py:70 +#: models.py:72 msgid "histories" msgstr "истории" -#: views.py:23 +#: permissions.py:7 +msgid "History" +msgstr "История" + +#: permissions.py:8 +msgid "Access the history of an object" +msgstr "" + +#: views.py:27 msgid "history events" msgstr "события" -#: views.py:26 views.py:60 +#: views.py:30 views.py:67 msgid "date and time" msgstr "дата и время" -#: views.py:30 +#: views.py:34 msgid "object" msgstr "объект" -#: views.py:34 views.py:64 +#: views.py:38 views.py:71 msgid "summary" msgstr "итого" -#: views.py:56 +#: views.py:63 #, python-format msgid "history events for: %s" msgstr "события для: %s" -#: views.py:81 +#: views.py:91 msgid "Date" msgstr "Дата" -#: views.py:82 +#: views.py:92 msgid "Time" msgstr "Время" -#: views.py:83 +#: views.py:93 msgid "Object" msgstr "Объект" -#: views.py:84 +#: views.py:94 msgid "Event type" msgstr "Тип события" -#: views.py:85 +#: views.py:95 msgid "Event details" msgstr "Подробности события" -#: views.py:89 +#: views.py:99 #, python-format msgid "details for: %s" msgstr "подробности: %s" + + diff --git a/apps/linking/locale/en/LC_MESSAGES/django.po b/apps/linking/locale/en/LC_MESSAGES/django.po index 17272844d4..49009ca01f 100644 --- a/apps/linking/locale/en/LC_MESSAGES/django.po +++ b/apps/linking/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,67 +17,51 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:11 -msgid "View existing smart links" -msgstr "" - -#: __init__.py:12 -msgid "Create new smart links" -msgstr "" - -#: __init__.py:13 -msgid "Delete smart links" -msgstr "" - -#: __init__.py:14 -msgid "Edit smart links" -msgstr "" - -#: __init__.py:16 -msgid "Smart links" -msgstr "" - -#: __init__.py:22 +#: __init__.py:17 msgid "smart links actions" msgstr "" -#: __init__.py:23 __init__.py:25 models.py:21 views.py:105 +#: __init__.py:18 __init__.py:20 models.py:23 views.py:132 msgid "smart links" msgstr "" -#: __init__.py:26 +#: __init__.py:21 msgid "smart links list" msgstr "" -#: __init__.py:27 +#: __init__.py:22 msgid "create new smart link" msgstr "" -#: __init__.py:28 __init__.py:33 +#: __init__.py:23 __init__.py:28 msgid "edit" msgstr "" -#: __init__.py:29 __init__.py:34 +#: __init__.py:24 __init__.py:29 msgid "delete" msgstr "" -#: __init__.py:31 +#: __init__.py:26 msgid "conditions" msgstr "" -#: __init__.py:32 +#: __init__.py:27 msgid "create condition" msgstr "" -#: forms.py:48 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: forms.py:50 msgid "Pages" msgstr "" -#: forms.py:54 +#: forms.py:56 msgid "Select" msgstr "" -#: forms.py:61 +#: forms.py:63 msgid "Click on the image for full size view of the first page." msgstr "" @@ -149,164 +133,184 @@ msgstr "" msgid "is in regular expression (case insensitive)" msgstr "" -#: models.py:10 +#: models.py:12 msgid "title" msgstr "" -#: models.py:11 views.py:108 +#: models.py:13 views.py:135 msgid "dynamic title" msgstr "" -#: models.py:11 models.py:29 +#: models.py:13 models.py:31 msgid "" "This expression will be evaluated against the current selected document. " "The document metadata is available as variables `metadata` and document " "properties under the variable `document`." msgstr "" -#: models.py:12 models.py:31 views.py:109 views.py:196 +#: models.py:14 models.py:33 views.py:136 views.py:232 msgid "enabled" msgstr "" -#: models.py:20 models.py:25 views.py:256 views.py:287 +#: models.py:22 models.py:27 views.py:296 views.py:330 msgid "smart link" msgstr "" -#: models.py:26 +#: models.py:28 msgid "The inclusion is ignored for the first item." msgstr "" -#: models.py:27 +#: models.py:29 msgid "foreign document data" msgstr "" -#: models.py:27 +#: models.py:29 msgid "" "This represents the metadata of all other documents. Available objects: " "`document.` and `metadata.`." msgstr "" -#: models.py:29 +#: models.py:31 msgid "expression" msgstr "" -#: models.py:30 +#: models.py:32 msgid "negated" msgstr "" -#: models.py:30 +#: models.py:32 msgid "Inverts the logic of the operator." msgstr "" -#: models.py:34 +#: models.py:36 msgid "not" msgstr "" -#: models.py:37 +#: models.py:39 msgid "link condition" msgstr "" -#: models.py:38 +#: models.py:40 msgid "link conditions" msgstr "" -#: views.py:32 +#: permissions.py:7 +msgid "Smart links" +msgstr "" + +#: permissions.py:9 +msgid "View existing smart links" +msgstr "" + +#: permissions.py:10 +msgid "Create new smart links" +msgstr "" + +#: permissions.py:11 +msgid "Delete smart links" +msgstr "" + +#: permissions.py:12 +msgid "Edit smart links" +msgstr "" + +#: views.py:40 msgid "No action selected." msgstr "" -#: views.py:47 +#: views.py:59 #, python-format msgid "documents in smart link: %(group)s" msgstr "" -#: views.py:65 +#: views.py:75 #, python-format msgid "Smart link query error: %s" msgstr "" -#: views.py:76 +#: views.py:97 #, python-format msgid "smart links (%s)" msgstr "" -#: views.py:90 +#: views.py:111 msgid "There no defined smart links for the current document." msgstr "" -#: views.py:124 +#: views.py:152 #, python-format msgid "Smart link: %s created successfully." msgstr "" -#: views.py:131 +#: views.py:159 msgid "Create new smart link" msgstr "" -#: views.py:144 +#: views.py:175 #, python-format msgid "Smart link: %s edited successfully." msgstr "" -#: views.py:153 +#: views.py:184 #, python-format msgid "Edit smart link: %s" msgstr "" -#: views.py:168 +#: views.py:202 #, python-format msgid "Smart link: %s deleted successfully." msgstr "" -#: views.py:170 +#: views.py:204 #, python-format msgid "Error deleting smart link: %(smart_link)s; %(error)s." msgstr "" -#: views.py:180 +#: views.py:213 #, python-format msgid "Are you sure you wish to delete smart link: %s?" msgstr "" -#: views.py:193 +#: views.py:229 #, python-format msgid "conditions for smart link: %s" msgstr "" -#: views.py:216 +#: views.py:254 #, python-format msgid "Smart link condition: \"%s\" created successfully." msgstr "" -#: views.py:223 +#: views.py:261 #, python-format msgid "Add new conditions to smart link: \"%s\"" msgstr "" -#: views.py:243 +#: views.py:283 #, python-format msgid "Smart link condition: \"%s\" edited successfully." msgstr "" -#: views.py:250 +#: views.py:290 msgid "Edit smart link condition" msgstr "" -#: views.py:257 views.py:288 +#: views.py:297 views.py:331 msgid "condition" msgstr "" -#: views.py:274 +#: views.py:317 #, python-format msgid "Smart link condition: \"%s\" deleted successfully." msgstr "" -#: views.py:276 +#: views.py:319 #, python-format msgid "" "Error deleting smart link condition: %(smart_link_condition)s; %(error)s." msgstr "" -#: views.py:290 +#: views.py:333 #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "" diff --git a/apps/linking/locale/es/LC_MESSAGES/django.mo b/apps/linking/locale/es/LC_MESSAGES/django.mo index 17ed6df31e37e19ff86b27e6a6496a794702ad59..19618d1dea6293ce4c7c6e5444f5a8efd8eb5b34 100644 GIT binary patch delta 1700 zcmYk+T};h!9LMo*Nss7Rp*RsjNB@&bCy7%MR%6+WjafLh77j(Txi~XS9yV*OSspg6 z3o|ZkXY(*O#!U@lZp1~iHim1{mGS=k&p-3q`JLDQ`S<;Of8YPVFL*B)oybWVG}=~r z5&cl2SqDBy;*aJen`twE%diI5;XbUuA*{tQ%*VtOv$P z<&1AX)0q_~N;vxrcjI}?n-!0I2sN`9&cHF`UVDSwY9Fu|Cy^M;W}7X5G}KI&qVBIj zO{5hy(VaM(@vWB)rT9FO1iOS9pdYm)H&FvUK|SatY9=3XA%4M3OqvrPI1iOM2Me(V zSK)RfMmysj@53nFhWXP29-;zxj+*HxQV#YS6~J56z@Jbv`-)oADQ`c6hv<9}DzGwC zAT2ma%G*#Ab+Y3bug)g_tsFSQfqHz3+wd2bV2BEm2T>`$fXi{j+kb^h^>+;8Orp{K zU8wsWq3#<;EzK`ffPb(JGxEs4s(DWygW({q#}BBK<&$q2!qs>b%kdU+iH+gK1hWZT z!~Wp{vkiCy-{B`5#QUs+iZH~hpyCW8x7p<=8%pg}RAkq2DUP5b9z)&m9?70fp=Ops zsjHY)paOG{q}hJ&_zBc=PotiD4wboU-tot%%tc>#2PSYC2fm|AT{nQb?hYy=F(er_iVAQ7RYPA;GyaCU{s(e>)PA$Uq%4P0_hC6|&Du}{bYU5u zMiu8U>OmB}J0lIMlutJ;kD7v1@l7|SzlE->uqy5=sPV0doq9UYbt3~e#Zm(*IL$!W zq0rr+)}bo7iay=+aZ=Npp{8X~=JYC8()Eo|3(=KHElUOCyPsYP(p`7WTFXTAM;WvE1xa8Giw?=ata_ delta 1663 zcmYk+OGs2v9LMp$Y33`(XPH`!*~^?sXKZ|oWvP{B1}!3k+Dud+iNZJpkuV`rQmqUl zD1vB_6$GJZ58U)1TL`wWO<@qxq6ZR5tDwHWnJaXd|9sB5bMHOp{LeXauWqm|I+v3) zY?M}_m^ik?EQB|c_@cOz%{F2Q)?+JH-~iU*80O;-T!D$p%yO_0SD_bku?4g6DDJ~9 z446f2oXR>bd`I2rN-J}=DooxYs1Ev2OK}0!(H&HZAEIXR64&4ix^N!V@n2NtiZaa# zumsC7h>XcjIoErUk6qy_su$d#q5(WW&2$vm1~!2jz*AJmuTV34i(0BrPW!j>`!Zgp zf#sqG;>Y)-ycVlz=VhC<<9^(Z*R#og8qKSrG-_aHqEt3e=|_!t1oglpBy08# zHM1|MO_ah`*T7sz(yRe>{UGYa9jF%{M`fA5;xM0PEpb3m`Ac{e^3K) zaktj80E1YAx-X2nFN(^@5RweLiyFuzYVW*6&G4PiL!Z%{-_M z+Hf;=pf=@s)Qj|+M$8gg1F=}NY$|m`QmhvL(ox$>=tSv{Nm*2BBI*hHCxbeF6nE@9 zJ_8*cPEu@HbXncQp|Xq61hqU`x>iCN(J~jSe@>4z z6Ds>*Ux%(j-$+10rp4J2PqUGDSxd|tob?ehiw)mNuoMV`eg{>osWy1bH-)*kAO icn^g`-Mw9*NKZKE4)^qi!ksf*L@Q-W& diff --git a/apps/linking/locale/es/LC_MESSAGES/django.po b/apps/linking/locale/es/LC_MESSAGES/django.po index 653a34abd0..440763b37e 100644 --- a/apps/linking/locale/es/LC_MESSAGES/django.po +++ b/apps/linking/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 20:56+0000\n" -"Last-Translator: rosarior \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18: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" @@ -18,67 +18,51 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:11 -msgid "View existing smart links" -msgstr "Ver enlaces inteligentes existentes" - -#: __init__.py:12 -msgid "Create new smart links" -msgstr "Crear nuevos enlaces inteligentes" - -#: __init__.py:13 -msgid "Delete smart links" -msgstr "Eliminar enlaces inteligentes" - -#: __init__.py:14 -msgid "Edit smart links" -msgstr "Editar enlaces inteligentes" - -#: __init__.py:16 -msgid "Smart links" -msgstr "Enlaces inteligentes" - -#: __init__.py:22 +#: __init__.py:17 msgid "smart links actions" msgstr "acciones de enlaces inteligentes" -#: __init__.py:23 __init__.py:25 models.py:21 views.py:105 +#: __init__.py:18 __init__.py:20 models.py:23 views.py:132 msgid "smart links" msgstr "enlaces inteligentes" -#: __init__.py:26 +#: __init__.py:21 msgid "smart links list" msgstr "lista de enlaces inteligentes" -#: __init__.py:27 +#: __init__.py:22 msgid "create new smart link" msgstr "crear un enlace inteligente nuevo" -#: __init__.py:28 __init__.py:33 +#: __init__.py:23 __init__.py:28 msgid "edit" msgstr "editar" -#: __init__.py:29 __init__.py:34 +#: __init__.py:24 __init__.py:29 msgid "delete" msgstr "borrar" -#: __init__.py:31 +#: __init__.py:26 msgid "conditions" msgstr "condiciones" -#: __init__.py:32 +#: __init__.py:27 msgid "create condition" msgstr "crear condicion" -#: forms.py:48 +#: __init__.py:31 +msgid "ACLs" +msgstr "LCAs" + +#: forms.py:50 msgid "Pages" msgstr "Páginas" -#: forms.py:54 +#: forms.py:56 msgid "Select" msgstr "Seleccionar" -#: forms.py:61 +#: forms.py:63 msgid "Click on the image for full size view of the first page." msgstr "" "Haga clic en la imagen para ver el tamaño completo de la primera página." @@ -151,15 +135,15 @@ msgstr "está en la expresión regular" msgid "is in regular expression (case insensitive)" msgstr "está en la expresión regular (mayúsculas y minúsculas)" -#: models.py:10 +#: models.py:12 msgid "title" msgstr "título" -#: models.py:11 views.py:108 +#: models.py:13 views.py:135 msgid "dynamic title" msgstr "título dinámico" -#: models.py:11 models.py:29 +#: models.py:13 models.py:31 msgid "" "This expression will be evaluated against the current selected document. " "The document metadata is available as variables `metadata` and document " @@ -169,23 +153,23 @@ msgstr "" " Los metadatos del documento están disponible como variables `metadata` y " "las propiedades del documento en la variable `document`." -#: models.py:12 models.py:31 views.py:109 views.py:196 +#: models.py:14 models.py:33 views.py:136 views.py:232 msgid "enabled" msgstr "habilitado" -#: models.py:20 models.py:25 views.py:256 views.py:287 +#: models.py:22 models.py:27 views.py:296 views.py:330 msgid "smart link" msgstr "enlace inteligente" -#: models.py:26 +#: models.py:28 msgid "The inclusion is ignored for the first item." msgstr "La inclusión es ignorada para el primer artículo." -#: models.py:27 +#: models.py:29 msgid "foreign document data" msgstr "datos de documento foráneo" -#: models.py:27 +#: models.py:29 msgid "" "This represents the metadata of all other documents. Available objects: " "`document.` and `metadata.`." @@ -194,122 +178,142 @@ msgstr "" "disponibles: `document.` y `metadata.`." -#: models.py:29 +#: models.py:31 msgid "expression" msgstr "expresión" -#: models.py:30 +#: models.py:32 msgid "negated" msgstr "negado" -#: models.py:30 +#: models.py:32 msgid "Inverts the logic of the operator." msgstr "Invierte la lógica del operador." -#: models.py:34 +#: models.py:36 msgid "not" msgstr "no" -#: models.py:37 +#: models.py:39 msgid "link condition" msgstr "condición de enlace" -#: models.py:38 +#: models.py:40 msgid "link conditions" msgstr "condiciones de enlace" -#: views.py:32 +#: permissions.py:7 +msgid "Smart links" +msgstr "Enlaces inteligentes" + +#: permissions.py:9 +msgid "View existing smart links" +msgstr "Ver enlaces inteligentes existentes" + +#: permissions.py:10 +msgid "Create new smart links" +msgstr "Crear nuevos enlaces inteligentes" + +#: permissions.py:11 +msgid "Delete smart links" +msgstr "Eliminar enlaces inteligentes" + +#: permissions.py:12 +msgid "Edit smart links" +msgstr "Editar enlaces inteligentes" + +#: views.py:40 msgid "No action selected." msgstr "Ninguna acción seleccionada." -#: views.py:47 +#: views.py:59 #, python-format msgid "documents in smart link: %(group)s" msgstr "documentos en el enlace inteligente: %(group)s" -#: views.py:65 +#: views.py:75 #, python-format msgid "Smart link query error: %s" msgstr "Error en consulta de enlace inteligente: %s" -#: views.py:76 +#: views.py:97 #, python-format msgid "smart links (%s)" msgstr "enlaces inteligentes (%s)" -#: views.py:90 +#: views.py:111 msgid "There no defined smart links for the current document." msgstr "No hay enlaces inteligentes definidos para el documento actual." -#: views.py:124 +#: views.py:152 #, python-format msgid "Smart link: %s created successfully." msgstr "Enlace inteligente: %s creado exitosamente." -#: views.py:131 +#: views.py:159 msgid "Create new smart link" msgstr "Crear un enlace inteligente nuevo" -#: views.py:144 +#: views.py:175 #, python-format msgid "Smart link: %s edited successfully." msgstr "Enlace inteligente: %s editado exitosamente." -#: views.py:153 +#: views.py:184 #, python-format msgid "Edit smart link: %s" msgstr "Editar enlace inteligente: %s" -#: views.py:168 +#: views.py:202 #, python-format msgid "Smart link: %s deleted successfully." msgstr "Enlace inteligente: %s eliminado exitosamente." -#: views.py:170 +#: views.py:204 #, python-format msgid "Error deleting smart link: %(smart_link)s; %(error)s." msgstr "" "Error al tratar de eliminar enlace inteligente: %(smart_link)s; %(error)s." -#: views.py:180 +#: views.py:213 #, python-format msgid "Are you sure you wish to delete smart link: %s?" msgstr "¿Está seguro que desea eliminar el enlace inteligente: %s?" -#: views.py:193 +#: views.py:229 #, python-format msgid "conditions for smart link: %s" msgstr "condiciones de enlace inteligente: %s" -#: views.py:216 +#: views.py:254 #, python-format msgid "Smart link condition: \"%s\" created successfully." msgstr "Condición de enlace inteligente: \"%s\" creada exitosamente." -#: views.py:223 +#: views.py:261 #, python-format msgid "Add new conditions to smart link: \"%s\"" msgstr "Añadir nuevas condiciones de enlace inteligente: \"%s\"" -#: views.py:243 +#: views.py:283 #, python-format msgid "Smart link condition: \"%s\" edited successfully." msgstr "Condición de enlace inteligente: \"%s\", editada exitosamente." -#: views.py:250 +#: views.py:290 msgid "Edit smart link condition" msgstr "Editar condición de enlace inteligente" -#: views.py:257 views.py:288 +#: views.py:297 views.py:331 msgid "condition" msgstr "condición" -#: views.py:274 +#: views.py:317 #, python-format msgid "Smart link condition: \"%s\" deleted successfully." msgstr "Condición de enlace inteligente: \"%s\" ha eliminada exitosamente." -#: views.py:276 +#: views.py:319 #, python-format msgid "" "Error deleting smart link condition: %(smart_link_condition)s; %(error)s." @@ -317,7 +321,7 @@ msgstr "" "Error al tratar de eliminar la condición de enlace inteligente: " "%(smart_link_condition)s; %(error)s." -#: views.py:290 +#: views.py:333 #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "" diff --git a/apps/linking/locale/it/LC_MESSAGES/django.mo b/apps/linking/locale/it/LC_MESSAGES/django.mo index 706288b1b5f67a667815bcd7640c5619850a3e9c..01c4149cc85733cd974414851cf99bbf419de7e4 100644 GIT binary patch delta 694 zcmX}p!Asjv9Ki9P+mxRLCe&Mrey>PSs$p%O%tpbe&-?w}OY(ldG)lip-qeWcB9R5Icuv@M1ScEf58ILK*!!hEv9+7dh@eF-DL@OgQ zjP*<;GRWkH1kXuFuSgtY+BA+3XEBDaQB_bznkH-b6hG+oPdG~aO|Spd`72a~HZg&} zF^hj9o#>;VOl26=#+RsC{uWhbt9pGG+li~lkT2X!JVAA!CQ_u_q54&woR((D5UQ3t zcps-x6+HcliTc2tb`jNsYp5#QM}{18Q=O^f0G^_HVWal>K`K!!n3fubU3Bb{X%#Ii z{=RIw{&uh#gd66px8*xV!LtAFn{e!p*U3!I4VV4OR%p24rdJ6eLTxgM7c{hpUBus1+l}qjyc3u45CcAuR!sX6A}wqlNbsEe zU@_+SvzA~RaW%Sd7*z+8$j~H$b-3l6A7MN3xpRKw;L z(L- BRg?e# diff --git a/apps/linking/locale/it/LC_MESSAGES/django.po b/apps/linking/locale/it/LC_MESSAGES/django.po index 92812d71b3..903258ac6f 100644 --- a/apps/linking/locale/it/LC_MESSAGES/django.po +++ b/apps/linking/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-12 08:59+0000\n" -"Last-Translator: Pierpaolo Baldan \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,67 +18,51 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:11 -msgid "View existing smart links" -msgstr "Vista intelligente dei link esistenti" - -#: __init__.py:12 -msgid "Create new smart links" -msgstr "Crea link intelligenti" - -#: __init__.py:13 -msgid "Delete smart links" -msgstr "Cancella link intelligenti" - -#: __init__.py:14 -msgid "Edit smart links" -msgstr "Modifica link intelligenti" - -#: __init__.py:16 -msgid "Smart links" -msgstr "Link intelligenti" - -#: __init__.py:22 +#: __init__.py:17 msgid "smart links actions" msgstr "azioni dei link intelligenti" -#: __init__.py:23 __init__.py:25 models.py:21 views.py:105 +#: __init__.py:18 __init__.py:20 models.py:23 views.py:132 msgid "smart links" msgstr "link intelligenti" -#: __init__.py:26 +#: __init__.py:21 msgid "smart links list" msgstr "lista dei link intelligenti" -#: __init__.py:27 +#: __init__.py:22 msgid "create new smart link" msgstr "crea nuovi link intelligenti" -#: __init__.py:28 __init__.py:33 +#: __init__.py:23 __init__.py:28 msgid "edit" msgstr "modifica" -#: __init__.py:29 __init__.py:34 +#: __init__.py:24 __init__.py:29 msgid "delete" msgstr "cancella" -#: __init__.py:31 +#: __init__.py:26 msgid "conditions" msgstr "condizioni" -#: __init__.py:32 +#: __init__.py:27 msgid "create condition" msgstr "crea condizioni" -#: forms.py:48 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: forms.py:50 msgid "Pages" msgstr "Pagine" -#: forms.py:54 +#: forms.py:56 msgid "Select" msgstr "Seleziona" -#: forms.py:61 +#: forms.py:63 msgid "Click on the image for full size view of the first page." msgstr "Click sull'immagine per vedere la prima pagina" @@ -150,15 +134,15 @@ msgstr "è un'espressione regolare" msgid "is in regular expression (case insensitive)" msgstr "è un'espressione regolare (case insensitive)" -#: models.py:10 +#: models.py:12 msgid "title" msgstr "titolo" -#: models.py:11 views.py:108 +#: models.py:13 views.py:135 msgid "dynamic title" msgstr "titolo dinamico" -#: models.py:11 models.py:29 +#: models.py:13 models.py:31 msgid "" "This expression will be evaluated against the current selected document. " "The document metadata is available as variables `metadata` and document " @@ -168,23 +152,23 @@ msgstr "" "metadati del documento sono disponibile come variabili `metadati` e le " "proprietà dei documenti sotto la variabile `documento`." -#: models.py:12 models.py:31 views.py:109 views.py:196 +#: models.py:14 models.py:33 views.py:136 views.py:232 msgid "enabled" msgstr "abilitato" -#: models.py:20 models.py:25 views.py:256 views.py:287 +#: models.py:22 models.py:27 views.py:296 views.py:330 msgid "smart link" msgstr "link intelligente" -#: models.py:26 +#: models.py:28 msgid "The inclusion is ignored for the first item." msgstr "L'inserimento viene ignorato per la prima voce." -#: models.py:27 +#: models.py:29 msgid "foreign document data" msgstr "dati del documento estero" -#: models.py:27 +#: models.py:29 msgid "" "This represents the metadata of all other documents. Available objects: " "`document.` and `metadata.`." @@ -192,121 +176,141 @@ msgstr "" "Questo rappresenta i metadati di tutti gli altri documenti. Oggetti " "disponibili: `document.` e `metadata.`." -#: models.py:29 +#: models.py:31 msgid "expression" msgstr "espressione" -#: models.py:30 +#: models.py:32 msgid "negated" msgstr "negato" -#: models.py:30 +#: models.py:32 msgid "Inverts the logic of the operator." msgstr "Inverti la logica dell'operazione" -#: models.py:34 +#: models.py:36 msgid "not" msgstr "not" -#: models.py:37 +#: models.py:39 msgid "link condition" msgstr "condizione per il link" -#: models.py:38 +#: models.py:40 msgid "link conditions" msgstr "condizioni per i link" -#: views.py:32 +#: permissions.py:7 +msgid "Smart links" +msgstr "Link intelligenti" + +#: permissions.py:9 +msgid "View existing smart links" +msgstr "Vista intelligente dei link esistenti" + +#: permissions.py:10 +msgid "Create new smart links" +msgstr "Crea link intelligenti" + +#: permissions.py:11 +msgid "Delete smart links" +msgstr "Cancella link intelligenti" + +#: permissions.py:12 +msgid "Edit smart links" +msgstr "Modifica link intelligenti" + +#: views.py:40 msgid "No action selected." msgstr "Nessuna azione selezionata " -#: views.py:47 +#: views.py:59 #, python-format msgid "documents in smart link: %(group)s" msgstr "documenti nei link intelligenti: %(group)s" -#: views.py:65 +#: views.py:75 #, python-format msgid "Smart link query error: %s" msgstr "Interrogazione dei link intelligenti, errore: %s" -#: views.py:76 +#: views.py:97 #, python-format msgid "smart links (%s)" msgstr "link intelligenti (%s)" -#: views.py:90 +#: views.py:111 msgid "There no defined smart links for the current document." msgstr "Non ci sono link intelligenti per questo documento." -#: views.py:124 +#: views.py:152 #, python-format msgid "Smart link: %s created successfully." msgstr "Link inteligente: %s creato con successo." -#: views.py:131 +#: views.py:159 msgid "Create new smart link" msgstr "Crea un nuovo link intelligente" -#: views.py:144 +#: views.py:175 #, python-format msgid "Smart link: %s edited successfully." msgstr "Link intelligente: %s modificato con successo." -#: views.py:153 +#: views.py:184 #, python-format msgid "Edit smart link: %s" msgstr "Modifica il link intelligente: %s" -#: views.py:168 +#: views.py:202 #, python-format msgid "Smart link: %s deleted successfully." msgstr "Link intelligente: %s cancellato con successo." -#: views.py:170 +#: views.py:204 #, python-format msgid "Error deleting smart link: %(smart_link)s; %(error)s." msgstr "Errore link intelligente: %(smart_link)s; %(error)s." -#: views.py:180 +#: views.py:213 #, python-format msgid "Are you sure you wish to delete smart link: %s?" msgstr "Sei sicuro di voler cancella questo link intelligente: %s?" -#: views.py:193 +#: views.py:229 #, python-format msgid "conditions for smart link: %s" msgstr "condizioni per il link intelligente: %s" -#: views.py:216 +#: views.py:254 #, python-format msgid "Smart link condition: \"%s\" created successfully." msgstr "Condizione per il link intelligente: \"%s\" creata con successo." -#: views.py:223 +#: views.py:261 #, python-format msgid "Add new conditions to smart link: \"%s\"" msgstr "Aggiungi una nuova condizione al link intelligente: \"%s\"" -#: views.py:243 +#: views.py:283 #, python-format msgid "Smart link condition: \"%s\" edited successfully." msgstr "Condizione per il link intelligente: \"%s\" modificato con successo." -#: views.py:250 +#: views.py:290 msgid "Edit smart link condition" msgstr "Modifica condizioni per i link intelligenti" -#: views.py:257 views.py:288 +#: views.py:297 views.py:331 msgid "condition" msgstr "condizioni" -#: views.py:274 +#: views.py:317 #, python-format msgid "Smart link condition: \"%s\" deleted successfully." msgstr "Condizioni per il link intelligente: \"%s\" cancellato con successo." -#: views.py:276 +#: views.py:319 #, python-format msgid "" "Error deleting smart link condition: %(smart_link_condition)s; %(error)s." @@ -314,7 +318,7 @@ msgstr "" "Errore nella cancellazione del link intelligente: %(smart_link_condition)s; " "%(error)s." -#: views.py:290 +#: views.py:333 #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "" diff --git a/apps/linking/locale/pt/LC_MESSAGES/django.mo b/apps/linking/locale/pt/LC_MESSAGES/django.mo index 86f916301e326e5dd5af66a241ebf710a493c7f9..ea1c804a3b76c04fe017ee69737f5278727431b5 100644 GIT binary patch delta 41 qcmaE>_*QYl5l&tsT>}tOFf_3;G@pEtQ;rM5wXia@-29XC3mX6m77S1T delta 41 xcmaE>_*QYl5l&u1T|+}%BO?VvLn|Y*$rm~0xD0g-j1&w^txOCy|K$9_1^@|?3_}0_ diff --git a/apps/linking/locale/pt/LC_MESSAGES/django.po b/apps/linking/locale/pt/LC_MESSAGES/django.po index bbfb8411f3..e9104b3edc 100644 --- a/apps/linking/locale/pt/LC_MESSAGES/django.po +++ b/apps/linking/locale/pt/LC_MESSAGES/django.po @@ -9,8 +9,8 @@ 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: 2012-01-02 05:40+0000\n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" @@ -19,67 +19,51 @@ msgstr "" "Language: pt\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:11 -msgid "View existing smart links" -msgstr "Ver os ligações inteligentes" - -#: __init__.py:12 -msgid "Create new smart links" -msgstr "Criar novas ligações inteligentes" - -#: __init__.py:13 -msgid "Delete smart links" -msgstr "Excluir ligações inteligentes" - -#: __init__.py:14 -msgid "Edit smart links" -msgstr "Editar ligações inteligentes" - -#: __init__.py:16 -msgid "Smart links" -msgstr "Ligações inteligentes" - -#: __init__.py:22 +#: __init__.py:17 msgid "smart links actions" msgstr "ações do ligações inteligentes" -#: __init__.py:23 __init__.py:25 models.py:21 views.py:105 +#: __init__.py:18 __init__.py:20 models.py:23 views.py:132 msgid "smart links" msgstr "ligações inteligentes" -#: __init__.py:26 +#: __init__.py:21 msgid "smart links list" msgstr "lista de ligações inteligentes" -#: __init__.py:27 +#: __init__.py:22 msgid "create new smart link" msgstr "criar um novo ligação inteligente" -#: __init__.py:28 __init__.py:33 +#: __init__.py:23 __init__.py:28 msgid "edit" msgstr "editar" -#: __init__.py:29 __init__.py:34 +#: __init__.py:24 __init__.py:29 msgid "delete" msgstr "excluir" -#: __init__.py:31 +#: __init__.py:26 msgid "conditions" msgstr "condições" -#: __init__.py:32 +#: __init__.py:27 msgid "create condition" msgstr "criar condições" -#: forms.py:48 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: forms.py:50 msgid "Pages" msgstr "Páginas" -#: forms.py:54 +#: forms.py:56 msgid "Select" msgstr "Selecionar" -#: forms.py:61 +#: forms.py:63 msgid "Click on the image for full size view of the first page." msgstr "Clique na imagem para ver em tamanho grande a primeira página." @@ -151,15 +135,15 @@ msgstr "está em expressão regular" msgid "is in regular expression (case insensitive)" msgstr "está em expressão regular (case insensitive)" -#: models.py:10 +#: models.py:12 msgid "title" msgstr "título" -#: models.py:11 views.py:108 +#: models.py:13 views.py:135 msgid "dynamic title" msgstr "título dinâmico" -#: models.py:11 models.py:29 +#: models.py:13 models.py:31 msgid "" "This expression will be evaluated against the current selected document. " "The document metadata is available as variables `metadata` and document " @@ -169,23 +153,23 @@ msgstr "" "metadados do documento estão disponíveis como variáveis \"​metadados \" e " "propriedades do documento em variáveis `documento`." -#: models.py:12 models.py:31 views.py:109 views.py:196 +#: models.py:14 models.py:33 views.py:136 views.py:232 msgid "enabled" msgstr "habilitado" -#: models.py:20 models.py:25 views.py:256 views.py:287 +#: models.py:22 models.py:27 views.py:296 views.py:330 msgid "smart link" msgstr "ligação inteligente" -#: models.py:26 +#: models.py:28 msgid "The inclusion is ignored for the first item." msgstr "A inclusão é ignorada para o primeiro item." -#: models.py:27 +#: models.py:29 msgid "foreign document data" msgstr "dados de documentos estrangeiros" -#: models.py:27 +#: models.py:29 msgid "" "This represents the metadata of all other documents. Available objects: " "`document.` and `metadata.`." @@ -193,127 +177,147 @@ msgstr "" "Isto representa os metadados de todos os outros documentos. Objetos " "disponíveis: `document. ` e ` metadata. `." -#: models.py:29 +#: models.py:31 msgid "expression" msgstr "expressão" -#: models.py:30 +#: models.py:32 msgid "negated" msgstr "negada" -#: models.py:30 +#: models.py:32 msgid "Inverts the logic of the operator." msgstr "Inverte a lógica do operador." -#: models.py:34 +#: models.py:36 msgid "not" msgstr "não" -#: models.py:37 +#: models.py:39 msgid "link condition" msgstr "condição de ligação" -#: models.py:38 +#: models.py:40 msgid "link conditions" msgstr "condições de ligação" -#: views.py:32 +#: permissions.py:7 +msgid "Smart links" +msgstr "Ligações inteligentes" + +#: permissions.py:9 +msgid "View existing smart links" +msgstr "Ver os ligações inteligentes" + +#: permissions.py:10 +msgid "Create new smart links" +msgstr "Criar novas ligações inteligentes" + +#: permissions.py:11 +msgid "Delete smart links" +msgstr "Excluir ligações inteligentes" + +#: permissions.py:12 +msgid "Edit smart links" +msgstr "Editar ligações inteligentes" + +#: views.py:40 msgid "No action selected." msgstr "Nenhuma ação selecionada." -#: views.py:47 +#: views.py:59 #, python-format msgid "documents in smart link: %(group)s" msgstr "" -#: views.py:65 +#: views.py:75 #, python-format msgid "Smart link query error: %s" msgstr "" -#: views.py:76 +#: views.py:97 #, python-format msgid "smart links (%s)" msgstr "ligações inteligente (%s)" -#: views.py:90 +#: views.py:111 msgid "There no defined smart links for the current document." msgstr "" -#: views.py:124 +#: views.py:152 #, python-format msgid "Smart link: %s created successfully." msgstr "Ligação inteligente: %s criado com sucesso." -#: views.py:131 +#: views.py:159 msgid "Create new smart link" msgstr "" -#: views.py:144 +#: views.py:175 #, python-format msgid "Smart link: %s edited successfully." msgstr "" -#: views.py:153 +#: views.py:184 #, python-format msgid "Edit smart link: %s" msgstr "Editar Ligação inteligente: %s" -#: views.py:168 +#: views.py:202 #, python-format msgid "Smart link: %s deleted successfully." msgstr "" -#: views.py:170 +#: views.py:204 #, python-format msgid "Error deleting smart link: %(smart_link)s; %(error)s." msgstr "" -#: views.py:180 +#: views.py:213 #, python-format msgid "Are you sure you wish to delete smart link: %s?" msgstr "" -#: views.py:193 +#: views.py:229 #, python-format msgid "conditions for smart link: %s" msgstr "" -#: views.py:216 +#: views.py:254 #, python-format msgid "Smart link condition: \"%s\" created successfully." msgstr "" -#: views.py:223 +#: views.py:261 #, python-format msgid "Add new conditions to smart link: \"%s\"" msgstr "" -#: views.py:243 +#: views.py:283 #, python-format msgid "Smart link condition: \"%s\" edited successfully." msgstr "" -#: views.py:250 +#: views.py:290 msgid "Edit smart link condition" msgstr "" -#: views.py:257 views.py:288 +#: views.py:297 views.py:331 msgid "condition" msgstr "condição" -#: views.py:274 +#: views.py:317 #, python-format msgid "Smart link condition: \"%s\" deleted successfully." msgstr "" -#: views.py:276 +#: views.py:319 #, python-format msgid "" "Error deleting smart link condition: %(smart_link_condition)s; %(error)s." msgstr "" -#: views.py:290 +#: views.py:333 #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "" diff --git a/apps/linking/locale/ru/LC_MESSAGES/django.mo b/apps/linking/locale/ru/LC_MESSAGES/django.mo index 982203f193776ad495b8bb62d85e9d34edc71955..d9072fc1ba8d1530f7059dc0794473d49df14a22 100644 GIT binary patch delta 705 zcmX}o%}Z2K7{~EnGPqE2rWsRoN^e94)*bJ>_%;bmB@|&8S3yldMj2$p@xqJ@Vv7NV zphb&t6}XAEfr0G;1^)n{B9a#3rd>NXMK1gv?JR7(g4214DMkBPg_(| zGe4m#QVwG{iWAt6?{El@&@7C$N;mOQU#1ryc4SJ=kHHkv2;goKWQ@jp0B9H6m9HF*^UV-naL&x zY$xM54bR4Gw@@usir$Jnl3y)kt(24eUpJUd4sD%;+tRK#UnsA7mg`mW<)UW|m;Hf6 d*&j$OdMoSs<-&Syv6L?^ClY?9kVdZXP=p8W}bb1r%qFc3)O|HYAGI&MkOU4 zOIh5+G+yC0dQH-6JjQ2u?fdA7RkN5^pFpZ&*6vHL-a36zM4ym9*?NSgsp!oP;}Q*`96J z%}iVA#f{u*ZaHs_XVw-I5!WWk&x&4!n7yJ*g CIaPE3 diff --git a/apps/linking/locale/ru/LC_MESSAGES/django.po b/apps/linking/locale/ru/LC_MESSAGES/django.po index 5a02a2120d..9ffe9932ed 100644 --- a/apps/linking/locale/ru/LC_MESSAGES/django.po +++ b/apps/linking/locale/ru/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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:47+0000\n" -"Last-Translator: gsv70 \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,67 +18,51 @@ 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:11 -msgid "View existing smart links" -msgstr "Просмотр отношений" - -#: __init__.py:12 -msgid "Create new smart links" -msgstr "Создать отношение" - -#: __init__.py:13 -msgid "Delete smart links" -msgstr "Удалить отношения" - -#: __init__.py:14 -msgid "Edit smart links" -msgstr "Редактировать отношения" - -#: __init__.py:16 -msgid "Smart links" -msgstr "Отношения" - -#: __init__.py:22 +#: __init__.py:17 msgid "smart links actions" msgstr "действия отношений" -#: __init__.py:23 __init__.py:25 models.py:21 views.py:105 +#: __init__.py:18 __init__.py:20 models.py:23 views.py:132 msgid "smart links" msgstr "отношения" -#: __init__.py:26 +#: __init__.py:21 msgid "smart links list" msgstr "список отношений" -#: __init__.py:27 +#: __init__.py:22 msgid "create new smart link" msgstr "создать отношение" -#: __init__.py:28 __init__.py:33 +#: __init__.py:23 __init__.py:28 msgid "edit" msgstr "редактировать" -#: __init__.py:29 __init__.py:34 +#: __init__.py:24 __init__.py:29 msgid "delete" msgstr "удалить" -#: __init__.py:31 +#: __init__.py:26 msgid "conditions" msgstr "условия" -#: __init__.py:32 +#: __init__.py:27 msgid "create condition" msgstr "создать условие" -#: forms.py:48 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: forms.py:50 msgid "Pages" msgstr "Страницы" -#: forms.py:54 +#: forms.py:56 msgid "Select" msgstr "Выбрать" -#: forms.py:61 +#: forms.py:63 msgid "Click on the image for full size view of the first page." msgstr "" "Нажмите на изображение для просмотра первой страницы в полном размере." @@ -151,15 +135,15 @@ msgstr "В регулярном выражении" msgid "is in regular expression (case insensitive)" msgstr "В регулярном выражении (без учета регистра)" -#: models.py:10 +#: models.py:12 msgid "title" msgstr "название" -#: models.py:11 views.py:108 +#: models.py:13 views.py:135 msgid "dynamic title" msgstr "динамический заголовок" -#: models.py:11 models.py:29 +#: models.py:13 models.py:31 msgid "" "This expression will be evaluated against the current selected document. " "The document metadata is available as variables `metadata` and document " @@ -169,23 +153,23 @@ msgstr "" "документа доступны как переменные `metadata` и свойства документа в " "переменной `document`." -#: models.py:12 models.py:31 views.py:109 views.py:196 +#: models.py:14 models.py:33 views.py:136 views.py:232 msgid "enabled" msgstr "разрешено" -#: models.py:20 models.py:25 views.py:256 views.py:287 +#: models.py:22 models.py:27 views.py:296 views.py:330 msgid "smart link" msgstr "отношение" -#: models.py:26 +#: models.py:28 msgid "The inclusion is ignored for the first item." msgstr "Включение игнорируется для первого элемента." -#: models.py:27 +#: models.py:29 msgid "foreign document data" msgstr "foreign document data" -#: models.py:27 +#: models.py:29 msgid "" "This represents the metadata of all other documents. Available objects: " "`document.` and `metadata.`." @@ -193,127 +177,147 @@ msgstr "" "Это представляет метаданные всех других документов. Доступные объекты: " "`document. ` и `metadata. `." -#: models.py:29 +#: models.py:31 msgid "expression" msgstr "выражение" -#: models.py:30 +#: models.py:32 msgid "negated" msgstr "отрицание" -#: models.py:30 +#: models.py:32 msgid "Inverts the logic of the operator." msgstr "Инвертирует логику оператора." -#: models.py:34 +#: models.py:36 msgid "not" msgstr "не" -#: models.py:37 +#: models.py:39 msgid "link condition" msgstr "условие ссылки" -#: models.py:38 +#: models.py:40 msgid "link conditions" msgstr "условия ссылки" -#: views.py:32 +#: permissions.py:7 +msgid "Smart links" +msgstr "Отношения" + +#: permissions.py:9 +msgid "View existing smart links" +msgstr "Просмотр отношений" + +#: permissions.py:10 +msgid "Create new smart links" +msgstr "Создать отношение" + +#: permissions.py:11 +msgid "Delete smart links" +msgstr "Удалить отношения" + +#: permissions.py:12 +msgid "Edit smart links" +msgstr "Редактировать отношения" + +#: views.py:40 msgid "No action selected." msgstr "Никаких действий не выбрано." -#: views.py:47 +#: views.py:59 #, python-format msgid "documents in smart link: %(group)s" msgstr "документы в отношении %(group)s" -#: views.py:65 +#: views.py:75 #, python-format msgid "Smart link query error: %s" msgstr "Ошибка запроса в отношении %s" -#: views.py:76 +#: views.py:97 #, python-format msgid "smart links (%s)" msgstr "отношения (%s)" -#: views.py:90 +#: views.py:111 msgid "There no defined smart links for the current document." msgstr "Для этого документа отношения не определены." -#: views.py:124 +#: views.py:152 #, python-format msgid "Smart link: %s created successfully." msgstr "Отношение %s создано." -#: views.py:131 +#: views.py:159 msgid "Create new smart link" msgstr "Создать новое отношение" -#: views.py:144 +#: views.py:175 #, python-format msgid "Smart link: %s edited successfully." msgstr "Отношение %s изменено." -#: views.py:153 +#: views.py:184 #, python-format msgid "Edit smart link: %s" msgstr "Редактировать отношение %s" -#: views.py:168 +#: views.py:202 #, python-format msgid "Smart link: %s deleted successfully." msgstr "Отношение %s удалено." -#: views.py:170 +#: views.py:204 #, python-format msgid "Error deleting smart link: %(smart_link)s; %(error)s." msgstr "Ошибка при удалении отношения %(smart_link)s; %(error)s." -#: views.py:180 +#: views.py:213 #, python-format msgid "Are you sure you wish to delete smart link: %s?" msgstr "Вы действительно хотите удалить отношение %s?" -#: views.py:193 +#: views.py:229 #, python-format msgid "conditions for smart link: %s" msgstr "условия для отношения %s" -#: views.py:216 +#: views.py:254 #, python-format msgid "Smart link condition: \"%s\" created successfully." msgstr "Условие для отношения \"%s\" успешно создано." -#: views.py:223 +#: views.py:261 #, python-format msgid "Add new conditions to smart link: \"%s\"" msgstr "Добавить новые условия отношения \"%s\"" -#: views.py:243 +#: views.py:283 #, python-format msgid "Smart link condition: \"%s\" edited successfully." msgstr "Условие отношения \"%s\" изменено." -#: views.py:250 +#: views.py:290 msgid "Edit smart link condition" msgstr "Изменить условие отношения" -#: views.py:257 views.py:288 +#: views.py:297 views.py:331 msgid "condition" msgstr "состояние" -#: views.py:274 +#: views.py:317 #, python-format msgid "Smart link condition: \"%s\" deleted successfully." msgstr "Условие отношения \"%s\" удалено." -#: views.py:276 +#: views.py:319 #, python-format msgid "" "Error deleting smart link condition: %(smart_link_condition)s; %(error)s." msgstr "Ошибка при удалении условия %(smart_link_condition)s; %(error)s." -#: views.py:290 +#: views.py:333 #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "Вы действительно хотите удалить условие отношения \"%s\"?" diff --git a/apps/main/locale/en/LC_MESSAGES/django.po b/apps/main/locale/en/LC_MESSAGES/django.po index 3f41a881ab..7cfcc72746 100644 --- a/apps/main/locale/en/LC_MESSAGES/django.po +++ b/apps/main/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-12-06 03:26-0400\n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,43 +17,43 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:31 +#: __init__.py:33 msgid "maintenance" msgstr "" -#: __init__.py:32 +#: __init__.py:34 msgid "statistics" msgstr "" -#: __init__.py:33 +#: __init__.py:35 msgid "diagnostics" msgstr "" -#: __init__.py:34 +#: __init__.py:36 msgid "sentry" msgstr "" -#: __init__.py:35 +#: __init__.py:37 msgid "admin site" msgstr "" -#: __init__.py:38 +#: __init__.py:40 msgid "home" msgstr "" -#: __init__.py:40 +#: __init__.py:42 msgid "search" msgstr "" -#: views.py:41 +#: views.py:43 msgid "maintenance menu" msgstr "" -#: views.py:53 +#: views.py:56 msgid "Statistics" msgstr "" -#: views.py:61 +#: views.py:66 msgid "Diagnostics" msgstr "" @@ -99,37 +99,37 @@ msgstr "" msgid "Secondary menu" msgstr "" -#: templates/base.html:302 +#: templates/base.html:301 #, python-format msgid "Actions for %(name)s: %(navigation_object)s" msgstr "" -#: templates/base.html:304 templates/base.html.py:336 +#: templates/base.html:303 templates/base.html.py:346 #, python-format msgid "Actions for: %(navigation_object)s" msgstr "" -#: templates/base.html:307 +#: templates/base.html:306 msgid "Available actions" msgstr "" -#: templates/base.html:319 templates/base.html.py:351 +#: templates/base.html:318 templates/base.html.py:361 msgid "Related actions" msgstr "" -#: templates/base.html:334 +#: templates/base.html:329 templates/base.html.py:374 +msgid "Other available actions" +msgstr "" + +#: templates/base.html:344 #, python-format msgid "Actions for %(object_name)s: %(navigation_object)s" msgstr "" -#: templates/base.html:339 +#: templates/base.html:349 msgid "Actions" msgstr "" -#: templates/base.html:364 -msgid "Other available actions" -msgstr "" - #: templates/home.html:8 msgid "Django based open source document management system" msgstr "" @@ -140,6 +140,6 @@ msgid "" "indexing, tagging, file serving integration and OCR capabilities" msgstr "" -#: templates/project_description.html:15 +#: templates/project_description.html:18 msgid "Released under the GPL V3 License" msgstr "" diff --git a/apps/main/locale/es/LC_MESSAGES/django.mo b/apps/main/locale/es/LC_MESSAGES/django.mo index 61b945b1de16be1f8cde1c0ff2a678dd7b369da3..4897cb44a060811c92d833def3f02fa7a6348ed9 100644 GIT binary patch delta 331 zcmX>uxn)5 zUjbUKKux?rx)ew|1L8(KiQy?t`q-S$7)H8?z8QVA+ z7!-l@86YhHq~8H)kU{@}G|+4YUM>a(VIVCEq=9-FG=Vh8Vk008Qs)k&*?@E?lph16 z#en=QAPqEvp%E(I4V9k+q=Ehh%54^6n#-)h72qGD>s*wYSdy8ar|Xhfl4_-3WMF8d nYXCwDh9*{q=97Q1UgYsf%u6p#Ob1G*7EeCK7QNYseJV2mzcwvP delta 352 zcmXZXKS;ws6vy#bOIll6{MT4;s)IVU*H-Ni+*}=86&#|3G+-0SC4*AwAh=7wNx@NE z{8Ku(x;Troi>u(`E`Ezy?sLC;ckgjG=BxQo$qYU-A}5AOUPSg-s_5V(o?-*faUDmv zgkNcWhD#Ol0v@8mGG5^(-r*E}r{}*oB9{uh!Iy#z#ANfq!6N?PG@8Z#M$5=7S;INp zKzhhFjtB4Hc%Y9t?5Ft*=gAjHOSw(!Pig%b`8T!U?8J3;r5i;@mQt=4b>scULC{lS zpzY8LLe;a6ZC`m>$Bs_!jcU17Z?)^qPOZ6WwL8hX@s>R1c1v5f@5Z+4ST#ovi}}m! EAM9o}5&!@I diff --git a/apps/main/locale/es/LC_MESSAGES/django.po b/apps/main/locale/es/LC_MESSAGES/django.po index aa29907f8d..f708c44413 100644 --- a/apps/main/locale/es/LC_MESSAGES/django.po +++ b/apps/main/locale/es/LC_MESSAGES/django.po @@ -1,67 +1,68 @@ # 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, 2012. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2011-12-06 03:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2012-01-02 05:42+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:31 +#: __init__.py:33 msgid "maintenance" msgstr "mantenimiento" -#: __init__.py:32 +#: __init__.py:34 msgid "statistics" msgstr "estadísticas" -#: __init__.py:33 +#: __init__.py:35 msgid "diagnostics" msgstr "diagnósticos" -#: __init__.py:34 +#: __init__.py:36 msgid "sentry" msgstr "sentry" -#: __init__.py:35 +#: __init__.py:37 msgid "admin site" msgstr "sitio administrativo" -#: __init__.py:38 +#: __init__.py:40 msgid "home" msgstr "inicio" -#: __init__.py:40 +#: __init__.py:42 msgid "search" msgstr "búsqueda" -#: views.py:41 +#: views.py:43 msgid "maintenance menu" msgstr "menú de mantenimiento" -#: views.py:53 +#: views.py:56 msgid "Statistics" msgstr "Estadísticas" -#: views.py:61 +#: views.py:66 msgid "Diagnostics" msgstr "Diagnósticos" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or" -" by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or " +"by a menu entry." msgstr "" "Controla si la funcionalidad de búsqueda es proporcionada por una barra " "lateral o por una entrada de menú." @@ -102,37 +103,37 @@ msgstr "Desconectarse" msgid "Secondary menu" msgstr "Menú secundario" -#: templates/base.html:302 +#: templates/base.html:301 #, python-format msgid "Actions for %(name)s: %(navigation_object)s" msgstr "Acciones para %(name)s: %(navigation_object)s " -#: templates/base.html:304 templates/base.html.py:336 +#: templates/base.html:303 templates/base.html.py:346 #, python-format msgid "Actions for: %(navigation_object)s" msgstr "Acciones para: %(navigation_object)s " -#: templates/base.html:307 +#: templates/base.html:306 msgid "Available actions" msgstr "Acciones disponibles" -#: templates/base.html:319 templates/base.html.py:351 +#: templates/base.html:318 templates/base.html.py:361 msgid "Related actions" msgstr "Acciones relacionadas" -#: templates/base.html:334 +#: templates/base.html:329 templates/base.html.py:374 +msgid "Other available actions" +msgstr "Otras acciones disponibles" + +#: templates/base.html:344 #, python-format msgid "Actions for %(object_name)s: %(navigation_object)s" msgstr "Acciones para %(object_name)s: %(navigation_object)s " -#: templates/base.html:339 +#: templates/base.html:349 msgid "Actions" msgstr "Acciones" -#: templates/base.html:364 -msgid "Other available actions" -msgstr "Otras acciones disponibles" - #: templates/home.html:8 msgid "Django based open source document management system" msgstr "Sistema de manejo de documentos de código abierto basado en Django" @@ -146,8 +147,6 @@ msgstr "" "personaliables, indexación, etiquedado de documentos, integración de " "servicio de archivos y capacidades de OCR" -#: templates/project_description.html:15 +#: templates/project_description.html:18 msgid "Released under the GPL V3 License" msgstr "Publicado bajo la licencia GPL v3" - - diff --git a/apps/main/locale/it/LC_MESSAGES/django.mo b/apps/main/locale/it/LC_MESSAGES/django.mo index 1fbd414fb8680cc7438b01b73c090f66b3c17373..dac1ab2db9d9dfdf4b6f901d6b54ab305fa7ef44 100644 GIT binary patch delta 331 zcmXZXu}eZx6vy$Ony;rm(2_I)K|&gY2R;b{+o~l9bZChNxq*m72J#$qadK%29O_?) z1_L3XHTpXOhlYmc#=aMYbMNPJ?m35hf3hFhS1&T2MWk9>+LZL|NPGB;gc2mnn85&# zaUXAy&;#2xK4A-AFoh{sVx;nD=M?ZAOSp?)n8rU>V-+~KiB;kN?SLBE#*=ma9O=;& z=I{n>-4Hi$f*#)E7CxeVz%$y1&d}B`kpBv_!^&x%jG9;}*=$_;r~S4GyLUbR%!KWF lv04eLe#J&HIIIUp)3^AicVT*+f$4DF4W}dLdcJhr*gu*MDHi|$ delta 368 zcmXZXy-EW?5Ww+?F{k+u(U2g57%YWz?@l=33LDc!(ZWg)*+{rtkzBaD6sclsWf331 z2e435C>C0Xy;!950elMo3xVDFEyK((`&s>~K2>t#Sx&?+h%AZ73Skp#XrY6`eUx-`7R7zLsk2Vd@Eq5*UC(y>hO-}d{^YLkHPO~Z Q=~(x}p$;jTzFOt{KN3VYhX4Qo diff --git a/apps/main/locale/it/LC_MESSAGES/django.po b/apps/main/locale/it/LC_MESSAGES/django.po index d2e9b27283..1072c590d1 100644 --- a/apps/main/locale/it/LC_MESSAGES/django.po +++ b/apps/main/locale/it/LC_MESSAGES/django.po @@ -1,67 +1,68 @@ # 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: 2011-12-06 03:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2012-01-02 04:46+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:31 +#: __init__.py:33 msgid "maintenance" msgstr "manutenzione" -#: __init__.py:32 +#: __init__.py:34 msgid "statistics" msgstr "statistiche" -#: __init__.py:33 +#: __init__.py:35 msgid "diagnostics" msgstr "disgnostica" -#: __init__.py:34 +#: __init__.py:36 msgid "sentry" msgstr "guardia" -#: __init__.py:35 +#: __init__.py:37 msgid "admin site" msgstr "sito d'amministrazione" -#: __init__.py:38 +#: __init__.py:40 msgid "home" msgstr "home" -#: __init__.py:40 +#: __init__.py:42 msgid "search" msgstr "cerca" -#: views.py:41 +#: views.py:43 msgid "maintenance menu" msgstr "menu manutenzione" -#: views.py:53 +#: views.py:56 msgid "Statistics" msgstr "Statistiche" -#: views.py:61 +#: views.py:66 msgid "Diagnostics" msgstr "Diagnostica" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or" -" by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or " +"by a menu entry." msgstr "" "Controlla se la funzionalità di ricerca è fornita da un widget sidebar o da " "una voce di menu." @@ -102,37 +103,37 @@ msgstr "Logout" msgid "Secondary menu" msgstr "Menu secondario" -#: templates/base.html:302 +#: templates/base.html:301 #, python-format msgid "Actions for %(name)s: %(navigation_object)s" msgstr "Azione per %(name)s: %(navigation_object)s" -#: templates/base.html:304 templates/base.html.py:336 +#: templates/base.html:303 templates/base.html.py:346 #, python-format msgid "Actions for: %(navigation_object)s" msgstr "Azione per : %(navigation_object)s" -#: templates/base.html:307 +#: templates/base.html:306 msgid "Available actions" msgstr "Azioni disponibili" -#: templates/base.html:319 templates/base.html.py:351 +#: templates/base.html:318 templates/base.html.py:361 msgid "Related actions" msgstr "Azioni relative" -#: templates/base.html:334 +#: templates/base.html:329 templates/base.html.py:374 +msgid "Other available actions" +msgstr "Altre azioni disponibili" + +#: templates/base.html:344 #, python-format msgid "Actions for %(object_name)s: %(navigation_object)s" msgstr "Azioni per %(object_name)s: %(navigation_object)s" -#: templates/base.html:339 +#: templates/base.html:349 msgid "Actions" msgstr "Azioni" -#: templates/base.html:364 -msgid "Other available actions" -msgstr "Altre azioni disponibili" - #: templates/home.html:8 msgid "Django based open source document management system" msgstr "" @@ -142,12 +143,10 @@ msgid "" "Open source, Django based electronic document manager with custom metadata, " "indexing, tagging, file serving integration and OCR capabilities" msgstr "" -"Open Source, Django programma per la gestione documentale con la possibilità" -" di metadati personalizabili, tagging, indicizzazione, integrazione con file" -" server e con possibilità di OCR" +"Open Source, Django programma per la gestione documentale con la possibilità " +"di metadati personalizabili, tagging, indicizzazione, integrazione con file " +"server e con possibilità di OCR" -#: templates/project_description.html:15 +#: templates/project_description.html:18 msgid "Released under the GPL V3 License" msgstr "Rilasciato con licenza GPL V3" - - diff --git a/apps/main/locale/pt/LC_MESSAGES/django.mo b/apps/main/locale/pt/LC_MESSAGES/django.mo index ad932ad425e1d57ef05704b46ffc5154ee77d252..06faf53e0cd35e85f4bc0f07e586538b7144d084 100644 GIT binary patch delta 331 zcmW;HJxjw-6vpwVHjTDK5Um9fq(jz76SS6qlP-mV4uXS=cPPcB21&=#4-s7*-0UO` z^fL&q&TfK&i{HTi5ia+4U!HTgw`l%sy#$rnq9S!`(yF9yU)sc9w7tg^VStC2Vu%^8 z;R81D5i=}t9YZc@sRTXj;T(@~7r)Tzyt-!EW3f}0Hn4}*ppRs9i59#@dTW9$oTBCK zk+s9vy15DZs_ux+i`U2@?qLeI&l(p fY_#KpG(IYpwbx+a#-oWFah>JG)W0e}{r&16`KBsX delta 369 zcmXZXze~eF7{>9p)>IoS7Oh1Pq=Q?DNm|U1Nzko=4lcULX-k`-O~{YI#g2{+8C)El zoP>^c6?Ah|@IP>Jb@6*D9PfvF@41(|&y~FPP$`Vx3L>5%GAANc$}+B@-Zv>0ws9L3 zZsHBj;}mQ7gb}{uB6c`rq#WZcp5i@raUGY+fA^YY8OsKZ9U4^~L_HuvvU2$!yh3Kn zE!Oc4b?y;M_<|LDMg5=;)c3!TCEpaCH%t-!``cT^x=hR&RqPDXH1ch`AEblqZ0kH6 z+HshuI0$2Vs4mpV4w5A6CFbG5k+mE5R2qaMYfq&;ztM7B*K%8y<29VN-}3Tn<2mn^ SP8RmnsGq4mk!Uh4ImI7CT{$oS diff --git a/apps/main/locale/pt/LC_MESSAGES/django.po b/apps/main/locale/pt/LC_MESSAGES/django.po index 6f871ca74f..37d5417566 100644 --- a/apps/main/locale/pt/LC_MESSAGES/django.po +++ b/apps/main/locale/pt/LC_MESSAGES/django.po @@ -1,67 +1,68 @@ # 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: 2011-12-06 03:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2012-01-02 04:46+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:31 +#: __init__.py:33 msgid "maintenance" msgstr "manutenção" -#: __init__.py:32 +#: __init__.py:34 msgid "statistics" msgstr "estatísticas" -#: __init__.py:33 +#: __init__.py:35 msgid "diagnostics" msgstr "diagnósticos" -#: __init__.py:34 +#: __init__.py:36 msgid "sentry" msgstr "sentinela" -#: __init__.py:35 +#: __init__.py:37 msgid "admin site" msgstr "site de administação" -#: __init__.py:38 +#: __init__.py:40 msgid "home" msgstr "inicio" -#: __init__.py:40 +#: __init__.py:42 msgid "search" msgstr "pesquisa" -#: views.py:41 +#: views.py:43 msgid "maintenance menu" msgstr "menu de manutenção" -#: views.py:53 +#: views.py:56 msgid "Statistics" msgstr "Estatísticas" -#: views.py:61 +#: views.py:66 msgid "Diagnostics" msgstr "Diagnósticos" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or" -" by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or " +"by a menu entry." msgstr "" "Controla-se a funcionalidade de pesquisa é fornecido por um widget da barra " "lateral ou por uma entrada de menu." @@ -102,37 +103,37 @@ msgstr "Sair" msgid "Secondary menu" msgstr "Menu secundário" -#: templates/base.html:302 +#: templates/base.html:301 #, python-format msgid "Actions for %(name)s: %(navigation_object)s" msgstr "Ações para %(name)s: %(navigation_object)s " -#: templates/base.html:304 templates/base.html.py:336 +#: templates/base.html:303 templates/base.html.py:346 #, python-format msgid "Actions for: %(navigation_object)s" msgstr "Ações para: %(navigation_object)s " -#: templates/base.html:307 +#: templates/base.html:306 msgid "Available actions" msgstr "Ações disponíveis" -#: templates/base.html:319 templates/base.html.py:351 +#: templates/base.html:318 templates/base.html.py:361 msgid "Related actions" msgstr "Ações relacionadas" -#: templates/base.html:334 +#: templates/base.html:329 templates/base.html.py:374 +msgid "Other available actions" +msgstr "Outras ações disponíveis" + +#: templates/base.html:344 #, python-format msgid "Actions for %(object_name)s: %(navigation_object)s" msgstr "Ações para %(object_name)s : %(navigation_object)s " -#: templates/base.html:339 +#: templates/base.html:349 msgid "Actions" msgstr "Ações" -#: templates/base.html:364 -msgid "Other available actions" -msgstr "Outras ações disponíveis" - #: templates/home.html:8 msgid "Django based open source document management system" msgstr "" @@ -146,8 +147,6 @@ msgstr "" "personalizados, indexação, etiquetagem, a integração do serviço de arquivos " "e recursos de OCR" -#: templates/project_description.html:15 +#: templates/project_description.html:18 msgid "Released under the GPL V3 License" msgstr "Liberado sob a licença GPL V3" - - diff --git a/apps/main/locale/ru/LC_MESSAGES/django.mo b/apps/main/locale/ru/LC_MESSAGES/django.mo index eceafef576f83e40363075c1b75ce035b3455ebd..cdf481963155c85dd2d32298ce0ce0d7931b6ecc 100644 GIT binary patch delta 896 zcmXZaOK1~87{KvK(!{2wwYIhC!_=t?rfAwcERj%DFz7{XpyH(puFVot^3Xhl_7Wm^ zQ!hb1c=3T3QHX|01?|CWMK&UMk%At)iyl1s|F#)+<~OsO-S5jc^Jw($SZ!;d>%OAx zqwl2;Ih2}0pOb;s#2xq=2k>2I{Rt1V{)$mlE~WNE483>}cjFbjj3wNO7RK;9x|OP_ z{w}3F+!)3?7(hS1z+LzeC-DpR;a}`Q7jH9FedxnMlteYk^B_vV7|QQXbk<4iXPrV1 z@s(jul)8rUViA8(g;kUfUSiOgMtSiz#_<6j$Im#8z1`c-=kNgQbNCW(;4n^5mK@Ha z#Ca+bU%g`TkbvtLW}PB!`9K{b_#DUa8xG+g9Kmk>_7R*!E_I$kDzu0aaJh58jx((9 z;UU~WN#GX-r1Za;$cO(SdD#0WAMiK4&heUrl8vAos+T@NmoU=g)CA~*bV+fP&c@nJ zY9&ohm7E01q$q{G8KCyaK$BC&A+l2<0X0UKZ0r_Hww^hs9I@oGQOFeaRikXCb@94c z(B)#av}EdZajBX&3l*I=3P#4Xr{$G$#mu)hU5_0Hds6ckLZ?cmQOOnyp`=kU6FM4> zL_=Y@bmV9v5^ub9>+VQgN5YBOV~s7he|*6#Wy}?QCYP-kdM;DG84sV#8`<1+soDs7 z7JO&Prb@Vk=EkaLvGvn4@9ceIt+(s#Th^NO-fA{By{AX44^~rK8|^xi4eO1yrnmn{ JYsQ;%{Rg=Mf^Yx; delta 875 zcmXxiPiWI{6u|LcyRL4vvvcZZ_eU}(%u&;%UFo2Tco@S&!7>Fw7?MitB5fl{D!7Bu zizg>YQ4bzeJPE>tUIjgPQ3S!8Fm@8blO6><_N%MOz@0ZQVC)sdkEb&kg zM;OzLbWEuQ{EHIL;!5qo=QxHh`|~%LWBwkC_zREX+<;QUxPtq!hHF^Iz4#6X@e?MM z3e^{W+~dMmoWQFIr80O6XYoGn!`GO?x5%MBa!TW8lmfR=?teo`^b+9CP0)@l&^v|MSmT`a)#qs4{FTN1#jV7MP=GTMZdc`mrPO#po=dZXe!*hMh zb6n48SvRe=;rM>X_Pbky6JbFw6m_$#nTwTTSvO0jnW~-BSM3{)@3?J!*$V86Ry5^L z1>G!aW~ovt=S(71wfsQ8;8|_IX$7uV(N^8M?FBAI*|byM?uC3meZJwgH>{?;ai-C- joTgOP)syGDo5@S*s?~0EtOm)vPValN7Vo_nzBcd=a3yvl diff --git a/apps/main/locale/ru/LC_MESSAGES/django.po b/apps/main/locale/ru/LC_MESSAGES/django.po index 517f7a9a6b..d56bcfdd89 100644 --- a/apps/main/locale/ru/LC_MESSAGES/django.po +++ b/apps/main/locale/ru/LC_MESSAGES/django.po @@ -1,67 +1,69 @@ # 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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2011-12-06 03:26-0400\n" -"PO-Revision-Date: 2012-01-02 04:46+0000\n" -"Last-Translator: Roberto Rosario \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-02 14:17-0400\n" +"PO-Revision-Date: 2012-01-17 10:58+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" -"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:31 +#: __init__.py:33 msgid "maintenance" msgstr "техническое обслуживание" -#: __init__.py:32 +#: __init__.py:34 msgid "statistics" msgstr "статистика" -#: __init__.py:33 +#: __init__.py:35 msgid "diagnostics" msgstr "диагностика" -#: __init__.py:34 +#: __init__.py:36 msgid "sentry" msgstr "sentry" -#: __init__.py:35 +#: __init__.py:37 msgid "admin site" msgstr "админка" -#: __init__.py:38 +#: __init__.py:40 msgid "home" msgstr "Начало" -#: __init__.py:40 +#: __init__.py:42 msgid "search" msgstr "поиск" -#: views.py:41 +#: views.py:43 msgid "maintenance menu" msgstr "меню техобслуживания" -#: views.py:53 +#: views.py:56 msgid "Statistics" msgstr "Статистика" -#: views.py:61 +#: views.py:66 msgid "Diagnostics" msgstr "Диагностика" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or" -" by a menu entry." +"Controls whether the search functionality is provided by a sidebar widget or " +"by a menu entry." msgstr "" "Определяет, будет ли функция поиска обеспечивается виджетом боковой панели " "или пунктом меню." @@ -102,40 +104,40 @@ msgstr "Выход" msgid "Secondary menu" msgstr "Вторичное меню" -#: templates/base.html:302 +#: templates/base.html:301 #, python-format msgid "Actions for %(name)s: %(navigation_object)s" msgstr "Действия для %(name)s: %(navigation_object)s" -#: templates/base.html:304 templates/base.html.py:336 +#: templates/base.html:303 templates/base.html.py:346 #, python-format msgid "Actions for: %(navigation_object)s" msgstr "Действия для: %(navigation_object)s" -#: templates/base.html:307 +#: templates/base.html:306 msgid "Available actions" msgstr "Доступные действия" -#: templates/base.html:319 templates/base.html.py:351 +#: templates/base.html:318 templates/base.html.py:361 msgid "Related actions" msgstr "Связанные действия" -#: templates/base.html:334 +#: templates/base.html:329 templates/base.html.py:374 +msgid "Other available actions" +msgstr "Другие возможные действия" + +#: templates/base.html:344 #, python-format msgid "Actions for %(object_name)s: %(navigation_object)s" msgstr "Действия для %(object_name)s: %(navigation_object)s" -#: templates/base.html:339 +#: templates/base.html:349 msgid "Actions" msgstr "Действия" -#: templates/base.html:364 -msgid "Other available actions" -msgstr "Другие возможные действия" - #: templates/home.html:8 msgid "Django based open source document management system" -msgstr "" +msgstr "Система управления электронными документами на основе Django" #: templates/project_description.html:6 msgid "" @@ -146,8 +148,6 @@ msgstr "" "управления электронными документами с метаданными, индексами, тегами, " "интеграцией с файл-сервером и возможностью оптического распознавания текста." -#: templates/project_description.html:15 +#: templates/project_description.html:18 msgid "Released under the GPL V3 License" msgstr "Выпущено под лицензией GPL V3" - - diff --git a/apps/metadata/locale/en/LC_MESSAGES/django.po b/apps/metadata/locale/en/LC_MESSAGES/django.po index 6f75f44ea8..b4d32bfd59 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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,99 +17,43 @@ 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:315 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:415 msgid "metadata sets" msgstr "" -#: __init__.py:62 models.py:92 +#: __init__.py:39 models.py:93 msgid "default metadata" msgstr "" @@ -150,272 +94,328 @@ msgstr "" 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:352 views.py:397 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:467 views.py:513 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:303 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:581 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:40 views.py:203 msgid "The selected document doesn't have any metadata." msgstr "" -#: views.py:43 views.py:131 views.py:199 +#: views.py:51 views.py:143 views.py:215 msgid "Must provide at least one document." msgstr "" -#: views.py:78 views.py:234 +#: views.py:86 views.py:250 #, python-format msgid "Error deleting document indexes; %s" msgstr "" -#: views.py:90 +#: views.py:98 #, python-format msgid "Error editing metadata for document %(document)s; %(error)s." msgstr "" -#: views.py:93 +#: views.py:101 #, python-format msgid "Metadata for document %s edited successfully." msgstr "" -#: views.py:98 views.py:251 +#: views.py:106 views.py:267 #, python-format msgid "Error updating document indexes; %s" msgstr "" -#: views.py:100 views.py:253 +#: views.py:108 views.py:269 msgid "Document indexes updated successfully." msgstr "" -#: views.py:111 +#: views.py:119 #, python-format msgid "Edit metadata for document: %s" msgstr "" -#: views.py:113 +#: views.py:121 #, python-format msgid "Edit metadata for documents: %s" msgstr "" -#: views.py:148 +#: views.py:160 #, python-format msgid "" "Metadata type: %(metadata_type)s successfully added to document %(document)s." msgstr "" -#: views.py:151 +#: views.py:163 #, python-format msgid "" "Metadata type: %(metadata_type)s already present in document %(document)s." msgstr "" -#: views.py:175 +#: views.py:187 #, python-format msgid "Add metadata type to document: %s" msgstr "" -#: views.py:177 +#: views.py:189 #, python-format msgid "Add metadata type to documents: %s" msgstr "" -#: views.py:242 +#: views.py:258 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " "%(document)s." msgstr "" -#: views.py:245 +#: views.py:261 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." msgstr "" -#: views.py:264 +#: views.py:280 #, python-format msgid "Remove metadata types from document: %s" msgstr "" -#: views.py:266 +#: views.py:282 #, python-format msgid "Remove metadata types from documents: %s" msgstr "" -#: views.py:281 +#: views.py:301 #, python-format msgid "metadata for: %s" msgstr "" -#: views.py:298 +#: views.py:319 msgid "internal name" msgstr "" -#: views.py:319 +#: views.py:340 msgid "Metadata type edited successfully" msgstr "" -#: views.py:322 +#: views.py:343 #, python-format msgid "Error editing metadata type; %s" msgstr "" -#: views.py:328 +#: views.py:349 #, python-format msgid "edit metadata type: %s" msgstr "" -#: views.py:343 +#: views.py:364 msgid "Metadata type created successfully" msgstr "" -#: views.py:349 +#: views.py:370 msgid "create metadata type" msgstr "" -#: views.py:368 +#: views.py:389 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "" -#: views.py:370 +#: views.py:391 #, python-format msgid "Metadata type: %(metadata_type)s delete error: %(error)s" msgstr "" -#: views.py:381 +#: views.py:402 #, python-format msgid "Are you sure you wish to delete the metadata type: %s?" msgstr "" -#: views.py:398 +#: views.py:419 msgid "members" msgstr "" -#: views.py:442 +#: views.py:463 #, python-format msgid "non members of metadata set: %s" msgstr "" -#: views.py:443 +#: views.py:464 #, python-format msgid "members of metadata set: %s" msgstr "" -#: views.py:458 +#: views.py:479 msgid "Metadata set created successfully" msgstr "" -#: views.py:464 +#: views.py:485 msgid "create metadata set" msgstr "" -#: views.py:483 +#: views.py:504 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "" -#: views.py:485 +#: views.py:507 #, python-format msgid "Metadata set: %(metadata_set)s delete error: %(error)s" msgstr "" -#: views.py:496 +#: views.py:518 #, python-format msgid "Are you sure you wish to delete the metadata set: %s?" msgstr "" -#: views.py:554 +#: views.py:576 #, python-format msgid "non members of document type: %s" msgstr "" -#: views.py:555 +#: views.py:577 #, 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 be0c179aa5648cdaf7980ffa5841fe3b6febc78f..e17b35335cdac74c08234c8e7de7f6be8ff864e4 100644 GIT binary patch delta 823 zcmXZaIY`@K7{~FSS86<(Dx{j2))}al9#&5{=Ra`u$C>uuj(VtE z(_sr2&?eT>Xu}v<{{n>_FoRooh~4;tT^Rl-O=1FV-VrY21%}bbDctx8`!J3+Z?D;r zrm1|VBZhyFWT-XxdeRYmM>~n_xQ@197U%E`r?9ex7>r{SPtY!sM;HFZN_@c(mQz^f z!VVSNIEhQRkK_0gt1!eW6&OM0svo(OlIX__cHmdE1D<0YKA@%gH`H=0K~=`LETz97GY4$u}nMLwNV*oOCL@ulo)8FC}9CqH^{2;br~+IkCU8CXW{ zrVV5rN7-UP4(l1XLVJQdTHq7f#%`kRKvA@~&qWu}MSBwoRT}N*Jw}VaMmxYAzQIQ< x$6r{XGU++zbFF)7`y##e1!DuFv7w`^cfylMt*)grsbC_tvy$FOJHfvMueVC~kz>g18YkQt*2)FwEyZ&b{~CGjo%^O7FVi;GjtAib{2o zE}lp=7~<86_2@94!sC!MR4X+wULCui_b^HSJ@(@Y_F^8NVZ@ahv9;h^WJ(j*jX76= z+G!jyU>jecEp+HS$2PR_VP2NtG*00XzQk*6!}wEa0Ef`lt>P!#!vt25#Y5~tA5&=S z<{AU(4UH`ZJp6|gLvH*&Qy(knXYd7nMB6Zjqxc;Mv8YKJ!xVPl2HHjP=-?%m;59bm zf3(WQ1A2CF20!2e_Ted(VvJoP*n+H4J8~&yupXze1((qh+`&rxg;wf6XrDApS;{b0 zFo9Olpo@mxD2^T&MEeAJw7@g8gF{4HLJ73E*9Aw=q5l;L)g;=_yM`8jgqFY$ xe1IodjOQ3pSo*tP=Zu#>@{*pH^!>Q!_4u#WSEKzU*_qkT*@>C#{_m(;c?ZX&RTuyO diff --git a/apps/metadata/locale/es/LC_MESSAGES/django.po b/apps/metadata/locale/es/LC_MESSAGES/django.po index 03f08e5442..395f09a291 100644 --- a/apps/metadata/locale/es/LC_MESSAGES/django.po +++ b/apps/metadata/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-02 14:17-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,99 +18,43 @@ msgstr "" "Content-Transfer-Encoding: 8bit\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:315 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:415 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" @@ -151,42 +95,46 @@ msgstr "Eliminar" 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 " @@ -195,97 +143,149 @@ msgstr "" "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:352 views.py:397 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:467 views.py:513 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:303 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:581 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:40 views.py:203 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:51 views.py:143 views.py:215 msgid "Must provide at least one document." msgstr "Debe proveer al menos un documento." -#: views.py:78 views.py:234 +#: views.py:86 views.py:250 #, python-format msgid "Error deleting document indexes; %s" msgstr "Error eliminando indicies de documento; %s" -#: views.py:90 +#: views.py:98 #, 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:101 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Metadatos para documento %s editados exitosamente." -#: views.py:98 views.py:251 +#: views.py:106 views.py:267 #, python-format msgid "Error updating document indexes; %s" msgstr "Error editando indices de documento; %s" -#: views.py:100 views.py:253 +#: views.py:108 views.py:269 msgid "Document indexes updated successfully." msgstr "Indices documento actualizados exitosamente." -#: views.py:111 +#: views.py:119 #, python-format msgid "Edit metadata for document: %s" msgstr "Editar metadatos para documento: %s" -#: views.py:113 +#: views.py:121 #, python-format msgid "Edit metadata for documents: %s" msgstr "Editar metadatos para documentos: %s" -#: views.py:148 +#: views.py:160 #, python-format msgid "" "Metadata type: %(metadata_type)s successfully added to document %(document)s." @@ -293,7 +293,7 @@ msgstr "" "Typo de metadatos: %(metadata_type)s agregado exitosamente al documento " "%(document)s." -#: views.py:151 +#: views.py:163 #, python-format msgid "" "Metadata type: %(metadata_type)s already present in document %(document)s." @@ -301,17 +301,17 @@ msgstr "" "Typo de metadatos: %(metadata_type)s ya esta presente en el documento " "%(document)s." -#: views.py:175 +#: views.py:187 #, python-format msgid "Add metadata type to document: %s" msgstr "Agregar tipo de metadato al documento: %s" -#: views.py:177 +#: views.py:189 #, python-format msgid "Add metadata type to documents: %s" msgstr "Agregar tipo de metadato a los documentos: %s" -#: views.py:242 +#: views.py:258 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " @@ -320,7 +320,7 @@ msgstr "" "Se elimino exitosamente el tipo de metadatos: %(metadata_type)s del " "documento: %(document)s." -#: views.py:245 +#: views.py:261 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." @@ -328,106 +328,106 @@ msgstr "" "Se elimino exitosamente el tipo de metadatos: %(metadata_type)s de los " "documentos: %(document)s." -#: views.py:264 +#: views.py:280 #, python-format msgid "Remove metadata types from document: %s" msgstr "Eliminar tipos de metadatos del documento: %s" -#: views.py:266 +#: views.py:282 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Eliminar tipos de metadatos de los documentos: %s" -#: views.py:281 +#: views.py:301 #, python-format msgid "metadata for: %s" msgstr "metadatos para: %s" -#: views.py:298 +#: views.py:319 msgid "internal name" msgstr "nombre interno" -#: views.py:319 +#: views.py:340 msgid "Metadata type edited successfully" msgstr "Tipo de metadatos editado exitosamente." -#: views.py:322 +#: views.py:343 #, python-format msgid "Error editing metadata type; %s" msgstr "Error editando tipo de metadatos; %s" -#: views.py:328 +#: views.py:349 #, python-format msgid "edit metadata type: %s" msgstr "editar tipo de metadatos: %s" -#: views.py:343 +#: views.py:364 msgid "Metadata type created successfully" msgstr "Tipo de metadatos creado exitosamente" -#: views.py:349 +#: views.py:370 msgid "create metadata type" msgstr "crear tipo de metadatos" -#: views.py:368 +#: views.py:389 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Tipos de metadatos: %s eliminado exitosamente." -#: views.py:370 +#: views.py:391 #, 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:402 #, 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:419 msgid "members" msgstr "miembros" -#: views.py:442 +#: views.py:463 #, python-format msgid "non members of metadata set: %s" msgstr "no miembros del conjunto de metadatos: %s" -#: views.py:443 +#: views.py:464 #, python-format msgid "members of metadata set: %s" msgstr "miembros del conjunto de metadatos: %s" -#: views.py:458 +#: views.py:479 msgid "Metadata set created successfully" msgstr "Conjunto de metadatos creados exitosamente" -#: views.py:464 +#: views.py:485 msgid "create metadata set" msgstr "crear conjunto de metadatos" -#: views.py:483 +#: views.py:504 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Conjunto de metadatos: %s eliminado exitosamente." -#: views.py:485 +#: views.py:507 #, 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:518 #, 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:576 #, python-format msgid "non members of document type: %s" msgstr "no miembros del tipo de documento: %s" -#: views.py:555 +#: views.py:577 #, python-format msgid "members of document type: %s" msgstr "miembros del tipo de documento: %s" diff --git a/apps/metadata/locale/it/LC_MESSAGES/django.mo b/apps/metadata/locale/it/LC_MESSAGES/django.mo index 828e1eaeac01877cc1a7a0cd295a4da88b8608ed..4dfe2c2d8daec61b8f650e535fbdcbed9a33ff33 100644 GIT binary patch delta 828 zcmXZaO-NKx6u|M*eCdew6rGv0v3chBg)@|8jJiz_;)MvJi-BOu$KXN{R9e1Tq|jy- zLv4Z}B5>1(42h70>C#06E@oj6w#$X!LIzUvf0zr8`Q3BozH{$A_pLhx=X2cetzHtj z6A@_PIaRM{=0^4vKuj6lw<9}nE zppSScE}rx2xhmk{L9mnAC(rX;WMq<~*PmtS_ zm#FnVU=40y6M9<=xK7zaZP5{iv10N*J_PMV8|u6i>Vl)F^Ig;h=S==7`iS3PJ-$Uf zz(?a3w23#7I-dMupoRXSwm!hctIepbN*YH@ej4>k7LCs_K>P|RA+M2U$`)#!1JnZ@ zqi*CBb-uq#V?T?RT0&!1u@H$}zMa0MkKI2o+@C3yBH!wr++2Psmv@KlnZ@FKG+Qc1 GA6ggEjb2g! delta 884 zcmXZaO=uHA6u|Lk6IvUJu}Wi8Qxp58wMn-du}TC%l9P?58bMGH*Amho*|f>#AfkH~ z10ISO1+RLrMJe>+$3YOJ2)(HEAb9AZ>am9+^kDx_2A2K3H#>PV^Cpk;EBV*4fWNj! z64qvWB(A|sf@V_3vfcn?qG8|=s5cmz9QB0Mr; z%;FgNt(f>SO3-3J3$LISUdLhlht!Z^su9Y0tl~}70$)%U{EK;K8*V!If6w7lDLIoj3-3)p@sYL9O?!OcpT^PB0j||{=&T2D+r9~g252(_S5ONqVF=ezf4G6#>OaV#, 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" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2011-12-13 09:10+0000\n" "Last-Translator: Pierpaolo Baldan \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:12 -msgid "Edit a document's metadata" -msgstr "Modifica i metadata dei documenti" - -#: __init__.py:13 -msgid "Add metadata to a document" -msgstr "Aggiungi il metadato al documento" - -#: __init__.py:14 -msgid "Remove metadata from a document" -msgstr "Revoca il metadato al documento" - -#: __init__.py:15 -msgid "View metadata from a document" -msgstr "Visualizza il metadato per il documento" - -#: __init__.py:17 -msgid "Edit metadata types" -msgstr "Modifica il tipo di metadato" - -#: __init__.py:18 -msgid "Create new metadata types" -msgstr "Crea il nuovo tipo di metadato" - -#: __init__.py:19 -msgid "Delete metadata types" -msgstr "Cancella il tipo di metadato" - -#: __init__.py:20 -msgid "View metadata types" -msgstr "Visualizza il tipo di metadato" - -#: __init__.py:22 -msgid "Edit metadata sets" -msgstr "Modifica il set di metadati" - -#: __init__.py:23 -msgid "Create new metadata sets" -msgstr "Crea un nuovo set di metadati" - -#: __init__.py:24 -msgid "Delete metadata sets" -msgstr "Cancella il set dei metadati" - -#: __init__.py:25 -msgid "View metadata sets" -msgstr "Visualizza il set dei metadati" - -#: __init__.py:27 forms.py:94 -msgid "Metadata" -msgstr "Metadati" - -#: __init__.py:33 -msgid "Metadata setup" -msgstr "Setup metadati" - -#: __init__.py:44 __init__.py:46 +#: __init__.py:21 __init__.py:23 msgid "edit metadata" msgstr "modifica metadati" -#: __init__.py:45 +#: __init__.py:22 msgid "metadata" msgstr "metadati" -#: __init__.py:47 __init__.py:48 +#: __init__.py:24 __init__.py:25 msgid "add metadata" msgstr "aggiungi metadata" -#: __init__.py:49 __init__.py:50 +#: __init__.py:26 __init__.py:27 msgid "remove metadata" msgstr "revoca metadata" -#: __init__.py:52 models.py:33 views.py:294 +#: __init__.py:29 models.py:34 views.py:315 msgid "metadata types" msgstr "tipo di metadata" -#: __init__.py:53 __init__.py:58 +#: __init__.py:30 __init__.py:35 msgid "edit" msgstr "modifica" -#: __init__.py:54 __init__.py:59 +#: __init__.py:31 __init__.py:36 msgid "delete" msgstr "cancella" -#: __init__.py:55 __init__.py:60 +#: __init__.py:32 __init__.py:37 msgid "create new" msgstr "crea nuovo" -#: __init__.py:57 views.py:394 +#: __init__.py:34 views.py:415 msgid "metadata sets" msgstr "set di metadati" -#: __init__.py:62 models.py:92 +#: __init__.py:39 models.py:93 msgid "default metadata" msgstr "metadati di default" @@ -151,42 +96,46 @@ msgstr "Revoca" msgid "Metadata sets" msgstr "Set di metadati" -#: models.py:9 +#: 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:10 +#: models.py:11 #, python-format msgid " Available functions: %s" msgstr " Funzioni disponibili: %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 "Non usare parole riservate python, o spazi." -#: models.py:18 models.py:40 +#: models.py:19 models.py:41 msgid "title" msgstr "titolo" -#: models.py:20 +#: models.py:21 msgid "default" msgstr "default" -#: models.py:21 +#: models.py:22 #, python-format msgid "Enter a string to be evaluated.%s" msgstr "Inserisci una stringa per la valutazione.%s" -#: models.py:23 +#: models.py:24 msgid "lookup" msgstr "lookup" -#: models.py:24 +#: models.py:25 #, python-format msgid "" "Enter a string to be evaluated. Example: [user.get_full_name() for user in " @@ -195,124 +144,175 @@ msgstr "" "Inserisci una stringa per la valutazione. Esempio: [user.get_full_name() " "per l'utente User.objects.all()].%s" -#: models.py:32 models.py:57 views.py:331 views.py:376 +#: models.py:33 models.py:58 views.py:352 views.py:397 msgid "metadata type" msgstr "tipo di metadata" -#: 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:467 views.py:513 msgid "metadata set" msgstr "set di metadata" -#: models.py:64 +#: models.py:65 msgid "metadata set item" msgstr "set di elemento per il metadata" -#: models.py:65 +#: models.py:66 msgid "metadata set items" msgstr "set di elementi per il metadata" -#: 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:303 msgid "value" msgstr "valore" -#: models.py:81 models.py:82 +#: models.py:82 models.py:83 msgid "document metadata" msgstr "metadata per il doccumento" -#: models.py:90 views.py:559 +#: models.py:91 views.py:581 msgid "document type" msgstr "tipo documento" -#: models.py:91 +#: models.py:92 msgid "default metadata sets" msgstr "set di default di metadata" -#: models.py:98 +#: models.py:99 msgid "document type defaults" msgstr "tipo documento predefinito" -#: models.py:99 +#: models.py:100 msgid "document types defaults" msgstr "tipi di documento predefiniti" -#: views.py:38 views.py:193 +#: 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:40 views.py:203 msgid "The selected document doesn't have any metadata." msgstr "Il documento selezionato non ha metadati." -#: views.py:43 views.py:131 views.py:199 +#: views.py:51 views.py:143 views.py:215 msgid "Must provide at least one document." msgstr "Devi fornire almeno un documento." -#: views.py:78 views.py:234 +#: views.py:86 views.py:250 #, python-format msgid "Error deleting document indexes; %s" msgstr "Errore nella cancellazione degli indici di documento;%s" -#: views.py:90 +#: views.py:98 #, 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:93 +#: views.py:101 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Metadata per il documento %s modificato con successo." -#: views.py:98 views.py:251 +#: views.py:106 views.py:267 #, python-format msgid "Error updating document indexes; %s" msgstr "Errore nella'ggiornamento degli indici del documento; %s" -#: views.py:100 views.py:253 +#: views.py:108 views.py:269 msgid "Document indexes updated successfully." msgstr "Indici documento aggiornati con successo." -#: views.py:111 +#: views.py:119 #, python-format msgid "Edit metadata for document: %s" msgstr "Modifica metadata per il documento: %s" -#: views.py:113 +#: views.py:121 #, python-format msgid "Edit metadata for documents: %s" msgstr "Modifica metadata per i documenti: %s" -#: views.py:148 +#: views.py:160 #, 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 metadata: %(metadata_type)s aggiunto con successo al documento " "%(document)s." -#: views.py:151 +#: views.py:163 #, 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:175 +#: views.py:187 #, python-format msgid "Add metadata type to document: %s" msgstr "Aggiungi tipo metadata al document: %s" -#: views.py:177 +#: views.py:189 #, python-format msgid "Add metadata type to documents: %s" msgstr "Aggiungi tipo metadata ai documents: %s" -#: views.py:242 +#: views.py:258 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " @@ -321,7 +321,7 @@ msgstr "" "Rimuovere con successo tipo di metadati: %(metadata_type)s per il " "documento: %(document)s." -#: views.py:245 +#: views.py:261 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." @@ -329,105 +329,105 @@ msgstr "" "Errore durante la rimozione dei metadati di tipo: %(metadata_type)s per il " "documento: %(document)s." -#: views.py:264 +#: views.py:280 #, python-format msgid "Remove metadata types from document: %s" msgstr "Rimuovi il tipo metadata per il documento: %s" -#: views.py:266 +#: views.py:282 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Rimuovi il tipo metadata per il documenti: %s" -#: views.py:281 +#: views.py:301 #, python-format msgid "metadata for: %s" msgstr "metadata per:%s" -#: views.py:298 +#: views.py:319 msgid "internal name" msgstr "nome interno" -#: views.py:319 +#: views.py:340 msgid "Metadata type edited successfully" msgstr "Tipo di metadata modificato con successo" -#: views.py:322 +#: views.py:343 #, python-format msgid "Error editing metadata type; %s" msgstr "Errore nella modifica del tipo di metadata ; %s" -#: views.py:328 +#: views.py:349 #, python-format msgid "edit metadata type: %s" msgstr "modifica tipo di metadata: %s" -#: views.py:343 +#: views.py:364 msgid "Metadata type created successfully" msgstr "Tipo metadata creato con successo" -#: views.py:349 +#: views.py:370 msgid "create metadata type" msgstr "create tipo di metadata" -#: views.py:368 +#: views.py:389 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Tipo metadata:%s cancellato con successo." -#: views.py:370 +#: views.py:391 #, 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:381 +#: views.py:402 #, 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:398 +#: views.py:419 msgid "members" msgstr "membri" -#: views.py:442 +#: views.py:463 #, python-format msgid "non members of metadata set: %s" msgstr "non membri del set di metadata:%s" -#: views.py:443 +#: views.py:464 #, python-format msgid "members of metadata set: %s" msgstr "membri del set di metadata:%s" -#: views.py:458 +#: views.py:479 msgid "Metadata set created successfully" msgstr "Set di metadata creata con successo" -#: views.py:464 +#: views.py:485 msgid "create metadata set" msgstr "creazione del set di metadata" -#: views.py:483 +#: views.py:504 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Set di metadata: %s cancellata con successo." -#: views.py:485 +#: views.py:507 #, 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:496 +#: views.py:518 #, 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:554 +#: views.py:576 #, python-format msgid "non members of document type: %s" msgstr "non membri del tipo di documento: %s" -#: views.py:555 +#: views.py:577 #, python-format msgid "members of document type: %s" msgstr "membri del tipo di documento: %s" @@ -453,25 +453,23 @@ 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 " +"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 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 " +"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 " +"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/pt/LC_MESSAGES/django.mo b/apps/metadata/locale/pt/LC_MESSAGES/django.mo index ad93c5f0759515c93d51d4b5a42106085100269d..7d7e1b543c7658a39f12d253094acdcee0201a2f 100644 GIT binary patch delta 26 fcmX@@bJ}M^y(q7dt^o)s7@Alans4qA-7f$DcHRgY delta 26 hcmX@@bJ}M^y(q7tuA!l>k&%L-p_P%@<{r`g0swZ+2p9kW diff --git a/apps/metadata/locale/pt/LC_MESSAGES/django.po b/apps/metadata/locale/pt/LC_MESSAGES/django.po index 4d7805cb79..d7268ae572 100644 --- a/apps/metadata/locale/pt/LC_MESSAGES/django.po +++ b/apps/metadata/locale/pt/LC_MESSAGES/django.po @@ -9,7 +9,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-02 14:17-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/" @@ -20,99 +20,43 @@ msgstr "" "Content-Transfer-Encoding: 8bit\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:315 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:415 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" @@ -153,42 +97,46 @@ msgstr "Remover" 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,97 +145,149 @@ 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:352 views.py:397 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:467 views.py:513 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:303 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:581 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:40 views.py:203 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:51 views.py:143 views.py:215 msgid "Must provide at least one document." msgstr "Deve fornecer pelo menos um documento." -#: views.py:78 views.py:234 +#: views.py:86 views.py:250 #, python-format msgid "Error deleting document indexes; %s" msgstr "Erro ao excluir índices de documento; %s" -#: views.py:90 +#: views.py:98 #, 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:101 #, 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:106 views.py:267 #, python-format msgid "Error updating document indexes; %s" msgstr "Erro ao atualizar índices de documento; %s" -#: views.py:100 views.py:253 +#: views.py:108 views.py:269 msgid "Document indexes updated successfully." msgstr "Índices de documento atualizados com sucesso. " -#: views.py:111 +#: views.py:119 #, python-format msgid "Edit metadata for document: %s" msgstr "Editar os metadados do documento: %s" -#: views.py:113 +#: views.py:121 #, python-format msgid "Edit metadata for documents: %s" msgstr "Editar os metadados do documentos: %s" -#: views.py:148 +#: views.py:160 #, python-format msgid "" "Metadata type: %(metadata_type)s successfully added to document %(document)s." @@ -295,24 +295,24 @@ msgstr "" "Tipo de metadados: %(metadata_type)s adicionado com sucesso para documento " "%(document)s." -#: views.py:151 +#: views.py:163 #, 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 ." -#: views.py:175 +#: views.py:187 #, python-format msgid "Add metadata type to document: %s" msgstr "Adicionar tipo de metadados ao documento: %s" -#: views.py:177 +#: views.py:189 #, python-format msgid "Add metadata type to documents: %s" msgstr "Adicionar tipo de metadados aos documentos: %s" -#: views.py:242 +#: views.py:258 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " @@ -321,7 +321,7 @@ msgstr "" "Tipos de metadados removidos com êxito: %(metadata_type)s do documento: " "%(document)s." -#: views.py:245 +#: views.py:261 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." @@ -329,105 +329,105 @@ msgstr "" "Erro ao remover tipo de metadados: %(metadata_type)s do documento: " "%(document)s." -#: views.py:264 +#: views.py:280 #, python-format msgid "Remove metadata types from document: %s" msgstr "Remover tipos de metadados do documento: %s" -#: views.py:266 +#: views.py:282 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Remover tipos de metadados dos documentos: %s" -#: views.py:281 +#: views.py:301 #, python-format msgid "metadata for: %s" msgstr "metadados para: %s" -#: views.py:298 +#: views.py:319 msgid "internal name" msgstr "nome interno" -#: views.py:319 +#: views.py:340 msgid "Metadata type edited successfully" msgstr "Tipo de metadados editados com sucesso" -#: views.py:322 +#: views.py:343 #, python-format msgid "Error editing metadata type; %s" msgstr "Erro de edição de tipo de metadados; %s" -#: views.py:328 +#: views.py:349 #, python-format msgid "edit metadata type: %s" msgstr "editar tipo de metadados: %s" -#: views.py:343 +#: views.py:364 msgid "Metadata type created successfully" msgstr "Tipo de metadados criado com sucesso" -#: views.py:349 +#: views.py:370 msgid "create metadata type" msgstr "criar um tipo de metadados" -#: views.py:368 +#: views.py:389 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Tipo de metadados: %s removido com sucesso." -#: views.py:370 +#: views.py:391 #, 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:402 #, 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:419 msgid "members" msgstr "membros" -#: views.py:442 +#: views.py:463 #, python-format msgid "non members of metadata set: %s" msgstr "não-membros do conjunto de metadados: %s" -#: views.py:443 +#: views.py:464 #, python-format msgid "members of metadata set: %s" msgstr "membros do conjunto de metadados: %s" -#: views.py:458 +#: views.py:479 msgid "Metadata set created successfully" msgstr "Conjunto de metadados criado com sucesso" -#: views.py:464 +#: views.py:485 msgid "create metadata set" msgstr "criar um conjunto de metadados" -#: views.py:483 +#: views.py:504 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Conjunto de metadados: %s removido com sucesso." -#: views.py:485 +#: views.py:507 #, 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:518 #, 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:576 #, python-format msgid "non members of document type: %s" msgstr "não membros do tipo de documento: %s" -#: views.py:555 +#: views.py:577 #, python-format msgid "members of document type: %s" msgstr "membros do tipo de documento: %s" diff --git a/apps/metadata/locale/ru/LC_MESSAGES/django.mo b/apps/metadata/locale/ru/LC_MESSAGES/django.mo index d58dc848fd64c11ba39f8b83d3474a2a83aa8590..0984aefc046b59605366b9c1772bae880d2f7ce3 100644 GIT binary patch delta 820 zcmXZaPe@cz6vy$O4oo8bLmX|?bW+QIy>y&Or%|(o=E#J9CAz|;V!mfq)HmVGZL=JAzn7{elbgZ20kt@1CJjUMN0 zLoensE=OC}!6v+qAv?`9ft}47at*X~?hmwz{-JGHPdRop!)TSvBlk_KXf57CyKH-C zcO{FgICe$RDt?BRz$DuLXaA2q(!z${`{K%_MyJ7^KrkE)HZOkgwO@QZGBrB#I?(kp MnR>pF@$LFg0SBI87ytkO delta 813 zcmXZa%}bO~6vy$O4!SVZjD{F39n;2_9P`fDjQMVirP!iCtaPCaVp1UtX&YZ2sI3w) zxX`6LX_4SUp~xUyMD1J%iv0oNMks^|^m|ko=5y|Sp68x>&b^C+>A{t&K5r*Oiu$D+ zlJc%dWmu2h_ynhUzJv!pDHxFMFrRzv?D>7{Vf-G4a1VR2wODGyG&bQD)?}hgf;lGoYndX7MO7O8(C8!+EIyJScEBz;~ZKCHZh6E_!N^NX&gUeGr9_?563VY zH!%-?VhiqK7Y01CSdhdC{D9W_(kkg9zBqRZ?ZY{=R{lV1rK+U}IJEIFvM0@BEq+3N z+UL&-@!ym#p+oC{mmsjpQfNC|MoYYoY*OEmW7i?x#tVF92|KV5$MF`vL#uoPGx0xK z!eh+AqVU\n" +"Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" "ru/)\n" "Language: ru\n" @@ -20,99 +20,43 @@ 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: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:315 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:415 msgid "metadata sets" msgstr "наборы метаданных" -#: __init__.py:62 models.py:92 +#: __init__.py:39 models.py:93 msgid "default metadata" msgstr "метаданные по умолчанию" @@ -153,42 +97,46 @@ msgstr "Удалить" 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 " @@ -197,121 +145,173 @@ 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:352 views.py:397 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:467 views.py:513 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:303 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:581 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:40 views.py:203 msgid "The selected document doesn't have any metadata." msgstr "Выбранный документ не имеет метаданных." -#: views.py:43 views.py:131 views.py:199 +#: views.py:51 views.py:143 views.py:215 msgid "Must provide at least one document." msgstr "Необходимо предоставить хотя бы один документ." -#: views.py:78 views.py:234 +#: views.py:86 views.py:250 #, python-format msgid "Error deleting document indexes; %s" msgstr "Ошибка при удалении индексов документа; %s" -#: views.py:90 +#: views.py:98 #, python-format msgid "Error editing metadata for document %(document)s; %(error)s." msgstr "" "Ошибка редактирования метаданных для документа %(document)s; %(error)s." -#: views.py:93 +#: views.py:101 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Метаданные для документов %s изменены." -#: views.py:98 views.py:251 +#: views.py:106 views.py:267 #, python-format msgid "Error updating document indexes; %s" msgstr "Ошибка при обновлении индексов документа; %s" -#: views.py:100 views.py:253 +#: views.py:108 views.py:269 msgid "Document indexes updated successfully." msgstr "Индексы документа успешно обновлены." -#: views.py:111 +#: views.py:119 #, python-format msgid "Edit metadata for document: %s" msgstr "Редактировать метаданные документа:%s." -#: views.py:113 +#: views.py:121 #, python-format msgid "Edit metadata for documents: %s" msgstr "Редактирование метаданных для документов: %s" -#: views.py:148 +#: views.py:160 #, python-format msgid "" "Metadata type: %(metadata_type)s successfully added to document %(document)s." msgstr "" "Тип метаданных: %(metadata_type)s успешно добавлены к документу %(document)s." -#: views.py:151 +#: views.py:163 #, 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:187 #, python-format msgid "Add metadata type to document: %s" msgstr "Добавить метаданные типа к документу: %s." -#: views.py:177 +#: views.py:189 #, python-format msgid "Add metadata type to documents: %s" msgstr "Добавляйте метаданные типа документов: %s" -#: views.py:242 +#: views.py:258 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " @@ -320,7 +320,7 @@ msgstr "" "Метаданные типа: %(metadata_type)s успешно удалены из документа: " "%(document)s." -#: views.py:245 +#: views.py:261 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." @@ -328,105 +328,105 @@ msgstr "" "Ошибка удаления метаданных, наберите:%(metadata_type)s из документа: " "%(document)s ." -#: views.py:264 +#: views.py:280 #, python-format msgid "Remove metadata types from document: %s" msgstr "Удалить типы метаданных из документа: %s" -#: views.py:266 +#: views.py:282 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Удалить типы метаданных из документа: %s" -#: views.py:281 +#: views.py:301 #, python-format msgid "metadata for: %s" msgstr "метаданных для: %s" -#: views.py:298 +#: views.py:319 msgid "internal name" msgstr "внутреннее имя" -#: views.py:319 +#: views.py:340 msgid "Metadata type edited successfully" msgstr "Тип метаданных отредактирован." -#: views.py:322 +#: views.py:343 #, python-format msgid "Error editing metadata type; %s" msgstr "Ошибка редактирования типа метаданных; %s" -#: views.py:328 +#: views.py:349 #, python-format msgid "edit metadata type: %s" msgstr "редактировать метаданные типа: %s" -#: views.py:343 +#: views.py:364 msgid "Metadata type created successfully" msgstr "Тип метаданных успешно создан" -#: views.py:349 +#: views.py:370 msgid "create metadata type" msgstr "создать тип метаданных" -#: views.py:368 +#: views.py:389 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Тип метаданных: %s успешно удален." -#: views.py:370 +#: views.py:391 #, python-format msgid "Metadata type: %(metadata_type)s delete error: %(error)s" msgstr "Метаданные типа: %(metadata_type)s ошибка удаления: %(error)s" -#: views.py:381 +#: views.py:402 #, python-format msgid "Are you sure you wish to delete the metadata type: %s?" msgstr "Вы действительно хотите удалить метаданные:%s?" -#: views.py:398 +#: views.py:419 msgid "members" msgstr "элементы" -#: views.py:442 +#: views.py:463 #, python-format msgid "non members of metadata set: %s" msgstr "не входят в набор метаданных: %s" -#: views.py:443 +#: views.py:464 #, python-format msgid "members of metadata set: %s" msgstr "входят в набор метаданных: %s" -#: views.py:458 +#: views.py:479 msgid "Metadata set created successfully" msgstr "Набор метаданных создан" -#: views.py:464 +#: views.py:485 msgid "create metadata set" msgstr "создать набор метаданных" -#: views.py:483 +#: views.py:504 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Набор метаданных: %s удалён." -#: views.py:485 +#: views.py:507 #, python-format msgid "Metadata set: %(metadata_set)s delete error: %(error)s" msgstr "Набор метаданных: %(metadata_set)s ошибка удаления: %(error)s" -#: views.py:496 +#: views.py:518 #, python-format msgid "Are you sure you wish to delete the metadata set: %s?" msgstr "Вы действительно хотите удалить набор метаданных: %s?" -#: views.py:554 +#: views.py:576 #, python-format msgid "non members of document type: %s" msgstr "не относится к типу документа: %s." -#: views.py:555 +#: views.py:577 #, python-format msgid "members of document type: %s" msgstr "относится к типу документа: %s." diff --git a/apps/navigation/locale/en/LC_MESSAGES/django.po b/apps/navigation/locale/en/LC_MESSAGES/django.po index 073df2fae0..8c2565fd8b 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-02 14:17-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 60911107089abd56734915f298f9673a6febe42c..0b9200fe378ac5ccec6b7631a3ed2b5bbe7424c5 100644 GIT binary patch delta 77 zcmZ3+x|VfbQpaG<7fHXUhUOF*y60ec20SGA=nphc{PyAue ZAC#YzT2zv+5R_k>Sd^K+*`6_-5ddW!5`O>y delta 70 zcmZ3>x{P&#jqDai28Q_z3=9fD9KyuFpaG;yfiydio;NXa60f1Ip`oskk%FP2m66%R UANCwY`NfGvnfXPV-5Apu0p-LG_5c6? diff --git a/apps/navigation/locale/es/LC_MESSAGES/django.po b/apps/navigation/locale/es/LC_MESSAGES/django.po index 4fa778b876..571dfa9788 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-02 14:17-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 index e67720c602dad5c509c2c9a35b6b9578ad7753f9..f83dfbbf5e6dce47bca0cb45d79aa338089c8276 100644 GIT binary patch delta 101 zcmZ3*+RQq^Ms@`w1H*g<1_lWr_F!UQkO9((K$-UBx=VM)o`-1H*g<1_lWr&Szp^kO9&iK$-ty diff --git a/apps/navigation/locale/it/LC_MESSAGES/django.po b/apps/navigation/locale/it/LC_MESSAGES/django.po index 764528c927..2745af0b09 100644 --- a/apps/navigation/locale/it/LC_MESSAGES/django.po +++ b/apps/navigation/locale/it/LC_MESSAGES/django.po @@ -1,33 +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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: forms.py:14 msgid "Multi item action" msgstr "Voce per azioni multiple" -#: widgets.py:28 +#: widgets.py:48 msgid "icon" msgstr "icon" -#: templatetags/navigation_tags.py:275 +#: templatetags/navigation_tags.py:278 msgid "Selected item actions:" msgstr "Selezione le azioni multiple" - - diff --git a/apps/navigation/locale/pt/LC_MESSAGES/django.mo b/apps/navigation/locale/pt/LC_MESSAGES/django.mo index da6beaf7eac91e13685d19208d8f9085b7bdde31..1ab3336d64afb5cbba1efe23d67d02c1c919097c 100644 GIT binary patch delta 24 dcmZo*ZD5`7n%79z0E83_O{@&fH~#2g1OQhN2Rr}( delta 24 fcmZo*ZD5`7n%7X*&`{UNNWsw1%E)Zvj}ArvR{{q* diff --git a/apps/navigation/locale/pt/LC_MESSAGES/django.po b/apps/navigation/locale/pt/LC_MESSAGES/django.po index 7f003b944a..36ef8d41f7 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-02 14:17-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 8dec51de246ac087c61aa9554f23ac9a09a948d4..cd3ec3919abe5b4aaf74ddbc315108798d17fc13 100644 GIT binary patch delta 74 zcmaFL`i6CajqF2428Q_z3=E1u+{nbhU=5@f18E*0eSc!)Bwiz30}xU$G_f)?pZLR` WCpfhzJ+)H7JtwmyakCBMN=5*7o)V(~ delta 67 zcmaFE`jmBojqEK(28Q_z3=E1uT*bt|U=5__0BIf|ePd$eBwj;ZLqlC7BLzc4D\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/ocr/locale/en/LC_MESSAGES/django.po b/apps/ocr/locale/en/LC_MESSAGES/django.po index 8aa482cb75..ca083755a5 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-02 14:17-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:31 __init__.py:32 msgid "submit to OCR queue" msgstr "" -#: __init__.py:45 __init__.py:46 +#: __init__.py:33 __init__.py:34 msgid "re-queue" msgstr "" -#: __init__.py:47 __init__.py:48 __init__.py:63 +#: __init__.py:35 __init__.py:36 __init__.py:49 msgid "delete" msgstr "" -#: __init__.py:50 +#: __init__.py:38 msgid "stop queue" msgstr "" -#: __init__.py:51 +#: __init__.py:39 msgid "activate queue" msgstr "" -#: __init__.py:53 +#: __init__.py:41 msgid "clean up pages content" msgstr "" -#: __init__.py:53 +#: __init__.py:41 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." msgstr "" -#: __init__.py:55 +#: __init__.py:43 msgid "queue document list" msgstr "" -#: __init__.py:58 views.py:316 -msgid "active tasks" +#: __init__.py:44 __init__.py:62 permissions.py:7 +msgid "OCR" msgstr "" -#: __init__.py:60 +#: __init__.py:46 msgid "transformations" msgstr "" -#: __init__.py:61 +#: __init__.py:47 msgid "add transformation" msgstr "" -#: __init__.py:62 +#: __init__.py:48 msgid "edit" msgstr "" -#: __init__.py:82 +#: __init__.py:69 msgid "Default" msgstr "" -#: __init__.py:104 +#: __init__.py:97 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 9c4c0ed1f323144ece5addd8bdeb76a5afc85810..4a3d4d8b4fe6ae5f1dcdc5ebd818a9b6a8a155eb 100644 GIT binary patch delta 2168 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 WAf=m_AS~u09-oxSrqxCEsxJUZvkH^| diff --git a/apps/ocr/locale/es/LC_MESSAGES/django.po b/apps/ocr/locale/es/LC_MESSAGES/django.po index 6905387d1e..f6ea7bf693 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. 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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:19+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:31 __init__.py:32 msgid "submit to OCR queue" msgstr "enviar a lista de OCR" -#: __init__.py:45 __init__.py:46 +#: __init__.py:33 __init__.py:34 msgid "re-queue" msgstr "volver a la cola" -#: __init__.py:47 __init__.py:48 __init__.py:63 +#: __init__.py:35 __init__.py:36 __init__.py:49 msgid "delete" msgstr "eliminar" -#: __init__.py:50 +#: __init__.py:38 msgid "stop queue" msgstr "detener cola" -#: __init__.py:51 +#: __init__.py:39 msgid "activate queue" msgstr "activar cola" -#: __init__.py:53 +#: __init__.py:41 msgid "clean up pages content" msgstr "limpiar el contenido" -#: __init__.py:53 +#: __init__.py:41 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:43 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:44 __init__.py:62 permissions.py:7 +msgid "OCR" +msgstr "OCR" -#: __init__.py:60 +#: __init__.py:46 msgid "transformations" msgstr "transformaciones" -#: __init__.py:61 +#: __init__.py:47 msgid "add transformation" msgstr "añadir transformación" -#: __init__.py:62 +#: __init__.py:48 msgid "edit" msgstr "editar" -#: __init__.py:82 +#: __init__.py:69 msgid "Default" msgstr "Por defecto" -#: __init__.py:104 +#: __init__.py:97 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 "" + +#: 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 "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 index 2719e242b38c46364bc5a9b796189881a86bc98f..c7381f6c7ebd72ad27460ff6ceb0f5cd37bdfd2a 100644 GIT binary patch delta 2132 zcmZwITWnNC9LMqhww2ycy6qNnqIsIEXyM#&A8RunA{8UF1gl(ffOOrP&7B zVbpa=tidB*`vh*GeGcPz9s99orCEnw^$?XcbezEeeu0|M52%@!+-%l@9oT>qcn7|W zefS<~;=iFLu!P09;TALg*+zci*oAHQ9O}9cuvtreiONQ_RfP#O;X^e0P!l_WjA`$p zmhfZb7Q2coa0#o?S7la?0bGqi)Jk-C{R!0d!^ke#qnOh`Pf%HlS=5`&Vi4a)#cjy1t6Uhw9-IlV{;GUV#{>8m zD!T`33)y`XyJ(-qop=pfv5V!<9_~kN-K(fAIER|(*LW9R!WO)N?byuhn(=Xr;!KW; z2Koeb;V;OfEl^iTmIh4F9>oEiLrvrg#xcUa-HOk6&f+H8r*SJ@#BEs1MIHDE*5h#; z!Q4C*EnVqtg^8>|W$#v0{{Y5u1U0}()Ej(-n(!iONgMchuy{6sqj(5eEW3!>qARHD zu6ylH5{<3S*#H$@+J;bjI)OU(Y1DwPAxG9uqjJPWUH2(!$uHnKTtIyX{`3rz!CJ}f zsELfA?tcoEW7Al!^Zz^*W%V)CF?-3o;0>>R3bhg+q8|7e^3wK=*Zv(f@ZYG3l`$J7 zZ#C-8>rgq-i0p>7qOMEG9F<`zdcYWxC-yXwy!ixq7?+FoQDq0ArC%;ut>wZT@`Z0# z{-mf8Cc215qKHtryMW%mP&A|eD?R_|)Z{|MZbB=iqU_gOsgRTT)1yRHxtCBfvLpE| zjH6aUtF6Kb$>o<$jm^Xmp_NeP-bw5sdI@E$l1>SzJyu?53)%?s*MY9?7eW~npCX~!fjb|q_q0QMsM@zQQ(Xv02K0JOPb=X}9yi@G_T92Fk37{~F`7KCC;Y0-j|Zxwk%DC_D2u3fW-jH*%-mt-j-m-n z+!A?(IBtn=T*3<%VxTHf6BUe+5EIc54Zcw05{*kt)VRG+zrUGV)c6m0;F-_4%bfK& z)4P`)SyA|?Vbp_$5+kM(^Q(-x3%k$bgR*k0F%I_QW%vv(#!qkoUQ}JaKY;yQ--){a zHnyV~XG{llpuX>*#fNZ)F$HssN`xC9;5@88-7gufVgY2~4gl58zT{am_|#am;2MPyZ%Hr3ZIo6px}t`~_Z$brTpI zcA*9m$Mv`eHNaD$pCV&4zvCk~mfp4Gk0WC-@1u703uMmbTP!qC`HhN3RKrChHlmiQ z6?MNC^~Kf5wwn#82Djlwcr$9|cjI(?0vWqGj%x2+9ED%uX#6hp#|GA44}J?@_yg5p z6}{`lTGZZ8MAE}Fp*o(8{5K2vP)Gf!fo(xOkD&&<8`aJp)c5zH+S`x(HwP!O{SXEq6WMkdvPx=$JbD& zsFK8J#>Kb^x1m<_2r`g@IZj2#;v3Y=z7JohB$Il$Za_6Oh?>cM)X1O5rT7`@RLq>g z{$nR{%iM?Tj(HBXm2cuBcn0;ol-2zLzi3pHEH9UCu;<9GnA2E|U!i_*en559IMWz@ zYs@@U(k(*0*MpkCDx?py9rXjWH}nbAO235~*jXG)|K@ut8o;lphWE6JAbQ?yT+GV0Y); zyleXOe2*K?2j?EdlP)*&8SAI5lT6x#AJ3=UbYL^iQ1Peg>{K`D^7gsgJN)e54Gt&9 zova!?=mz=BaLahFV$xtfmhyuCyj?s{H>a?n-+E~q>~t+{q`GW#%1ymfo{5C%(%~C-f+vD>Y-2etegg9%{1#`DEZ_ znD9vdf)hf`N5sM((u5N_U1&G#sibtn+g@-#P(9akAwd z4C^+ZW)1v=V>51P`OUig8%M31bBFR?*5z?&PqJPnpJai28{`8vjn!Zmy)@hB{=Kul z>GRV;)=wrK>z&&w&ldMKZk|hq#9f}y=s%w&NR5AwVE9bq?ooBLw8I<9XPw(UpKgYG zo9?feKIjL5pYgM_F_Jc3Y2e8gQnC2n)RzBmF8ng}+S<~hGyPIF46mNnTTz+ti~FY+ h>iwZ1m$|VOOpf&Mi(_W=O$gH>?Wf8aR9rcu`!6H8<&yva diff --git a/apps/ocr/locale/it/LC_MESSAGES/django.po b/apps/ocr/locale/it/LC_MESSAGES/django.po index 799dd966d3..c15bfb6d6d 100644 --- a/apps/ocr/locale/it/LC_MESSAGES/django.po +++ b/apps/ocr/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-09 16:09+0000\n" -"Last-Translator: Pierpaolo Baldan \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,59 +18,31 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:28 -msgid "Submit document for OCR" -msgstr "Sottoporre documenti per l'OCR" - -#: __init__.py:29 -msgid "Delete document for OCR queue" -msgstr "Cancellare i documenti dalla coda per OCR" - -#: __init__.py:30 -msgid "Can enable/disable an OCR queue" -msgstr "Posso attivare/disattivare una coda per OCR" - -#: __init__.py:31 -msgid "Can execute an OCR clean up on all document pages" -msgstr "Può eseguire un OCR ripulendo tutte le pagine del documento" - -#: __init__.py:32 -msgid "Can edit an OCR queue properties" -msgstr "Posso modificare le proprità della coda di OCR" - -#: __init__.py:34 __init__.py:56 __init__.py:74 -msgid "OCR" -msgstr "OCR" - -#: __init__.py:40 -msgid "OCR Setup" -msgstr "Configurazione OCR" - -#: __init__.py:44 +#: __init__.py:31 __init__.py:32 msgid "submit to OCR queue" msgstr "Sottoponi una coda di OCR" -#: __init__.py:45 __init__.py:46 +#: __init__.py:33 __init__.py:34 msgid "re-queue" msgstr "riaccoda" -#: __init__.py:47 __init__.py:48 __init__.py:63 +#: __init__.py:35 __init__.py:36 __init__.py:49 msgid "delete" msgstr "cancella" -#: __init__.py:50 +#: __init__.py:38 msgid "stop queue" msgstr "stoppa la coda" -#: __init__.py:51 +#: __init__.py:39 msgid "activate queue" msgstr "attiva la coda" -#: __init__.py:53 +#: __init__.py:41 msgid "clean up pages content" msgstr "ripulisci il contenuto delle pagine" -#: __init__.py:53 +#: __init__.py:41 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -78,35 +50,35 @@ msgstr "" "Esegue un filtro per rimuovere i comuni errori di OCR dal contenuto del " "documento pagine." -#: __init__.py:55 +#: __init__.py:43 msgid "queue document list" msgstr "lista dei documenti in coda" -#: __init__.py:58 views.py:316 -msgid "active tasks" -msgstr "attiva i tasks" +#: __init__.py:44 __init__.py:62 permissions.py:7 +msgid "OCR" +msgstr "OCR" -#: __init__.py:60 +#: __init__.py:46 msgid "transformations" msgstr "transformazioni" -#: __init__.py:61 +#: __init__.py:47 msgid "add transformation" msgstr "aggiungi trasformazione" -#: __init__.py:62 +#: __init__.py:48 msgid "edit" msgstr "modifica" -#: __init__.py:82 +#: __init__.py:69 msgid "Default" msgstr "Default" -#: __init__.py:104 +#: __init__.py:97 msgid "Checks the OCR queue for pending documents." msgstr "Controlla i documenti nella coda dell'OCR" -#: api.py:119 +#: api.py:122 msgid "Text from OCR" msgstr "testo dall'OCR" @@ -130,88 +102,108 @@ msgstr "in elaborazione" msgid "error" msgstr "errore" -#: models.py:22 +#: models.py:26 msgid "name" msgstr "nome" -#: models.py:23 +#: models.py:27 msgid "label" msgstr "etichetta" -#: models.py:27 models.py:47 +#: models.py:31 models.py:51 msgid "state" msgstr "stato" -#: 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 "coda del documento" -#: models.py:33 +#: models.py:37 msgid "document queues" msgstr "code di documenti" -#: models.py:41 +#: models.py:45 msgid "document" msgstr "documento" -#: models.py:42 +#: models.py:46 msgid "date time submitted" msgstr "orario di esecuzione" -#: models.py:43 +#: models.py:47 msgid "delay ocr" msgstr "proroga ocr" -#: models.py:48 +#: models.py:52 msgid "result" msgstr "risultato" -#: models.py:49 +#: models.py:53 msgid "node name" msgstr "nome del nodo" -#: models.py:53 +#: models.py:57 msgid "queue document" msgstr "coda del documento" -#: models.py:54 +#: models.py:58 msgid "queue documents" msgstr "code dei documenti" -#: models.py:63 views.py:48 +#: models.py:78 views.py:49 msgid "Missing document." msgstr "Documento perso" -#: models.py:67 +#: models.py:82 msgid "Enter a valid value." msgstr "Inserisci un valore valido" -#: models.py:95 views.py:341 +#: models.py:110 views.py:319 msgid "order" msgstr "ordina" -#: 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 "trasforma" -#: models.py:97 views.py:343 +#: models.py:112 views.py:321 msgid "arguments" msgstr "argomenti" -#: models.py:97 +#: 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:107 +#: models.py:122 msgid "document queue transformation" msgstr "coda del documento in trasformazione" -#: models.py:108 +#: 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" @@ -226,181 +218,165 @@ msgstr "Code di documenti:%d" msgid "OCR statistics" msgstr "Statistiche OCR" -#: views.py:41 +#: views.py:42 #, python-format msgid "documents in queue: %s" msgstr "documenti in coda: %s" -#: views.py:49 +#: views.py:50 msgid "thumbnail" msgstr "thumbnail" -#: views.py:62 +#: views.py:63 msgid "document queue properties" msgstr "proprietà della coda documenti" -#: views.py:63 +#: views.py:64 #, python-format msgid "Current state: %s" msgstr "Stato corrente: %s" -#: views.py:79 views.py:154 +#: views.py:80 views.py:168 msgid "Must provide at least one queue document." msgstr "Deve fornire almeno un documento di coda." -#: views.py:89 +#: 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:92 +#: views.py:93 #, python-format msgid "Queue document: %(document)s deleted successfully." msgstr "Coda documento: %(document)s cancellata con successo." -#: views.py:96 +#: 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:109 +#: 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:111 +#: 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:134 +#: 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:137 +#: views.py:151 #, python-format msgid "Document: %(document)s is already queued." msgstr "Il documento: %(document)s è gia stato elaborato." -#: views.py:165 -#, 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:173 +#: 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:176 +#: views.py:186 #, python-format msgid "Document id#: %d, no longer exists." msgstr "il documento id#: %d,non esiste più." -#: views.py:189 +#: 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:191 +#: 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:209 +#: views.py:222 #, python-format msgid "Document queue: %s, already stopped." msgstr "Questa coda: %s, è stata appena fermata." -#: views.py:215 +#: views.py:228 #, python-format msgid "Document queue: %s, stopped successfully." msgstr "Questa coda: %s,è stata fermata con successo." -#: views.py:221 +#: 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:236 +#: views.py:249 #, python-format msgid "Document queue: %s, already active." msgstr "La coda per questo documento: %s, è già attiva." -#: views.py:242 +#: views.py:255 #, python-format msgid "Document queue: %s, activated successfully." msgstr "Coda documento: %s, attivata con successo." -#: views.py:248 +#: 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:265 +#: 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:266 +#: 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:272 +#: views.py:285 msgid "Document pages content clean up complete." msgstr "Pulizia del contenuto delle pagine completata." -#: views.py:274 +#: views.py:287 #, python-format msgid "Document pages content clean up error: %s" msgstr "Errore nella pulizia del contenuto delle pagine: %s" -#: views.py:320 -msgid "node" -msgstr "nodo" - -#: views.py:321 -msgid "task id" -msgstr "task id" - -#: views.py:322 -msgid "task name" -msgstr "nome task" - -#: views.py:323 -msgid "related object" -msgstr "oggetto correlato" - -#: views.py:335 +#: views.py:313 #, python-format msgid "transformations for: %s" msgstr "trasformazione per: %s" -#: views.py:365 +#: views.py:343 msgid "Queue transformation edited successfully" msgstr "Modifica della coda di trasformazione effettuata con successo" -#: views.py:368 +#: views.py:346 #, python-format msgid "Error editing queue transformation; %s" msgstr "Errore nella modifica alla coda di trasformazione; %s" -#: views.py:373 +#: views.py:351 #, python-format msgid "Edit transformation: %s" msgstr "Modifica trasformazioni:%s" -#: views.py:396 +#: views.py:374 msgid "Queue transformation deleted successfully." msgstr "Coda di trasformazione cancellata con successo" -#: views.py:398 +#: views.py:376 #, python-format msgid "Error deleting queue transformation; %(error)s" msgstr "Errore nella cancellazione della coda di trasformazione; %(error)s" -#: views.py:411 +#: views.py:389 #, python-format msgid "" "Are you sure you wish to delete queue transformation \"%(transformation)s\"" @@ -408,16 +384,16 @@ msgstr "" "Sei sicuro di voler cancellare la coda di trasformazione " "\"%(transformation)s\"" -#: views.py:434 +#: views.py:412 msgid "Queue transformation created successfully" msgstr "Coda di trasformazione creata con successo" -#: views.py:437 +#: views.py:415 #, python-format msgid "Error creating queue transformation; %s" msgstr "Errore creano la coda di trasformazione; %s" -#: views.py:446 +#: views.py:424 #, python-format msgid "Create new transformation for queue: %s" msgstr "Crea una nuova coda di trasformazione:%s" @@ -442,20 +418,10 @@ msgstr "" "Automaticamente crea una coda appena si sottomone un documento ad 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 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." - -#: conf/settings.py:18 msgid "File path to unpaper program." msgstr "File path per il programma unpaper" -#: parsers/__init__.py:23 +#: parsers/__init__.py:37 msgid "Text extracted from PDF" msgstr "Testo estratto da PDF" diff --git a/apps/ocr/locale/pt/LC_MESSAGES/django.mo b/apps/ocr/locale/pt/LC_MESSAGES/django.mo index 065b53a37a79dc7a50404f46ef3bcfac4a19668d..f1ddf70ec16c48ce2224a3d5049e0b1494f291ac 100644 GIT binary patch delta 2193 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 GiT?n, 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-02 05:10+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-02 14:17-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" "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: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:31 __init__.py:32 msgid "submit to OCR queue" msgstr "submeter à lista de OCR" -#: __init__.py:45 __init__.py:46 +#: __init__.py:33 __init__.py:34 msgid "re-queue" msgstr "re-enfileirar" -#: __init__.py:47 __init__.py:48 __init__.py:63 +#: __init__.py:35 __init__.py:36 __init__.py:49 msgid "delete" msgstr "excluir" -#: __init__.py:50 +#: __init__.py:38 msgid "stop queue" msgstr "parar lista" -#: __init__.py:51 +#: __init__.py:39 msgid "activate queue" msgstr "ativar lista" -#: __init__.py:53 +#: __init__.py:41 msgid "clean up pages content" msgstr "limpar conteúdo das páginas" -#: __init__.py:53 +#: __init__.py:41 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -80,35 +51,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:43 msgid "queue document list" msgstr "lista de documentos da fila" -#: __init__.py:58 views.py:316 -msgid "active tasks" -msgstr "tarefas ativas" +#: __init__.py:44 __init__.py:62 permissions.py:7 +msgid "OCR" +msgstr "OCR" -#: __init__.py:60 +#: __init__.py:46 msgid "transformations" msgstr "transformações" -#: __init__.py:61 +#: __init__.py:47 msgid "add transformation" msgstr "adicionar transformação" -#: __init__.py:62 +#: __init__.py:48 msgid "edit" msgstr "editar" -#: __init__.py:82 +#: __init__.py:69 msgid "Default" msgstr "Padrão" -#: __init__.py:104 +#: __init__.py:97 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 +103,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,199 +219,184 @@ 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." +"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\"" msgstr "" -"Tem certeza que deseja deletar a transformação de lista \"%(transformation)s" -"\"" +"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,11 @@ 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 2532ba2c7164c9eaf4f97d0b18b5aa6f07839578..ca6858dc7152d7801977c9fb74fa48311fe51c4a 100644 GIT binary patch delta 2204 zcmZA2TWnNC9LMp0FZ5n%=>?%JE>dV~*=`He(iKWkYNf4UOQiu@iS*CDcN33XrK`)%P@+1veUQ%KSsv3Yp4Nl zVkZ8DN{@S<54`>~wm}QXLVaI^I?8h7v}^@xzB<&xHWsu0nxKact!NOn!Z2!p3Dk{I z)Ii5jH@=0M=mXS%GpKPsMeW#C^pVK7@H5&ExM>1E;e5kbRc1Df$IICNeN=v@<0y9X zm}B@ozK%_db_mboNnH83*=u+a_hSLu){8Mz5`Kd^ia)R&AL1TtTh7Db`?wSDp^~yA zQDN3eizA(cWpd3e1am6xe)Cbkotggs9zBAy{sG6>~MnHrQf zV!c~S9pe_SzQA)-x``LO4&|1Le%Ojj`A|~nT~+cZv34Xoa$@ODUjAhAZ2q?y$^DD> zr8&P9)i~#hyOZ<9IcZLI$&eE(S?_#RGF3Acj~@&M0;A*cv8myPk;s8SG!hF%$0O0e zfzaX5WMDiNn+nGqf9cY~b^b>E`I~v;pFC~+8d(xe@-b_*GHgiG|;p(Ny{Vc#$>`(rEH&=_Kf3C5O9Li_%% zP1k9E>?FsZbM8Iw$IW!kA4&bTbm>!y5Fl0)>z61siaT!Lhp=~( zl?B=79oSBO1m*cWHlZq1$_rkU`UYzJ9fdug&4xtS2mpOlrj8Xj)pT=eME=&FbG8Xj?%C5eL%vpVisZtUP zBxFP$GOKVE%2G9;Jii^K;yuW=t4@>#d$1B8Mw$7exCUQD#;)E(Y0tr>_&(<0Uvhp@ z%KFQTgTDV7FArWOCmp|*a~7qcH&HsUQI`5D{$`O<|G@L)-(IOy1fO7HX#2uD{d^&tKcrQq%=rH@TyA&aFZ za6i6+ZTJ~JfZN!QBX|}M;77Okg3yHF|>@V)b7@o$XxPU3VPctjL zf?Z#VN=F}~lxtg`9mum-Oa3#IiLT-9%Ax)NGNF`un}ihD$h4ZUBj>kp zg8XYJBfVoIHvrG#-8hdsuzXYY-gje~{4jQ6D~-zc;55>OO5=(}TuV%lf1fK=D^okl z^kuKdkX2F>*nrb0OMDeu@RQv0I)*O|A4aJ+g4{TD7Nw&XQOf@UZ^wV-+({*QpF;Xp zFX3ug+IbRkAOD2X(5H9<=GA9UwFisIuSDr^BXa&!3(5fZBDA;|fW;I1BSk^TP~3AV^R?O(x%h4$bu; zpNyP`tweUh-8yi;58`&>-I5>}S=@6aw@ZSYtsC~_j2eN6*%S)LMa`1~dph-rq?t6;9(g}x z29t?vFM<)1hsgmQi)teh(V6S@dcf$lJ}nrmHX|mbuRT5%8~jg$Goiw_mgIGr ziR8dc?TYZC@~&i{Kb-iV($;u!U8=KPhod^tXKLE$_v`ijW`EEK_L(7nQqJb)2h3pj*f+GH-Eul$1dp51ki1I9-DY$o7Cat~_BQH{WF!$DV8VT| zcp^@Ps1BI97Q$vo$1BVMW6(&D3`mP{vp*b+MPkuLD_z{NJeUZdG?IWLGvbMc?m;6Or>oeYU-!mOZu9CLE^Ylr zIMO(nwB}2@Jo}7jZ_?zR41?D4#H&)OOLb^9lFM%&Z&C40{KuJgEk!5ML$ z)J;5c&R7eps;rMH)^0jyrzw)LXYDtxtK*!pFO!|43AdJYs-kj(oz~`7 zC1;ey)NYB(&bZsw#YXE$&5x@mc{#$!r=_awfV9He%5-LyZR}aRjMisqY|aYQzO&{O zn=_v6$*pivGps4+I~1TDtF>;z?=B!OY1Mf&yC&{1hX1Q=#hW)|DX#0!daLf_zX5l> B(Juf1 diff --git a/apps/ocr/locale/ru/LC_MESSAGES/django.po b/apps/ocr/locale/ru/LC_MESSAGES/django.po index e4dd103e6d..d26093e9e4 100644 --- a/apps/ocr/locale/ru/LC_MESSAGES/django.po +++ b/apps/ocr/locale/ru/LC_MESSAGES/django.po @@ -1,78 +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: # Sergey Glita , 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 10:48+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-02 14:17-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" "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: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:31 __init__.py:32 msgid "submit to OCR queue" msgstr "отправить на распознавание" -#: __init__.py:45 __init__.py:46 +#: __init__.py:33 __init__.py:34 msgid "re-queue" msgstr "переотправить" -#: __init__.py:47 __init__.py:48 __init__.py:63 +#: __init__.py:35 __init__.py:36 __init__.py:49 msgid "delete" msgstr "удалить" -#: __init__.py:50 +#: __init__.py:38 msgid "stop queue" msgstr "остановка очереди" -#: __init__.py:51 +#: __init__.py:39 msgid "activate queue" msgstr "активировать очередь" -#: __init__.py:53 +#: __init__.py:41 msgid "clean up pages content" msgstr "очистка содержимого страниц" -#: __init__.py:53 +#: __init__.py:41 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -80,35 +50,35 @@ msgstr "" "Применить языковый фильтр для удаления общих ошибок распознавания " "содержимого страниц документа." -#: __init__.py:55 +#: __init__.py:43 msgid "queue document list" msgstr "список очереди документов" -#: __init__.py:58 views.py:316 -msgid "active tasks" -msgstr "активные задачи" +#: __init__.py:44 __init__.py:62 permissions.py:7 +msgid "OCR" +msgstr "Распознавание текста" -#: __init__.py:60 +#: __init__.py:46 msgid "transformations" msgstr "преобразования" -#: __init__.py:61 +#: __init__.py:47 msgid "add transformation" msgstr "добавить преобразование" -#: __init__.py:62 +#: __init__.py:48 msgid "edit" msgstr "редактировать" -#: __init__.py:82 +#: __init__.py:69 msgid "Default" msgstr "Умолчание" -#: __init__.py:104 +#: __init__.py:97 msgid "Checks the OCR queue for pending documents." msgstr "Проверить очередь документов ожидающих распознавания ." -#: api.py:119 +#: api.py:122 msgid "Text from OCR" msgstr "Распознанный текст" @@ -132,88 +102,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 +218,185 @@ 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\"" +"Вы действительно хотите удалить преобразование очереди " +"\"%(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 +420,11 @@ 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/permissions/locale/en/LC_MESSAGES/django.po b/apps/permissions/locale/en/LC_MESSAGES/django.po index a2354e2728..acd1b43e64 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-02 14:17-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:216 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:218 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:336 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:213 msgid " and " msgstr "" -#: views.py:142 views.py:201 +#: views.py:149 views.py:213 #, 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:174 #, python-format msgid "" "Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" msgstr "" -#: views.py:211 +#: views.py:223 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "" -#: views.py:214 +#: views.py:226 #, python-format msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." msgstr "" -#: views.py:226 +#: views.py:238 #, python-format msgid "" "Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" msgstr "" -#: views.py:278 +#: views.py:273 views.py:297 +msgid "Users" +msgstr "" + +#: views.py:276 views.py:300 +msgid "Groups" +msgstr "" + +#: views.py:279 views.py:303 +msgid "Special" +msgstr "" + +#: views.py:332 #, python-format msgid "non members of role: %s" msgstr "" -#: views.py:279 +#: views.py:333 #, 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 ddd24a555b92940b30097848d608f933d1b5a2bf..bc2b168886f1309eb101f83a59977dc2b0f1b0c5 100644 GIT binary patch delta 414 zcmX}oKTE?<6o&Cr|3%XlYZ0X_+U`x564ThiX>22(loy=9SCfBYnYxb^bmCGMcF9pZ8c>*`uAv@0 z$4P9W?t8!yd_uk88I#yC@867F%#nYg?jKAs04TJobhcgvD*&I}J{} WQ2B0QOYI-}p~ArPkJW9@8vX-2cR7Lp delta 407 zcmX}oJxBvV5QgE2f2a9D4H8WPnp!<@FGk@+EiKeeP%AmGP!Lb{u9aY6VPlg*v<-rS zg<@lw!cuHg2%=z-&MsJ3_%2!8=3%~_**UJ2|IFX-CaP}p}K z+`>(~z*YRlbzDe_4B{DP@e)Vz4tY|ZaTs50{*GnpHqPQ?N~*#x*-3Q<_Hc;$2+iOL zj$jQ<-wpQR1DXX-n8Aj#HZDT%}ykD=FoBbG0j{IQ^eg{PO(N3@5o3M6tV}gTv?` Sh(qm{bQlGCKh*V>)B6WiU^ess diff --git a/apps/permissions/locale/es/LC_MESSAGES/django.po b/apps/permissions/locale/es/LC_MESSAGES/django.po index 2ae5d18ed6..29f9e554c8 100644 --- a/apps/permissions/locale/es/LC_MESSAGES/django.po +++ b/apps/permissions/locale/es/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:18+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,164 +18,176 @@ msgstr "" "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:216 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:218 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:336 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:213 msgid " and " msgstr "y" -#: views.py:142 views.py:201 +#: views.py:149 views.py:213 #, 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:174 #, 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:223 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "Permiso \"%(permission)s\" revocado de: %(requester)s." -#: views.py:214 +#: views.py:226 #, 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:238 #, 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:273 views.py:297 +msgid "Users" +msgstr "" + +#: views.py:276 views.py:300 +msgid "Groups" +msgstr "" + +#: views.py:279 views.py:303 +msgid "Special" +msgstr "" + +#: views.py:332 #, python-format msgid "non members of role: %s" msgstr "no miembros de la función: %s" -#: views.py:279 +#: views.py:333 #, python-format msgid "members of role: %s" msgstr "miembros de la función: %s" diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.mo b/apps/permissions/locale/it/LC_MESSAGES/django.mo index f280a0f28ab729d1acb36791f60a61fccd54c0df..1996647392b9b98c278e9c4f4a887e123278cdd7 100644 GIT binary patch delta 422 zcmX}oPbdU&6u|Mf8U{Ng`Lkn_DJKV;(S|k-ds5ssE^@H4Ny*fZw3o?64sLT(ilfw~ z_Nv%}xHz~d2RBCt4me2pzUG&D{XW0<-mmxj^}BKJ+{?98^pp}Autl0hm*yh+|r=X{}F_=^_yFiiU{4&pHCyrMHJ(#vL!g1TZFyQqUA z)So#(eaMmV1iQ&=rr)TaH@#XNItay7Cvgc5Zf*s^&O&h$ ziXcvQP{BoT@GsCo2X%7x`!vFFpS<^u-yOLx-;^)vsrWG^GGdElMC3gyGLBz3hlTz> zmvMvo7}xO)S8;Jbge9kJ1w2c<#2obRMa}s{z3>|?%oC>bB97rGYF^+hi45_vKto+i1`%q|KI)%| zQ6F-Yc!EXhPBOplo~K`|yzz|jeBU)D@N2EMU2*96o~gQ1GeNc0vr7{z+gp3hFlt2Z WeAuXmJML`rzcab{+v%pWx7H8z-#E(v diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.po b/apps/permissions/locale/it/LC_MESSAGES/django.po index 1dcf050cc9..7c37d3efb9 100644 --- a/apps/permissions/locale/it/LC_MESSAGES/django.po +++ b/apps/permissions/locale/it/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-12-13 08:38+0000\n" -"Last-Translator: Pierpaolo Baldan \n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,135 +18,135 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:12 -msgid "View roles" -msgstr "Vedi i ruoli" - -#: __init__.py:13 -msgid "Edit roles" -msgstr "Modifica i ruoli" - -#: __init__.py:14 -msgid "Create roles" -msgstr "Crea ruoli" - -#: __init__.py:15 -msgid "Delete roles" -msgstr "Cancella i ruoli" - -#: __init__.py:16 -msgid "Grant permissions" -msgstr "Concedere le autorizzazioni" - -#: __init__.py:17 -msgid "Revoke permissions" -msgstr "Revoca le autorizzazioni" - -#: __init__.py:19 models.py:87 views.py:38 +#: __init__.py:17 models.py:209 views.py:40 msgid "roles" msgstr "ruoli" -#: __init__.py:20 +#: __init__.py:18 msgid "create new role" msgstr "crea nuovo ruolo" -#: __init__.py:21 +#: __init__.py:19 msgid "edit" msgstr "modifica" -#: __init__.py:22 +#: __init__.py:20 msgid "members" msgstr "membri" -#: __init__.py:23 +#: __init__.py:21 msgid "role permissions" msgstr "permessi dei ruoli" -#: __init__.py:24 +#: __init__.py:22 msgid "delete" msgstr "cancella" -#: __init__.py:26 +#: __init__.py:24 msgid "grant" msgstr "concessione" -#: __init__.py:27 +#: __init__.py:25 msgid "revoke" msgstr "revoca" -#: api.py:22 -msgid "Permissions" -msgstr "Permessi" - -#: api.py:55 +#: models.py:51 msgid "Insufficient permissions." msgstr "Permessi insufficienti" -#: 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 "etichetta" - -#: models.py:20 models.py:65 views.py:145 views.py:204 +#: models.py:131 models.py:187 views.py:152 views.py:216 msgid "permission" msgstr "permesso" -#: models.py:21 views.py:55 views.py:147 views.py:206 +#: models.py:132 views.py:57 views.py:154 views.py:218 msgid "permissions" msgstr "permessi" -#: models.py:73 +#: models.py:195 msgid "permission holder" msgstr "titolare del permesso" -#: models.py:74 +#: models.py:196 msgid "permission holders" msgstr "titolari dei permessi" -#: models.py:86 models.py:104 views.py:74 views.py:91 views.py:115 -#: views.py:282 +#: models.py:204 +msgid "label" +msgstr "etichetta" + +#: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117 +#: views.py:336 msgid "role" msgstr "ruolo" -#: models.py:115 +#: models.py:255 msgid "role member" msgstr "membro del ruolo" -#: models.py:116 +#: models.py:256 msgid "role members" msgstr "membri del ruolo" -#: views.py:61 +#: 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:142 views.py:201 +#: views.py:149 views.py:213 msgid " and " msgstr " and " -#: views.py:142 views.py:201 +#: views.py:149 views.py:213 #, 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 "Permesso \"%(permission)s\" concesso a: %(requester)s." -#: views.py:155 +#: 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:167 +#: views.py:174 #, python-format msgid "" "Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" @@ -154,17 +154,17 @@ msgstr "" "Sei sicuro che tu voglia concedere questo permesso %(permissions_label)s " "%(title_suffix)s?" -#: views.py:211 +#: views.py:223 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "Permesso \"%(permission)s\" revocato per: %(requester)s." -#: views.py:214 +#: views.py:226 #, 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:226 +#: views.py:238 #, python-format msgid "" "Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" @@ -172,12 +172,24 @@ msgstr "" "Sei sicuro di voler revocare questo permesso %(permissions_label)s " "%(title_suffix)s?" -#: views.py:278 +#: views.py:273 views.py:297 +msgid "Users" +msgstr "" + +#: views.py:276 views.py:300 +msgid "Groups" +msgstr "" + +#: views.py:279 views.py:303 +msgid "Special" +msgstr "" + +#: views.py:332 #, python-format msgid "non members of role: %s" msgstr "nessun menbro per il ruolo:%s" -#: views.py:279 +#: views.py:333 #, python-format msgid "members of role: %s" msgstr "membri per il ruolo:%s" diff --git a/apps/permissions/locale/pt/LC_MESSAGES/django.mo b/apps/permissions/locale/pt/LC_MESSAGES/django.mo index 715b0f389ba40b09480ce6eeb9d3af97083cc62b..039a7cdf27cd637eb4826b946afaf08c6a9f1205 100644 GIT binary patch delta 467 zcmZwCKTE?v7zXgSwY4@;tp7z6f?JU^mr}6=w{|R4Vkcd^mXHQ)t|V8%IMh`gJNf~f z1hKnr>Q@lD_yJsX^-0^&rjOYa2KvX1~I9M1yQO^_s1FPj}J~!*uX&xq8GY?S$GY% z;Vo3)16+g8a1(yOxPdPiH~0;g;SY=-&Y~FKy949<_96Z|&H`kIN-|3J+fsHd!*D&> z?llW7(J=xM^1u^;(czceH@qp%(99TyBet=-d9N&`IbJ=Q5*(w ks3IL(OS}4Hww-D$8asuu3Tnry#tVl@, 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 04:52+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-02 14:17-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" "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 "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:216 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:218 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:336 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:213 msgid " and " msgstr "" -#: views.py:142 views.py:201 -#, fuzzy, python-format +#: views.py:149 views.py:213 +#, 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:174 +#, 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:223 +#, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." -msgstr "Permissão \"%(permission)s\" revogada de %(ct_name)s: %(requester)s." - -#: views.py:214 -#, fuzzy, 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 +#, python-format +msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." +msgstr "" + +#: views.py:238 +#, 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:273 views.py:297 +msgid "Users" +msgstr "" + +#: views.py:276 views.py:300 +msgid "Groups" +msgstr "" + +#: views.py:279 views.py:303 +msgid "Special" +msgstr "" + +#: views.py:332 #, python-format msgid "non members of role: %s" msgstr "não membros da função: %s" -#: views.py:279 +#: views.py:333 #, python-format msgid "members of role: %s" msgstr "membros da função: %s" @@ -205,5 +206,4 @@ 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 8f8ad487ab18ee9ef8a5d9d5e3740bc3394583f4..7ce243e6ceef6bf749d68119dc7a7e7e0758a1db 100644 GIT binary patch delta 451 zcmX}mPfG$(6o=uHl$L2k6qO=Oe}q6BoG6k>rXV5+S0S{B7L$nxIs@a>!i}_)AcA%h z)UsAZZd|-C3xHKNPh4bVioWnCT@CtQ&!(IGA3)f@PmT4Y-Ok@%}xPV<$gI{qG z`#6EWn80W}SdhjUvW2Q&!YM2dJjXD(gKF+I&f*KIz3=foku;A_3M)9m6xGmCeP{Wi*O%P WoL7pr`^$RUJ8l*Hvw@koHGTk=bu*&? diff --git a/apps/permissions/locale/ru/LC_MESSAGES/django.po b/apps/permissions/locale/ru/LC_MESSAGES/django.po index b30891a80f..4a10f25c8a 100644 --- a/apps/permissions/locale/ru/LC_MESSAGES/django.po +++ b/apps/permissions/locale/ru/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,162 +18,174 @@ 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: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:216 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:218 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:336 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:213 msgid " and " msgstr "и" -#: views.py:142 views.py:201 +#: views.py:149 views.py:213 #, 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:174 #, 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:223 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "Право \"%(permission)s\" отозвано у %(requester)s." -#: views.py:214 +#: views.py:226 #, python-format msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." msgstr "%(requester)s не имеет права \"%(permission)s\"." -#: views.py:226 +#: views.py:238 #, 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:273 views.py:297 +msgid "Users" +msgstr "" + +#: views.py:276 views.py:300 +msgid "Groups" +msgstr "" + +#: views.py:279 views.py:303 +msgid "Special" +msgstr "" + +#: views.py:332 #, python-format msgid "non members of role: %s" msgstr "не входит в %s" -#: views.py:279 +#: views.py:333 #, python-format msgid "members of role: %s" msgstr "входит в %s" diff --git a/apps/project_setup/locale/en/LC_MESSAGES/django.po b/apps/project_setup/locale/en/LC_MESSAGES/django.po index 2a81c4bb2a..567bfb3830 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-02 14:17-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 37f3fb805306d9580ae222ba8e96d20ffc539e48..054334e2686d644f5b6a7d33ed83ecf5b5e7226b 100644 GIT binary patch delta 69 zcmcc2a*JhxiRf-d28Ln=1_nML)@Nd1kOtCr6Ftj#jdTq_NWsv=%Fuk`8GHVq{G`;P Tl6-}r{Nlu-%>2#5j1G(d2PF`> delta 62 zcmcb`a+zg\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 index 228f7547c6abd139e708e3d6773bfefa2c316317..837d26e8e38056e14cd40a7f5e3c9d5874052d50 100644 GIT binary patch delta 72 zcmaFKa)@PuiRcPO28Ln=1_n+bmSJLGkOtCf6FuW6o)_me(lr1f1w#`nL-UEB_wo27 X=B1Y=rl(pdWR^_cz!*JQf+-LHO*|5d delta 129 zcmX@a@{(nOiRgJo28Ln=1_n+bc4lH=kOtDe6FuX-GfGMdtn~HMGfOf`lk}4FbM=ez zixZ17^NaLz6Dt$*^fQZ#OH+%v0{laCor_WvOEUBGbX^ilQmqt>3=9o*fyl^6!O+mk c$ZX=7eUqm%MsfKh=B1Y=rUO+>e#aOB07q^oYybcN diff --git a/apps/project_setup/locale/it/LC_MESSAGES/django.po b/apps/project_setup/locale/it/LC_MESSAGES/django.po index de45fa3044..7d10e457d4 100644 --- a/apps/project_setup/locale/it/LC_MESSAGES/django.po +++ b/apps/project_setup/locale/it/LC_MESSAGES/django.po @@ -1,29 +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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:6 msgid "setup" msgstr "configura" -#: views.py:13 +#: views.py:15 msgid "setup items" msgstr "parametri di configurazione" - - diff --git a/apps/project_setup/locale/pt/LC_MESSAGES/django.mo b/apps/project_setup/locale/pt/LC_MESSAGES/django.mo index 7c882520090ae4c5eab03716106e87e8a90b1668..c35bd7a24031251ca0cebda3389834d3bcc8bef2 100644 GIT binary patch delta 24 dcmdnPvWI2DeqJM80}xU$G_f)?-*~2g5ddAa2SNY< delta 24 fcmdnPvWI2DeqKXeLqlC7BLzc4D diff --git a/apps/project_setup/locale/pt/LC_MESSAGES/django.po b/apps/project_setup/locale/pt/LC_MESSAGES/django.po index 7ffd621c32..e675f151ed 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-02 14:17-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 6eafab04931b1807af2a58217a4e5e52c4f25b7f..a413851f5ae3d11f8443ceb17135858909f3d687 100644 GIT binary patch delta 66 zcmeyw@{?tPiReQ{28Ln=1_mJ@4rO9s5CGB{6Ftj#jdTq_NWsv=%Fuk`8GD}K)S~p% QN(J|v%#y^-0*pzF0QR2{CIA2c delta 59 zcmey#@`+`FiRdjx28Ln=1_mJ@_G4mT5CGDN6Ftj#4Rs9-b&ZS^3=OS}%qE_(XH73I MGdI{Q&X~jq0E9vfMgRZ+ diff --git a/apps/project_setup/locale/ru/LC_MESSAGES/django.po b/apps/project_setup/locale/ru/LC_MESSAGES/django.po index e6069f5616..945a27b089 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-02 14:17-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_tools/locale/en/LC_MESSAGES/django.po b/apps/project_tools/locale/en/LC_MESSAGES/django.po index 255cb9e18c..dbf6bf4871 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-02 14:17-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 9416fb42f7ba4c26f6e2109c71e92ad4b578727c..73e308f8dc49e7870148969a9e772c657ce5ef3d 100644 GIT binary patch delta 60 zcmbQqvVdiR4)1P828M731_mA=7M^IC#cQN%0743eCRT>#6F1oN2jwTF7M0{H1mzbe M7G>sd{I0|Z0GlZgD*ylh delta 53 zcmZ3$GLvP34(}F528M731_mAwo@klHYp82zsB2`TU}$J%WHxbwJx5V~abi(se$mE% GN{j$BxDBuX diff --git a/apps/project_tools/locale/es/LC_MESSAGES/django.po b/apps/project_tools/locale/es/LC_MESSAGES/django.po index 9db820eb03..ba97e95eda 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-02 14:17-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 index bf768aae63544c0f0b27345295ad90cdf757551d..e74238fc0bfb5162dbcc3ee6fb01e3c57ad5b584 100644 GIT binary patch delta 84 zcmdnU(#0}Chj#@d14B3i0|O@zGfcD$R^bZp57BilN=+=u%+J$xNi0dVQZOrGfO5-E-pn0$%R0sxswCB6Uv diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.po b/apps/project_tools/locale/it/LC_MESSAGES/django.po index 959bcf5413..bb22a3a0c3 100644 --- a/apps/project_tools/locale/it/LC_MESSAGES/django.po +++ b/apps/project_tools/locale/it/LC_MESSAGES/django.po @@ -1,25 +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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:7 views.py:13 +#: __init__.py:7 views.py:15 msgid "tools" msgstr "strumenti" - - diff --git a/apps/project_tools/locale/pt/LC_MESSAGES/django.mo b/apps/project_tools/locale/pt/LC_MESSAGES/django.mo index 424ab9c3eeb2c6380b63ac78d5785902e546c286..4fd22d2f96333a9b003430b93428eb0d2278db25 100644 GIT binary patch delta 24 dcmZo?X=j\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 99daa2c0af223caa95567c215f7ce69706b7da41..316e8bbbf63d986d29b3d1d09d78c437cae7cf17 100644 GIT binary patch delta 363 zcmYL^&q~8U5XMujmmWRnMPv^i6y5A527*hG9x6pJ7}KKX#cpFH|JdC$_EfD$Pa-~w z;6dLZc>%!}@EM#a=*RpRKA3Nq`C6{p^N-c`vjJKHHh?`~1?U2ee4z1Xz-P-aE}*Xg z2M_@JlY{mzon^5ye3@N~OO21m_*_U8Whp}*pYaqO^}S&y5P2pw_SEBKYi?uO6tWy< zxtKbXcKlNuh-uX1aGz_zkWDQML(zR?xy*KUDX4S8mBu5Wailrw zhHC24Uc#f;l*J)Tr(wZEfk%QT3$ s&GlG}6Gb${i7d#@-$sUH@wC~h)~na*y}qj#^=*A$y;U#Z7WISi4cicC_5c6? delta 249 zcmcb>@{T#?o)F7a1|VPrVi_P-0b*t#)&XJ=umIvMKuJp=4N?OK0Y&*)smUd}o+-Lv zsYS(^`FU0f0glezj_$4sVXi^Jp8kFlOZ9jSbqx)5jf@lw4XupKCT@_Zk92hm()IP% zb#YYi@VD~y)Qxyup;p9rj F0|0-!J|_SG diff --git a/apps/project_tools/locale/ru/LC_MESSAGES/django.po b/apps/project_tools/locale/ru/LC_MESSAGES/django.po index b4158a9108..9d2e159cc5 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-02 14:17-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/smart_settings/locale/en/LC_MESSAGES/django.po b/apps/smart_settings/locale/en/LC_MESSAGES/django.po index d0e511720a..d3d311c670 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-02 14:17-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 71eba7fd8b3614a732e13873e1ade605bb429df0..1b20e4e7df6b61e584fe6fe74ca10887217f21f5 100644 GIT binary patch delta 85 zcmZo-?PQ(cqPm-rfng~F0|Pe@Co(ZGumR~@Ak7D)OMo;hkZzus*}-e1YXCwDh9*{q e<`e(f^9SW8r52UsD+J{iCl+PqZ+2z0Wds0!+Y(g( delta 78 zcmeBVZDO6^qPm5Vfng~F0|Pe@M=>!lumR~bAk7D)bAdD~kgl1S*}-e5YiOuzWTaqd ZXk}zJ@t-|MQGRh^QD%P8W*\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 index ec725d4764000c19450336b186a0880bf371e902..30ad835a45cb53c72fb3f861509443b27b98f45c 100644 GIT binary patch delta 90 zcmbQi`jKUVi|PtS28N{!3=Hf*?8n5wzyhShfHWVFjt0_fKssw;X5nN;MsZ#vT>}tO jFf_3;G@q=>xR1vtF)zI|F+J5vA+u!iBgW{-UQB)f!-Epv delta 145 zcmey!GJ|!3i|Tns28N{!3=Hf*T*}12zyhRefixeGZUWM5KzicD%tG&sl9B=|ef{*z zl8n+Mz2y8{{i6Kh#G=gnBK_RN%EUbV%;MtG)MBmx{}5g0qSVBa%=|oEm&B4(D+MD1 mLqlC4GBQ#yG_*1@oA__v7|M3Koye}m;wP{@F>>+ diff --git a/apps/smart_settings/locale/it/LC_MESSAGES/django.po b/apps/smart_settings/locale/it/LC_MESSAGES/django.po index 9f4f5da204..00cd08980d 100644 --- a/apps/smart_settings/locale/it/LC_MESSAGES/django.po +++ b/apps/smart_settings/locale/it/LC_MESSAGES/django.po @@ -1,37 +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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2011-11-22 11:26-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:8 views.py:26 +#: __init__.py:9 views.py:28 msgid "settings" msgstr "configurazione" -#: views.py:31 +#: views.py:33 msgid "name" msgstr "nome" -#: views.py:32 +#: views.py:34 msgid "default" msgstr "default" -#: views.py:33 +#: views.py:35 msgid "value" msgstr "valore" - - diff --git a/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo b/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo index 868ac5ecd2ccc01655ef75ececa21b054d8dd369..eb2bc89543e7ab69adb9f7cfbda7e3925fdc02d8 100644 GIT binary patch delta 24 dcmaFE@`h!?M_wac0}xU$G_f)?-}o<&5ddnP2m}BC delta 24 fcmaFE@`h!?M_xl+LqlC7BLzc4D\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 d8be5861811d38f2aa3d7e80a95d2b2c26a9520e..9f2931e45f113d4767448675441675ce8ab4999d 100644 GIT binary patch delta 82 zcmX@idWv;|i|Rv028N{!3=HBx+|I#28N{!3=HBx+`z=Zzy_pe0BIp0Js(I50O?H=Gdp+\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/sources/locale/en/LC_MESSAGES/django.po b/apps/sources/locale/en/LC_MESSAGES/django.po index 609adf9151..90020f8f73 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-02 14:17-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:201 msgid "web forms" msgstr "" -#: __init__.py:30 models.py:130 +#: __init__.py:24 models.py:172 msgid "staging folders" msgstr "" -#: __init__.py:31 models.py:194 +#: __init__.py:25 models.py:236 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:200 msgid "web form" msgstr "" @@ -169,127 +157,151 @@ msgstr "" msgid "server watch folders" msgstr "" -#: models.py:29 +#: models.py:36 msgid "title" msgstr "" -#: models.py:30 +#: models.py:37 msgid "enabled" msgstr "" -#: models.py:31 +#: models.py:38 msgid "whitelist" msgstr "" -#: models.py:32 +#: models.py:39 msgid "blacklist" msgstr "" -#: models.py:98 +#: models.py:140 msgid "icon" msgstr "" -#: models.py:98 +#: models.py:140 msgid "An icon to visually distinguish this source." msgstr "" -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "folder path" msgstr "" -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "Server side filesystem path." msgstr "" -#: models.py:115 +#: models.py:157 msgid "preview width" msgstr "" -#: models.py:115 +#: models.py:157 msgid "Width value to be passed to the converter backend." msgstr "" -#: models.py:116 +#: models.py:158 msgid "preview height" msgstr "" -#: models.py:116 +#: models.py:158 msgid "Height value to be passed to the converter backend." msgstr "" -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "uncompress" msgstr "" -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "Whether to expand or not compressed archives." msgstr "" -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "delete after upload" msgstr "" -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "Delete the file after is has been successfully uploaded." msgstr "" -#: models.py:129 +#: models.py:171 msgid "staging folder" msgstr "" -#: models.py:169 +#: models.py:211 msgid "interval" msgstr "" -#: models.py:169 +#: models.py:211 msgid "" "Inverval in seconds where the watch folder path is checked for new documents." msgstr "" -#: models.py:193 +#: models.py:235 msgid "watch folder" msgstr "" -#: models.py:198 +#: models.py:240 msgid "Enter a valid value." msgstr "" -#: models.py:226 views.py:487 +#: models.py:268 views.py:581 msgid "order" msgstr "" -#: models.py:227 views.py:488 views.py:525 views.py:555 +#: models.py:269 views.py:582 views.py:619 views.py:649 msgid "transformation" msgstr "" -#: models.py:228 views.py:489 +#: models.py:270 views.py:583 msgid "arguments" msgstr "" -#: models.py:228 +#: models.py:270 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "" -#: models.py:239 +#: models.py:281 msgid "document source transformation" msgstr "" -#: models.py:240 +#: models.py:282 msgid "document source transformations" msgstr "" -#: staging.py:42 +#: models.py:288 models.py:289 +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,205 @@ 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 metadata" msgstr "" -#: views.py:265 views.py:284 +#: views.py:358 views.py:377 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "" -#: views.py:307 +#: views.py:400 msgid "Staging file delete successfully." msgstr "" -#: views.py:309 +#: views.py:402 #, python-format msgid "Staging file delete error; %s." msgstr "" -#: views.py:368 +#: views.py:462 msgid "Source edited successfully" msgstr "" -#: views.py:371 +#: views.py:465 #, python-format msgid "Error editing source; %s" msgstr "" -#: views.py:376 +#: views.py:470 #, 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 +#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 +#: views.py:691 msgid "source" msgstr "" -#: views.py:410 +#: views.py:504 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "" -#: views.py:412 +#: views.py:506 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "" -#: views.py:419 +#: views.py:513 #, python-format msgid "Are you sure you wish to delete the source: %s?" msgstr "" -#: views.py:451 +#: views.py:545 msgid "Source created successfully" msgstr "" -#: views.py:454 +#: views.py:548 #, python-format msgid "Error creating source; %s" msgstr "" -#: views.py:459 +#: views.py:553 #, python-format msgid "Create new source of type: %s" msgstr "" -#: views.py:481 +#: views.py:575 #, python-format msgid "transformations for: %s" msgstr "" -#: views.py:511 +#: views.py:605 msgid "Source transformation edited successfully" msgstr "" -#: views.py:514 +#: views.py:608 #, python-format msgid "Error editing source transformation; %s" msgstr "" -#: views.py:519 +#: views.py:613 #, python-format msgid "Edit transformation: %s" msgstr "" -#: views.py:542 +#: views.py:636 msgid "Source transformation deleted successfully." msgstr "" -#: views.py:544 +#: views.py:638 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "" -#: views.py:557 +#: views.py:651 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" msgstr "" -#: views.py:587 +#: views.py:681 msgid "Source transformation created successfully" msgstr "" -#: views.py:590 +#: views.py:684 #, python-format msgid "Error creating source transformation; %s" msgstr "" -#: views.py:599 +#: views.py:693 #, 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 4395893c480d68c6dedde616379048bbb3fa4719..7a4495f7d4963160d717ea9fd7bef90258726460 100644 GIT binary patch delta 2355 zcmY+^Uu;ul7{~EvZiBAC*cfvo2rrrsfqKGTKg}is;Tadk^2A!3XVhz)amU*ofn}8Lwj#Iz?u5Z2(&_iTB|c zF2FBv34V_ySQPZ`ufz(ojMdU<;UBB90Mn=&U&TT^faN%fJYZuu2hZYsoIp+B2h>2n z;=Ncl%Pfpx)I@u+9uML@n8galw+T90;Wc~^f5UdHp6v~^8#R&FF^+HHOuU53*tb}N zw@@oDXLgn7;!=#`GTe&|cmnyeulbnG_;!WP{rC&&MKg=NR5zez+=E)#K3s$+QTI*w z{()_LFPUpb*Sau*gGe&$FzWrsF^r#M9p1!DGo5nstrc!Uy`Tf_M-1=s7&q0 zGCYWS@iDB%v#2ecLf&mZp)z#~wS~8lsdT<45LNO#c z){c5nFW!wWp(gS!sun)NT(P2_A4ffZ4mF`~Pz$<>8s|nS`PU6M{TuF}imaIBD|L%e zd*-6Hq8Hg_dmA;OQPjkbqF#K`_YD4+XZ9ItB1f5>i(}Y>ljvYmhUIAH1K5Qx<3juj zmD=C28E3Iv-eob=z}ry&@5gnx54ECm$RlHHs{ zqiQ~ln&D;CF`7oDsECW2SQM4Q-KecNhT8j!sMB!;b=(SgIEqd90PaF9+Pu+gOVwEH{D?)Wnjw5|5x(co}v7B$6zfM%7Ru`=qKb zK^12eGFPj`dd9aH9TnLQ|AtYd4(%|ixK5!m@Cm90uA>J0)AtT4r3KaA^{>d5tWHGsLVW%8765*=qO@u`{_n&wb(J zalf+_pCuk9=J?mN#c{v?kgw`5w})iV))Qf3vHwq{h*RU8d;glUprTt#=(uXXwIa0+ zVlxpUROzY_H66#Dxt_PUCcm$RuVMV$@mhx}8tr2z(N8ENtBE>7g{P*1Qlp6NF``dj z{PvXZ5N;tJAyhZrL@UukY#;)M}HwV5_MOGorvQEw{8h{4!x2bNv8IMHzd+S(NMGF{(E0b)NNVj s(1P*ANIKj-oY*t+LL!|Sj)po@gG0mV6pkc@ld0^dWnKAMw_;cDZ+rjJdH?_b delta 2398 zcmYk-U2Icz7{~Ev(!DV4giXhALpsJNxE0ni2XvE{f-qoHv;*8=8+BCHsB7rPvI}FK zL6QLhXTyzpBQHi`3<-@U27?3=GZGUd0g23PS6&c}XjDWKiQiv)mh2y%eNIo$`M*5> z=TE;0eXu?`QS3Tlv|gfu*geDS2!5EyAKF-fnJ%wlEq;ev@IPFJ%`?rov>|N5VJyds zI1g{*V!V&Du(B}wd;sT|C9RQ*m3$FK7am1DIEwS}BqG+7i|LFcn=>#*TdP4 z=b{E&fOByx`Y?)`a0xkYC5WhM9|dQcs$!CH)%F@|pjA7-dOx2*aa5<86+dP~6>%r~ZkR7OE>PAhZ7xiKvYC?lZ z*6bZrM=31Dv#5z&Le;_z)CBLK-v15t{(aPh@>!J@G^d#SYoJPQ=m9V4fd*7fY(%B5 z3$39dnbIkrgP2?K0^W!btfisgVqmGL`sF{yq7(d1Z z_%AB8^H^p8n~=UNjvDxF)c5b=Iy{G3(C^5r_BU3co7HH-epIopMipmr7Z+Obp!3Bc zR0pR}1D?e){1H_&f8i>u;-*eXC+e7uqR#uLsFhyD2E2~lSinP?a4)L=L3~N){|zpb zvYS|qlc=iBWqO*Smp?jAAylTiP!l_jO66tLmi&pTfeIehDXBvpyLJrXL0pPoqZaZj zuGRUkARjtrov0TMV>5n^s)+}vW94Rf+M;c!lt!^0M^F>Hh%4|eYK30*MbGJ(+L|U*adx5Z4?B*a1{g&R@DZ|` zb{=o)xb@JGN9Edwb}+{O6}<^nO{s@?jtr3Yl(Hl^rqE! z5X?W*ypB4W+Cq(=DK1?2?RN{I)<)nAl1b6KXnUuMq8o_H8%ONUSGR;nUk5 zJ}e_%BvgbtA=Shx;sv6Um}*-zr1m>PEF^lIZ``PT-$*>`+*|B8g$is9vBBEJm3*3I6-|q_qJbr&L(2!~@DX*Qn6YvM?0yTBC z!j?$?fUhkP>Fa+jG7wJ$J&AaKBoT`z(jz6|8C4scUgMsgNMc`PFUI>k(V^G?k7>B* L()4)gtA+mqHGJKI diff --git a/apps/sources/locale/es/LC_MESSAGES/django.po b/apps/sources/locale/es/LC_MESSAGES/django.po index b71b65dc33..45c0ca1900 100644 --- a/apps/sources/locale/es/LC_MESSAGES/django.po +++ b/apps/sources/locale/es/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ 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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:18+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:201 msgid "web forms" msgstr "formularios web" -#: __init__.py:30 models.py:130 +#: __init__.py:24 models.py:172 msgid "staging folders" msgstr "carpetas de archivos provisionales" -#: __init__.py:31 models.py:194 +#: __init__.py:25 models.py:236 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 "" + +#: __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 "" + #: 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:200 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:36 msgid "title" msgstr "título" -#: models.py:30 +#: models.py:37 msgid "enabled" msgstr "activado" -#: models.py:31 +#: models.py:38 msgid "whitelist" msgstr "lista blanca" -#: models.py:32 +#: models.py:39 msgid "blacklist" msgstr "lista negra" -#: models.py:98 +#: models.py:140 msgid "icon" msgstr "icono" -#: models.py:98 +#: models.py:140 msgid "An icon to visually distinguish this source." msgstr "Un icono para distinguir visualmente esta fuente." -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "folder path" msgstr "ruta de la carpeta" -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "Server side filesystem path." msgstr "Camino a los archivos en el servidor." -#: models.py:115 +#: models.py:157 msgid "preview width" msgstr "ancho de muestra" -#: models.py:115 +#: models.py:157 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:158 msgid "preview height" msgstr "alto de muestra" -#: models.py:116 +#: models.py:158 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:159 models.py:196 models.py:209 msgid "uncompress" msgstr "descomprimir" -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 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:160 models.py:210 msgid "delete after upload" msgstr "eliminar después de subir" -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 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:171 msgid "staging folder" msgstr "carpeta de archivos provisionales" -#: models.py:169 +#: models.py:211 msgid "interval" msgstr "intervalo" -#: models.py:169 +#: models.py:211 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:235 msgid "watch folder" msgstr "carpeta observada" -#: models.py:198 +#: models.py:240 msgid "Enter a valid value." msgstr "Introduzca un valor válido." -#: models.py:226 views.py:487 +#: models.py:268 views.py:581 msgid "order" msgstr "orden" -#: models.py:227 views.py:488 views.py:525 views.py:555 +#: models.py:269 views.py:582 views.py:619 views.py:649 msgid "transformation" msgstr "transformación" -#: models.py:228 views.py:489 +#: models.py:270 views.py:583 msgid "arguments" msgstr "argumentos" -#: models.py:228 +#: models.py:270 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Utilizar diccionarios para identificar argumentos, por ejemplo: %s" -#: models.py:239 +#: models.py:281 msgid "document source transformation" msgstr "transformación de fuente de documentos" -#: models.py:240 +#: models.py:282 msgid "document source transformations" msgstr "transformaciones de fuentes de documentos" -#: staging.py:42 +#: models.py:288 models.py:289 +msgid "out of process" +msgstr "" + +#: 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,195 @@ 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 "" -#: 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 "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 "" + +#: 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 "" + +#: 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 "Archivo provisional: %s, borrado exitosamente." -#: 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 "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 metadata" msgstr "Metadatos actuales" -#: views.py:265 views.py:284 +#: views.py:358 views.py:377 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "Error de transformación de archivo provisional: %(error)s" -#: views.py:307 +#: views.py:400 msgid "Staging file delete successfully." msgstr "Archivos provisional borrado exitosamente." -#: views.py:309 +#: views.py:402 #, python-format msgid "Staging file delete error; %s." msgstr "Error al borrar archivo provisional; %s." -#: views.py:368 +#: views.py:462 msgid "Source edited successfully" msgstr "Fuente editada exitosamente" -#: views.py:371 +#: views.py:465 #, python-format msgid "Error editing source; %s" msgstr "Error editando fuente; %s" -#: views.py:376 +#: views.py:470 #, 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:475 views.py:515 views.py:577 views.py:618 views.py:648 +#: views.py:691 msgid "source" msgstr "fuente" -#: views.py:410 +#: views.py:504 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Fuente \"%s\" borrada exitosamente." -#: views.py:412 +#: views.py:506 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Error borrando fuente \"%(source)s\": %(error)s" -#: views.py:419 +#: views.py:513 #, 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:545 msgid "Source created successfully" msgstr "Fuente creada exitosamente" -#: views.py:454 +#: views.py:548 #, python-format msgid "Error creating source; %s" msgstr "Error creando fuente; %s" -#: views.py:459 +#: views.py:553 #, python-format msgid "Create new source of type: %s" msgstr "Crear nuevo tipo de fuente: %s" -#: views.py:481 +#: views.py:575 #, python-format msgid "transformations for: %s" msgstr "transformaciones para: %s" -#: views.py:511 +#: views.py:605 msgid "Source transformation edited successfully" msgstr "Transformación de la fuente editada exitosamente" -#: views.py:514 +#: views.py:608 #, python-format msgid "Error editing source transformation; %s" msgstr "Error al editar la transformación de la fuente; %s" -#: views.py:519 +#: views.py:613 #, python-format msgid "Edit transformation: %s" msgstr "Editar transformación: %s" -#: views.py:542 +#: views.py:636 msgid "Source transformation deleted successfully." msgstr "Transformación de la fuente borrada exitosamente." -#: views.py:544 +#: views.py:638 #, 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:651 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -455,16 +511,16 @@ msgstr "" "¿Está seguro que desea eliminar la transformación de la fuente " "\"%(transformation)s\"" -#: views.py:587 +#: views.py:681 msgid "Source transformation created successfully" msgstr "Transformación de la fuente creado exitosamente" -#: views.py:590 +#: views.py:684 #, python-format msgid "Error creating source transformation; %s" msgstr "Error al crear la transformación de la fuente; %s" -#: views.py:599 +#: views.py:693 #, 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 index 3941752e44f67febee8c61051620ab689185f09c..1f5ed79f936ae25b9146102495424c4709402122 100644 GIT binary patch delta 2391 zcmY+_e@xVM9LMoDC;^utKSGj34haS2;0_RxUm;qM9zR4djSLP0b{lYYoLRJWbFpRF zAFQUWRo)%-cK`A_ac_#CESZYVI_Lg&FI=7HewL( z$5|}E1uVtun2G7G#P#`@XBM?$I(7V^0as%Lb>VZEg0EmM&LB6~EZ&3jcrPxZ7H|VK z(J#0jbM7|tpa-?ke%ykm@IH)T9`oBG9X;WXSdF)^0}IzACK^XA-QCwl=Oz&X@) zi;llyE615@&FI*RlFfrEb^}lR-6m|L={;EkFV5i zM(vpowH5uyHrtD+1BnT@}8G`*9H~abuLnVNUDBHXKCl z?FCe7KSM9xL|vE9V{5{4RLZxbimMOxL?@7sz2qF9LtXbSswl6ZGI7m0j;_$rjV>O$ z0W(p>=Eq%l4EN#(*o4WvJ0;kHO7RG4K@+I!j^j8kpfcp;UF0Xln(;8UqB3s~X;cx-qb~dkwb$7!Q+r>C<=BSW%LsPh94do^yI{3PC!H1}YET9JX8X41WpsM{ZR7!K$SWTRVD%Jv2v6Z6kt3=hz zPSkz-P_;DRID=8fvdeVz!*U(9!W4JH3}iPf4~x-<8n_QN(Ew^IMjVeJFIOQ*uMbsLJvza}i@ga-CGHeiyD3H?3{5=ynwpG>IY)s)7q@m}Jq&*^vL zQQ{#&MX1(J_~SjZ2OU*^@#0bzb`vTf6{DJpPfw%0?|GTQMtSBRD%3Krk$BS?uICO8=kO?dVMBE$9WDzER~>+0%#b=$l& zmp?EW@$`lR6O&_sNGM$I?gSW<(%J>W52DNb^Q%4so;qK delta 2418 zcmYk+e@vBC9LMo5hC&pm-1wnrJt*=+yvn^05fCaCqCjdW2L7PO3w9~EFu<1mbJdxD zsME1Kn>E_{z4)W$WXoF3T1!wxEhaRDSnD2_zR{pzRk}tqc8K}qv)VIT90ecMa}pO>dijG0=$WO zE_q?XLagVy5xHfjumayg7Rjbi{og=8-o@xDDn+b!5L-}hcm&nK3CzTE$oARCo)=L$ z@fG@T0@d+Ps4csL+RE(3W{hEZsFf;3ZDBdG=(c4s>#qlQ(I7ie$<&FONEr3Q2x>yF zAggAtqdJOVHjbet@(n5%en3s|HtP3(p?*JunotUFr5DP{Wc@WzJ`H-H2=zcEDkmCH zOSd1jXFaH`h@rOZOVorWQ4{|W)$vWw+c=eE_BU!m6U;7%-{B6tAEmO6$~Iny$ypRP z;|OYRe?~3sJuJheysn;WLJhbNwd4m;$#nwtLKl%g`<#EeKjpRm>0SSWO3r8&ucf5*&nD6#=lsISFh7{F`Z z^*yZ9`7dRZ$GPzmR^U7MBwj~$#}+cHIxIl#c?gvQ1E}M99<`@eumxvOE7-ukF@`mJ zhEXqi-17{kGQORs!dUh$YAG*!{;CJKPGbW#5g)39Vq^>pqOyKFYDv3L1BX#b8$l)A zVbt%ApmOIV>UX0URZ?A`B5xsMTBeiuzyweeX!GnucE`fF5|5!e{s=YD1=Lnt^1O=V znO#S%-0!HZxQiOEB%k%?WLO8OuD$C+4R{#U@iEWSn8dYKshikMsH`URMk;#}#FJ80 z^;hM!J&PJ}Zqe3l*8Z=cLXyVIHva20)DkR4JfpRwdOIbPigHCIoWNehr-=>3Mq+N! zYIP9IKVFnKDxBtc&S?DjH(QPK2xYiRd|y$k(X0l_PC{o~*{#IVo-5%TVn4w_uq}kX zq+LWEQB7z|Rg^P1L^+}D)9Hym&%Z{ZlV~G$5v@cMp{-HTu{lVz6D7o6qK4Q+C^6@j z7r4+KKSyW_D+ndEPSg%!A2D0_KD5OX#-*iz2zhtXQ3=yPJma+$d(N_m%6g*EYf#3k zDB%u_f08<#l+qtM)Ylyuj-AcO9Y2}&L27!y9|-t^K_?KX4pzo$e0dGD1pR?>r>u&W z(lSa~vpY2G-#O?;hI-xM{=sTzdr$Y^fZN~O@6@}!U2epw9hhxddm!F2{=V\n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,86 +18,74 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:14 -msgid "View existing document sources" -msgstr "Visualizza sorgenti documento esistente" - -#: __init__.py:15 -msgid "Edit document sources" -msgstr "Modifica sorgenti dei documenti" - -#: __init__.py:16 -msgid "Delete document sources" -msgstr "Cancella sorgenti dei documenti" - -#: __init__.py:17 -msgid "Create new document sources" -msgstr "Crea nuova sorgente dei documenti" - #: __init__.py:19 -msgid "Sources setup" -msgstr "Setup sorgente" - -#: __init__.py:25 msgid "preview" msgstr "anteprima" -#: __init__.py:26 __init__.py:34 __init__.py:40 +#: __init__.py:20 __init__.py:28 __init__.py:34 msgid "delete" msgstr "cancella" -#: __init__.py:28 +#: __init__.py:22 msgid "sources" msgstr "sorgenti" -#: __init__.py:29 literals.py:53 models.py:159 +#: __init__.py:23 literals.py:53 models.py:201 msgid "web forms" msgstr "web forms" -#: __init__.py:30 models.py:130 +#: __init__.py:24 models.py:172 msgid "staging folders" msgstr "cartelle per la gestione temporanea" -#: __init__.py:31 models.py:194 +#: __init__.py:25 models.py:236 msgid "watch folders" msgstr "cartelle di" -#: __init__.py:33 __init__.py:39 +#: __init__.py:27 __init__.py:33 msgid "edit" msgstr "modifica" -#: __init__.py:35 +#: __init__.py:29 msgid "add new source" msgstr "aggiungi una nuova sorgente" -#: __init__.py:37 +#: __init__.py:31 msgid "transformations" msgstr "trasformazioni" -#: __init__.py:38 +#: __init__.py:32 msgid "add transformation" msgstr "aggiungi una trasformazione" -#: __init__.py:42 +#: __init__.py:36 msgid "Document sources" msgstr "Sorgente del documento" -#: __init__.py:69 widgets.py:39 +#: __init__.py:38 +msgid "upload new version" +msgstr "" + +#: __init__.py:68 widgets.py:39 msgid "thumbnail" msgstr "thumbnail" -#: forms.py:32 forms.py:55 +#: forms.py:34 forms.py:59 msgid "Expand compressed files" msgstr "Espandi" -#: forms.py:33 forms.py:56 +#: 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:41 +#: 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" @@ -150,7 +138,7 @@ msgstr "Stampante" msgid "Empty printer" msgstr "Stampante vuota" -#: literals.py:47 models.py:158 +#: literals.py:47 models.py:200 msgid "web form" msgstr "web form" @@ -170,82 +158,82 @@ msgstr "server per la gestione temporanea delle cartelle" msgid "server watch folders" msgstr "server di salvataggio delle cartelle" -#: models.py:29 +#: models.py:36 msgid "title" msgstr "titolo" -#: models.py:30 +#: models.py:37 msgid "enabled" msgstr "abilitato" -#: models.py:31 +#: models.py:38 msgid "whitelist" msgstr "whitelist" -#: models.py:32 +#: models.py:39 msgid "blacklist" msgstr "blacklist" -#: models.py:98 +#: models.py:140 msgid "icon" msgstr "icona" -#: models.py:98 +#: models.py:140 msgid "An icon to visually distinguish this source." msgstr "Un'icona per distinguere visivamente questa fonte." -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "folder path" msgstr "path della cartella" -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "Server side filesystem path." msgstr "Path del server di filesystem" -#: models.py:115 +#: models.py:157 msgid "preview width" msgstr "anteprima larghezza" -#: models.py:115 +#: models.py:157 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:116 +#: models.py:158 msgid "preview height" msgstr "anteprima altezza" -#: models.py:116 +#: models.py:158 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:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "uncompress" msgstr "decomprimere" -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "Whether to expand or not compressed archives." msgstr "Se espandere o meno degli archivi compressi." -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "delete after upload" msgstr "cancella dopo il caricamento" -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "Delete the file after is has been successfully uploaded." msgstr "Cancella il file dopo essere stato caricato" -#: models.py:129 +#: models.py:171 msgid "staging folder" msgstr "Cartella di conservazione" -#: models.py:169 +#: models.py:211 msgid "interval" msgstr "intervallo" -#: models.py:169 +#: models.py:211 msgid "" "Inverval in seconds where the watch folder path is checked for new " "documents." @@ -253,50 +241,74 @@ msgstr "" "Invervallo di pochi secondi in cui viene controllato il percorso cartella di" " controllo per i nuovi documenti." -#: models.py:193 +#: models.py:235 msgid "watch folder" msgstr "controlla cartella" -#: models.py:198 +#: models.py:240 msgid "Enter a valid value." msgstr "Inserisci un valore valido" -#: models.py:226 views.py:487 +#: models.py:268 views.py:581 msgid "order" msgstr "ordine" -#: models.py:227 views.py:488 views.py:525 views.py:555 +#: models.py:269 views.py:582 views.py:619 views.py:649 msgid "transformation" msgstr "trasformazione" -#: models.py:228 views.py:489 +#: models.py:270 views.py:583 msgid "arguments" msgstr "argomenti" -#: models.py:228 +#: models.py:270 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Usa dei dizionari per identificare gli argomenti , esempio: %s" -#: models.py:239 +#: models.py:281 msgid "document source transformation" msgstr "trasformazione del documento sorgente" -#: models.py:240 +#: models.py:282 msgid "document source transformations" msgstr "trasformazioni dei documenti sorgente" -#: staging.py:42 +#: models.py:288 models.py:289 +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:127 +#: staging.py:129 #, python-format msgid "Unable to upload staging file: %s" msgstr "Impossibile caricare file di gestione temporanea: %s" -#: staging.py:137 +#: staging.py:139 #, python-format msgid "Unable to delete staging file: %s" msgstr "Impossibile eliminare file di gestione temporanea: %s" @@ -305,151 +317,195 @@ msgstr "Impossibile eliminare file di gestione temporanea: %s" msgid "Whitelist Blacklist validation error." msgstr "Errori di validazione nelle Whitelist e Blacklist." -#: views.py:80 +#: views.py:98 msgid "here" msgstr "qui" -#: views.py:85 +#: views.py:103 msgid "Upload sources" msgstr "Sorgenti caricamento" -#: views.py:87 +#: 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:88 +#: 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:136 -msgid "Document uploaded successfully." -msgstr "Documenti caricati con successo" +#: 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 "carica un documento in locale dalla sorgente: %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 "File in allestimento:%s, caricato con successo." -#: 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 "File in allestimento:%s, cancellato con successo." -#: 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 "carica documento dalla sorgente allestimento:%s" -#: views.py:215 +#: views.py:288 msgid "files in staging path" msgstr "path dei file in allestimento" -#: views.py:229 +#: views.py:320 msgid "Current metadata" msgstr "Metadati correnti" -#: views.py:265 views.py:284 +#: views.py:358 views.py:377 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "Errore nella trasformazione del file: %(error)s" -#: views.py:307 +#: views.py:400 msgid "Staging file delete successfully." msgstr "File in allestimento cancellato con successo." -#: views.py:309 +#: views.py:402 #, python-format msgid "Staging file delete error; %s." msgstr "Errore nella cancellazione del file in allestimento;%s." -#: views.py:368 +#: views.py:462 msgid "Source edited successfully" msgstr "Sorgente modificata con successo" -#: views.py:371 +#: views.py:465 #, python-format msgid "Error editing source; %s" msgstr "Errore nella modifica del sorgente;%s" -#: views.py:376 +#: views.py:470 #, python-format msgid "edit source: %s" msgstr "modifica sorgente:%s" -#: views.py:381 views.py:421 views.py:483 views.py:524 views.py:554 -#: views.py:597 +#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 +#: views.py:691 msgid "source" msgstr "sorgente" -#: views.py:410 +#: views.py:504 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Sorgente \"%s\" cancellata con successo." -#: views.py:412 +#: views.py:506 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Errore nella cancellazione della sorgente \"%(source)s\": %(error)s" -#: views.py:419 +#: views.py:513 #, python-format msgid "Are you sure you wish to delete the source: %s?" msgstr "Sei sicuro di voler cancellare la sorgente: %s?" -#: views.py:451 +#: views.py:545 msgid "Source created successfully" msgstr "Sorgente creata con successo" -#: views.py:454 +#: views.py:548 #, python-format msgid "Error creating source; %s" msgstr "Errore nella creazione della sorgente;%s" -#: views.py:459 +#: views.py:553 #, python-format msgid "Create new source of type: %s" msgstr "Crea nuovo tipo di sorgente:%s" -#: views.py:481 +#: views.py:575 #, python-format msgid "transformations for: %s" msgstr "trasformazione per: %s" -#: views.py:511 +#: views.py:605 msgid "Source transformation edited successfully" msgstr "Sorgente per la trasformazione modificata con successo" -#: views.py:514 +#: views.py:608 #, python-format msgid "Error editing source transformation; %s" msgstr "Errore nella modifica della sorgente per la trasformazione;%s" -#: views.py:519 +#: views.py:613 #, python-format msgid "Edit transformation: %s" msgstr "Modifica trasformazione:%s" -#: views.py:542 +#: views.py:636 msgid "Source transformation deleted successfully." msgstr "Sorgente per la trasformazione cancellata con successo." -#: views.py:544 +#: views.py:638 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "" "Erroro nella cancellazione della sorgente per la trasformazione; %(error)s" -#: views.py:557 +#: views.py:651 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -457,16 +513,16 @@ msgstr "" "Sei sicuro di voler cancellare la sorgente di trasformazione " "\"%(transformation)s\"" -#: views.py:587 +#: views.py:681 msgid "Source transformation created successfully" msgstr "Sorgente di trasformazione creata con successo" -#: views.py:590 +#: views.py:684 #, python-format msgid "Error creating source transformation; %s" msgstr "Errore nella creazione della sorgente di trasformazione; %s" -#: views.py:599 +#: views.py:693 #, python-format msgid "Create new transformation for source: %s" msgstr "Crea una nuova sorgente per la trasformazione:%s" diff --git a/apps/sources/locale/pt/LC_MESSAGES/django.mo b/apps/sources/locale/pt/LC_MESSAGES/django.mo index 242213a5baf74d56f9ba5a93f7d340425b101706..3ccd8d7c726cdd4f49c5747cb56e285c29e7a26a 100644 GIT binary patch delta 2441 zcmY+_du)?c7{~E580-Q9-G$r0b(;()>)MWO%x>TikXtukjET(2-p#JmZ0&5j7-nK6 zN}^5^l8HpKXo3;`L{beTBt#)5{xPS?5)+~+7-r%nfj_nw6BG6Od;4niWKTcmefwU{ zdCqgX^KGZvQkkOMvxXKX))8F`jd>m4T+9dU<9uV(y^OVZ75Cwf=tW#95>*7Ox4pVCEuFi9@GOmun2pRWium= zW2j8Mip4mNdhiEWj@MC3m_eRx?xHd^hg!lvkmMSdD|_8~7x~u>m7LHTZbS{lhq|!| zHK1)sa!fnwK|QzE3qFt=0`>&$z{|q&tuTc}aje5_|F7mGn?mHL!i7K*X zOkb(1My;72wG=(bGMiUW13H5m`1_~_Uv#{Tw{ncRh8oaWM(4*#JdD#=hm|R&qmduN z4je=`eu{Q+p-s`e@wrd~ zDMQsr1u9cM)PVM)Wse`l~a;2|eI0>c)A@L2Vh$w2#mdXp>;n*Xq}%TwAKFGnmACcX_^0N`MUK+e_$((HiDwCI z9~GvG?td-)MSdnHeX}r>zyCxsITG-C!;$2P(f+!D*swPqOIYzpEbbk)PFhiKB#{^m zB?=E7=<@7{hpc2I7WM43lA(aR-si9P`1I%YHw64!CW6If?f;%>4)~il`DlefE0Oec z#jR*!$V$fI0e5GtKNL^K(0-GYz3XPC zCY!n}4Vsw6#4Q?4bVga6?=kKMujFDXnTB2H4KYR&ahWE|{Qla<$O->`PM>`5{XQ%(CT1GwY~zD&bm5Dr8!zBSyo71^HRj9~Rq zmANb|!75Y+I`Kgq$1QjUtMGk%2!F)YJl~{c8N*m62RERF8fYhOMH@Bamr*PG2+Qym z>OR++q!rl0`!?hwa}Mk9H6%&qTh#bB(T#s&tej3I`SxKaYK5mz13Zt}IE`$ddE4p>-4&<&NS8|qOt zu?Lm9LDZg&qqZWB+Op436PiU${Cm{Ew;UJoa*8p3q9*hzv-9HX*o|{BI@NT_SdM1i zjr(y7Exd**u6fjh|3b2B*0XF)xEl3&6EC`i7~DG3>{72EhIbU3uN(T9yP!cYT$oR4^H8bD>DVC300zs%jaD8 zqbA&rde8vsv`nHh_AF`(-rY$4HM8%ypaFkzTtW@tvXWoS!xY|=SrZ`o2(>K)M>^34 z9Ge`KVr_?-PLwCn`~O8X@tF3%l#bG(c7V`C8VTl*Sd}uM)vMUl9!`?@kE!k`(MmKE zj}pt9R^Lx3%WB$IHD%GK4$n{gW~-k{RI5W%p>+{DiXDVn51|wA2%+uaKXsx|EgU4Y zb$bcb!Z5Le@DuD>qERl16H<#R;CdqVI4^C)F`}0^Oz4+sAHk1SqUjfFgm{9`{v9D2 zh+Tv#e0e+0n;PN}p(3m!%8Bj7LEo=- zM1^xvg{Y=NJ~8uN#zIPZXlQaG5RAspXBEzz%^b-n%j`PP-W{i8*++wB(8XTmWM0eDi1BQ!;VDVJz+Z-dD4!C!hS0-5eP>@!AQss z2O?JEaA2z1xfH*gb9_~Y9UPssM|r|i(Rga^z|6_q-KiT|ojHZ9KyYf@9u8SUp$RK8 QITVOQLe(=@^1E053l7WdNB{r; diff --git a/apps/sources/locale/pt/LC_MESSAGES/django.po b/apps/sources/locale/pt/LC_MESSAGES/django.po index 0e71ddee4e..8b6840a616 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-02 14:17-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" "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:201 msgid "web forms" msgstr "formulários web" -#: __init__.py:30 models.py:130 +#: __init__.py:24 models.py:172 msgid "staging folders" msgstr "staging folders" -#: __init__.py:31 models.py:194 +#: __init__.py:25 models.py:236 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:200 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:36 msgid "title" msgstr "título" -#: models.py:30 +#: models.py:37 msgid "enabled" msgstr "habilitado" -#: models.py:31 +#: models.py:38 msgid "whitelist" msgstr "lista branca" -#: models.py:32 +#: models.py:39 msgid "blacklist" msgstr "lista negra" -#: models.py:98 +#: models.py:140 msgid "icon" msgstr "ícone" -#: models.py:98 +#: models.py:140 msgid "An icon to visually distinguish this source." msgstr "Um ícone para distinguir visualmente essa fonte." -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "folder path" msgstr "caminho da pasta" -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "Server side filesystem path." msgstr "Caminho do sistema do servidor" -#: models.py:115 +#: models.py:157 msgid "preview width" msgstr "largura de visualização" -#: models.py:115 +#: models.py:157 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:158 msgid "preview height" msgstr "altura de visualização" -#: models.py:116 +#: models.py:158 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:159 models.py:196 models.py:209 msgid "uncompress" msgstr "descompactar" -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "Whether to expand or not compressed archives." msgstr "Se expandir ou não arquivos compactados." -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "delete after upload" msgstr "excluir após o upload" -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 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:171 msgid "staging folder" msgstr "preparação de pasta" -#: models.py:169 +#: models.py:211 msgid "interval" msgstr "intervalo" -#: models.py:169 +#: models.py:211 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:235 msgid "watch folder" msgstr "assistir pasta" -#: models.py:198 +#: models.py:240 msgid "Enter a valid value." msgstr "Digite um valor válido." -#: models.py:226 views.py:487 +#: models.py:268 views.py:581 msgid "order" msgstr "ordem" -#: models.py:227 views.py:488 views.py:525 views.py:555 +#: models.py:269 views.py:582 views.py:619 views.py:649 msgid "transformation" msgstr "transformação" -#: models.py:228 views.py:489 +#: models.py:270 views.py:583 msgid "arguments" msgstr "argumentos" -#: models.py:228 +#: models.py:270 #, 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:281 msgid "document source transformation" msgstr "transformação do documento de origem" -#: models.py:240 +#: models.py:282 msgid "document source transformations" msgstr "fonte de transformações de documentos" -#: staging.py:42 +#: models.py:288 models.py:289 +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,195 @@ 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 metadata" msgstr "Metadados atuais" -#: views.py:265 views.py:284 +#: views.py:358 views.py:377 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "Staging file transformation error: %(error)s" -#: views.py:307 +#: views.py:400 msgid "Staging file delete successfully." msgstr "Staging file delete successfully." -#: views.py:309 +#: views.py:402 #, python-format msgid "Staging file delete error; %s." msgstr "Staging file delete error; %s." -#: views.py:368 +#: views.py:462 msgid "Source edited successfully" msgstr "Fonte editada com sucesso" -#: views.py:371 +#: views.py:465 #, python-format msgid "Error editing source; %s" msgstr "Erro ao editar fonte; %s" -#: views.py:376 +#: views.py:470 #, 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:475 views.py:515 views.py:577 views.py:618 views.py:648 +#: views.py:691 msgid "source" msgstr "fonte" -#: views.py:410 +#: views.py:504 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Fonte \"%s\" removida com sucesso." -#: views.py:412 +#: views.py:506 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Erro ao excluir fonte \" %(source)s \": %(error)s " -#: views.py:419 +#: views.py:513 #, 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:545 msgid "Source created successfully" msgstr "Fonte criada com sucesso" -#: views.py:454 +#: views.py:548 #, python-format msgid "Error creating source; %s" msgstr "Erro ao criar fonte; %s" -#: views.py:459 +#: views.py:553 #, python-format msgid "Create new source of type: %s" msgstr "Criar nova fonte do tipo: %s" -#: views.py:481 +#: views.py:575 #, python-format msgid "transformations for: %s" msgstr "transformações para: %s" -#: views.py:511 +#: views.py:605 msgid "Source transformation edited successfully" msgstr "Transformação de fonte alterado com sucesso" -#: views.py:514 +#: views.py:608 #, python-format msgid "Error editing source transformation; %s" msgstr "Erro ao editar transformação de fonte; %s" -#: views.py:519 +#: views.py:613 #, python-format msgid "Edit transformation: %s" msgstr "Editar transformação: %s" -#: views.py:542 +#: views.py:636 msgid "Source transformation deleted successfully." msgstr "Transformação de fonte excluída com sucesso." -#: views.py:544 +#: views.py:638 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "Erro ao deletar transformação de fonte; %(error)s " -#: views.py:557 +#: views.py:651 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -455,16 +512,18 @@ msgstr "" "Tem certeza de que deseja deletar a transformação de fonte \" " "%(transformation)s \"" -#: views.py:587 +#: views.py:681 msgid "Source transformation created successfully" msgstr "Transformação de fonte criada com sucesso" -#: views.py:590 +#: views.py:684 #, python-format msgid "Error creating source transformation; %s" msgstr "Erro ao criar a transformação de fonte; %s" -#: views.py:599 +#: views.py:693 #, 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 90fbdf8a30070758b6af4441302be89ea043bce9..7155e2b7493d109e0e28009cfdacafe6e71e21c8 100644 GIT binary patch delta 2452 zcmY+^T}+!*9LMpq(G3PTUJ9~T>4qC)TWJe8u2%a^Z$VB|1aAL5?7|BZ_4{j!$xiq`pVNouIWPZn z&U3rvla}~QzU>V|2@z|EK$g!dBKe012~BVIE@;>ZB$3U z;Yze;8RJAJYM>ohiWhJNj$;x1n`tVV;T%@t@7RFF*~yN2Q3H7f{rCc=<5#GReUIz# z9%|-=jBXWra5MUG3!cR?yo&spFS%sXzqv)_A^a89Q2O#@s>@I#Zbi-PIeZwep`M#g z`3LUicW#a`RLxPW!fqrP<}FnF@1YYv!wq;B;}uj2$+u>B0M$Sv=3^(aZ02;zAylS@ z(T*2T4PU`xoJ1|*4AQpw8I`Gfs3rUxNv_GuOFp+YkNoR}_1w@JmZApYM!mQVHK1A~ zIi>;CPzOGUXHWxq3AGn4V`8(S-k(6d|0!xfU!x{8i|S`SkNoR_yQv5ML2a_-Okb(n zh*~obYAHI9Wj5zf1GX1&gnIr*M%RY(_$=;X7A-g#r=kvWna=Cz z#ho~f)tJp_0$7jQL~o-qFolocEv&*kwzLMa4>iyxRL5tr4u{c$Q>ab)7wY}EowK40 z97K(%9o673k@5w-8aL99*vooKLlca1T&SGm##Pj@DCKO$umN?U}To2X6mJ}yG-SR2trG!RPfVnS(G zQRhnKLecW5G!rL@y@Zab$^pWks3rGPvP%A|sj*kg9zyHJo70ig+~G!oia4x*iK6Doy7C{ar;mzG9F6W*cq*IMi%G;@7Kl&TX%4zZn3%5)@E zwC*aLE_0aBj$SC*^(sN4iP%SIy#s{yK@Cw)SVS6ekcfM^JVmIK5XT9veHpQzPSdR@^-zZDHfqOM+R(CTxA z`}+ri{h7^80q34*(29j4ea?C-7W6tQ+@1=jTYnBumDf`};o^kW4n|`UO!VaNMUywmQ(c#bB7H+vPjIL%)N6%%G^&v+_M;>J c+K*-Xt-jEJ6{7p-z<7H>zHR*SioLo20SRCJ>Hq)$ delta 2467 zcmY+_eN5F=9LMp4TplDrc~CJdFG@o4e0jP73ML5%BnU_;2p2+N6IeWD&F!kFvuG6~ z{;~R}Rii&#>YcJosO2AF3;Nxy)rJl0pEl+{ZY`s&r}yXH+eT-6f3I_Y_jk|lJbce# zrtarD_fm{)(onjItweLMF=O~{C>P3HxG}2U!8Ek+0RDxUSh3a^s^%mX;~7lAS$qr^ zF$Gs}113iJpLgJ9W89{Qijyzu(T1<19vsJQ_&$ctREH-p8E<1e?>G0Us6pF0|46rD4xe{m4K|@(^dYJv9<0VsF$_cbQZpBY ziI|F-ff{@idvF(?!&LkPpTxTu$@@)6lrgkrV)1dbqZ%r~G<2bQ{03@dH!unBp`Np? z_q!9H=5qz|l^Mfayo5}W`4-jwBBtXX=zfAqGV|@g8q^3+qZ+t?F*u1VpP34H4V4qO zFcxp48vX&bWDikGxhdKh-eD3@GnI;3!W?AMO=UFmuLm2sA&;PvsTI|cZqyI^P#qdU zX3d;OH8g>n@MBa*zCh)|cc>07qkjJY_4^f6hr$?@2DCYb`PYjQxuFM=Q4i#!a$-Mf z>W-n-tOvCe6R0Ko4Ar4IRL8$ZHGD7NGA;%g^DFB41$x(nckvYFxEV$rl`E(htYJ9g zn1&@div{>MHef!zQWA}!W?&lga2|6pINsk8C#s`+F&leO9e4*zaVl`%y-Y>fn!sLB zLj|ar=tXtx6sq9`Jcz-hbSu_l3wp2=qiIAhJcOFDS5O^2kFVlYq>rYEt)lkp@n!A* z_P~uFkw0^v%XSRs^w0s4$|VCUaSxtE&CE2G;_s*zJITNu*oNhJ4m0r^Jc57XZfx4- zKW`?nMf-n&$^pJev-?N*5{~luE7b0&Vvh~si>U4P3zvEfrFi4X+FRx-fw29?8130!N?c#+prklLe1Dbx*b%0qw*A{?DUVYJ>WT1Lm#1DJdHeRzDD|J9t7^k z(VCu1MlGQ;U?cKp2DqrBm+&ZF#X}gG!u+ejHjXt-?FEd+DOAsIqLStg2B8}7B$@~n z&6=K9QNt=)V-+1RPG8NKXHhe@x@c+2wf-y{{|Nj=8NQy-G?5m*!y^Pk39X@uc8N;2 zAJc_pL@BYCSY5QvNN6(w8=K@R$gc7Tc!t=)4ud?_fbzhk(!vu|kP&8T?KYZ1r8lOk#lHl*(x=yVPB z^!KHgxrRCm?T)PM>~#Jd4tsWXp(B5yC^o_AyOWh`&(14!, 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 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-02 14:17-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" "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:201 msgid "web forms" msgstr "web-формы" -#: __init__.py:30 models.py:130 +#: __init__.py:24 models.py:172 msgid "staging folders" msgstr "транспортные папки" -#: __init__.py:31 models.py:194 +#: __init__.py:25 models.py:236 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 "Загрузить файлы, содержащиеся в архиве в качестве отдельных документов" +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 +139,7 @@ msgstr "Принтер" msgid "Empty printer" msgstr "Пустой принтер" -#: literals.py:47 models.py:158 +#: literals.py:47 models.py:200 msgid "web form" msgstr "веб-формы" @@ -172,128 +159,153 @@ msgstr "папки на промежуточном сервере" msgid "server watch folders" msgstr "наблюдаемые папки" -#: models.py:29 +#: models.py:36 msgid "title" msgstr "название" -#: models.py:30 +#: models.py:37 msgid "enabled" msgstr "разрешено" -#: models.py:31 +#: models.py:38 msgid "whitelist" msgstr "белый список" -#: models.py:32 +#: models.py:39 msgid "blacklist" msgstr "черный список" -#: models.py:98 +#: models.py:140 msgid "icon" msgstr "иконка" -#: models.py:98 +#: models.py:140 msgid "An icon to visually distinguish this source." msgstr "Значок, чтобы визуально отличать этот источник." -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "folder path" msgstr "путь к папке" -#: models.py:114 models.py:166 +#: models.py:156 models.py:208 msgid "Server side filesystem path." msgstr "Путь на сервере" -#: models.py:115 +#: models.py:157 msgid "preview width" msgstr "ширина предпросмотра" -#: models.py:115 +#: models.py:157 msgid "Width value to be passed to the converter backend." msgstr "Ширина после обработки." -#: models.py:116 +#: models.py:158 msgid "preview height" msgstr "Предварительный просмотр высоты" -#: models.py:116 +#: models.py:158 msgid "Height value to be passed to the converter backend." msgstr "Высота после обработки." -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "uncompress" msgstr "распаковать" -#: models.py:117 models.py:154 models.py:167 +#: models.py:159 models.py:196 models.py:209 msgid "Whether to expand or not compressed archives." msgstr "Независимо от того распакованы или нет архивы." -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "delete after upload" msgstr "удалить после загрузки" -#: models.py:118 models.py:168 +#: models.py:160 models.py:210 msgid "Delete the file after is has been successfully uploaded." msgstr "Удалить файл после загрузки." -#: models.py:129 +#: models.py:171 msgid "staging folder" msgstr "промежуточная папка" -#: models.py:169 +#: models.py:211 msgid "interval" msgstr "интервал" -#: models.py:169 +#: models.py:211 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 "" "Интервал в секундах, между проверками папки на появление новых документов." -#: models.py:193 +#: models.py:235 msgid "watch folder" msgstr "просматривать папку" -#: models.py:198 +#: models.py:240 msgid "Enter a valid value." msgstr "Введите допустимое значение." -#: models.py:226 views.py:487 +#: models.py:268 views.py:581 msgid "order" msgstr "порядок" -#: models.py:227 views.py:488 views.py:525 views.py:555 +#: models.py:269 views.py:582 views.py:619 views.py:649 msgid "transformation" msgstr "преобразование" -#: models.py:228 views.py:489 +#: models.py:270 views.py:583 msgid "arguments" msgstr "аргументы" -#: models.py:228 +#: models.py:270 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Использование словарей для определения аргументов, например: %s" -#: models.py:239 +#: models.py:281 msgid "document source transformation" msgstr "преобразования источника документов" -#: models.py:240 +#: models.py:282 msgid "document source transformations" msgstr "преобразования источника документов" -#: staging.py:42 +#: models.py:288 models.py:289 +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 +314,212 @@ 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, чтобы добавить или включить какой-нибудь документ " "источников." -#: 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 "" + +#: 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 "загрузить локальный документ из источника: %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 "Промежуточный файл %s загружен." -#: 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 "Постановка файл %s успешно удален." -#: 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 "загрузить документ из промежуточного источника %s" -#: views.py:215 +#: views.py:288 msgid "files in staging path" msgstr " файлы в транспортном пути" -#: views.py:229 +#: views.py:320 msgid "Current metadata" msgstr "Действующие метаданные" -#: views.py:265 views.py:284 +#: views.py:358 views.py:377 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "Ошибка преобразования транспортного файла: %(error)s" -#: views.py:307 +#: views.py:400 msgid "Staging file delete successfully." msgstr "Транспортный файл удалён." -#: views.py:309 +#: views.py:402 #, python-format msgid "Staging file delete error; %s." msgstr "Ошибка удаления транспортного файла %s." -#: views.py:368 +#: views.py:462 msgid "Source edited successfully" msgstr "Источник успешно изменен" -#: views.py:371 +#: views.py:465 #, python-format msgid "Error editing source; %s" msgstr "Ошибка редактирования источника; %s" -#: views.py:376 +#: views.py:470 #, 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:475 views.py:515 views.py:577 views.py:618 views.py:648 +#: views.py:691 msgid "source" msgstr "источник" -#: views.py:410 +#: views.py:504 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Источник \"%s\"удален." -#: views.py:412 +#: views.py:506 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Ошибка при удалении источника \"%(source)s\": %(error)s" -#: views.py:419 +#: views.py:513 #, python-format msgid "Are you sure you wish to delete the source: %s?" msgstr "Вы действительно хотите удалить источник: %s?" -#: views.py:451 +#: views.py:545 msgid "Source created successfully" msgstr "Источник создан" -#: views.py:454 +#: views.py:548 #, python-format msgid "Error creating source; %s" msgstr "Ошибка создания источника; %s" -#: views.py:459 +#: views.py:553 #, python-format msgid "Create new source of type: %s" msgstr "Создать новый источник типа: %s" -#: views.py:481 +#: views.py:575 #, python-format msgid "transformations for: %s" msgstr "преобразования для: %s" -#: views.py:511 +#: views.py:605 msgid "Source transformation edited successfully" msgstr "Преобразование источника изменено" -#: views.py:514 +#: views.py:608 #, python-format msgid "Error editing source transformation; %s" msgstr "Ошибка редактирования преобразования источника; %s" -#: views.py:519 +#: views.py:613 #, python-format msgid "Edit transformation: %s" msgstr "Изменить преобразование: %s" -#: views.py:542 +#: views.py:636 msgid "Source transformation deleted successfully." msgstr "Преобразование источника удалено." -#: views.py:544 +#: views.py:638 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "Ошибка при удалении преобразования источника; %(error)s" -#: views.py:557 +#: views.py:651 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" msgstr "" -"Вы действительно хотите удалить источник трансформации \"%(transformation)s\"" +"Вы действительно хотите удалить источник трансформации " +"\"%(transformation)s\"" -#: views.py:587 +#: views.py:681 msgid "Source transformation created successfully" msgstr "Преобразование источника создано" -#: views.py:590 +#: views.py:684 #, python-format msgid "Error creating source transformation; %s" msgstr "Ошибка создания преобразования источника; %s" -#: views.py:599 +#: views.py:693 #, python-format msgid "Create new transformation for source: %s" msgstr "Создать новое преобразование для источника: %s" + + diff --git a/apps/tags/locale/en/LC_MESSAGES/django.po b/apps/tags/locale/en/LC_MESSAGES/django.po index 3a71fb37af..cd16115144 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-02 14:17-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 +#: __init__.py:21 msgid "tag list" msgstr "" -#: __init__.py:29 +#: __init__.py:22 msgid "create new tag" msgstr "" -#: __init__.py:30 +#: __init__.py:23 msgid "attach tag" msgstr "" -#: __init__.py:31 __init__.py:32 +#: __init__.py:24 __init__.py:25 msgid "remove" msgstr "" -#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 +#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 msgid "tags" msgstr "" -#: __init__.py:34 __init__.py:37 +#: __init__.py:27 __init__.py:30 msgid "delete" msgstr "" -#: __init__.py:35 +#: __init__.py:28 msgid "edit" msgstr "" -#: __init__.py:36 +#: __init__.py:29 msgid "tagged documents" msgstr "" -#: __init__.py:41 models.py:46 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: __init__.py:35 models.py:13 msgid "color" msgstr "" -#: __init__.py:45 +#: __init__.py:39 msgid "color name" msgstr "" -#: forms.py:14 -msgid "New tag" +#: __init__.py:43 +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:153 views.py:205 views.py:219 msgid "tag" msgstr "" -#: models.py:49 +#: 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:129 views.py:256 msgid "Must provide at least one tag." msgstr "" -#: views.py:176 +#: views.py:144 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "" -#: views.py:178 views.py:294 +#: views.py:146 views.py:268 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" msgstr "" -#: views.py:193 +#: views.py:161 #, python-format msgid "Are you sure you wish to delete the tag: %s?" msgstr "" -#: views.py:194 views.py:197 +#: views.py:162 views.py:165 msgid "Will be removed from all documents." msgstr "" -#: views.py:196 +#: views.py:164 #, python-format msgid "Are you sure you wish to delete the tags: %s?" msgstr "" -#: views.py:221 +#: views.py:193 msgid "Tag updated succesfully." msgstr "" -#: views.py:230 +#: views.py:202 #, python-format msgid "edit tag: %s" msgstr "" -#: views.py:245 +#: views.py:216 #, python-format msgid "documents with the tag \"%s\"" msgstr "" -#: views.py:258 +#: views.py:235 #, python-format msgid "tags for: %s" msgstr "" -#: views.py:292 +#: views.py:266 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "" -#: views.py:308 +#: views.py:282 #, python-format msgid "Are you sure you wish to remove the tag: %s?" msgstr "" -#: views.py:310 +#: views.py:284 #, 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 36248389b687e51794226f8cbb7bbe04256ce86e..a451381c2c1e4a183856693e0e6ea641894085d9 100644 GIT binary patch delta 1334 zcmX}rOGs2v9LMov>6p`uR+IKHbu4R29p{l?4nl$!MGq@1ENXF$NriG^<{AZ|3kzvB z5r+_=2W`rzMd6~LMeS-+i*gY}5n&Wjt0-vK_cz`;+%uo^zmN0ypEF;>v(;lCmK9$$ zlq7Wx^?s2tUD&aZAIgqmV?wwSoADS%G4I8Xz4$Y7nNW!_TxO+bEmjaWpq{tlT5QLN zF=OT^jQ}?;AeXtqPZ>^PDc-_byo>7K1^VzMYL2tG8sB0a{zSbW;w70xEnq*c#I)xq z7Bjw?q_K_%*O1FRU=4AeG-=zWu?^pOafsO~-j3>L6t#eH z&r4WEd>O~|!fhH6yoc)W4QhqH#q%FlBDYL6GPc=(%2*3(PmmokEmZw`R5Xx^ z4yE>6g#{Nfqsc_6`nH)`qy5(@ZK7&`N~($mi4|J&6H?lAxU^0GN`l75e*tcw#=ThC zWNw9`%qdISTBUsxRoknwM`>2k{wjryRAnSgRnb1Hkio*CSyhPU)2uC6K&_`LoyL}w zys}?PBDUVQ&K~qdY~I&sKl|!zpfqmBOK;A!FX}AXHR!shQ?b~x!g!P=ik@U8|})b9d{@*9PM`8bSj*TCz8>)u5h9?m1wiq%c?j3 zzq2KkXm5&B{JWi;8|}?H!?}}=o5`la2QvNXtee5YNOrDl+`9fFf!)sVz=$(I*Xi8M mOMiWl^#_{mp};0P6-e5TfvD{aM(mm3R$Ed2bmn{c`J%u5=94Y} literal 4200 zcmchZUu+yl9mfYSkeIeW+7f68Obw}Rn!P)lG^Ce?;@U21S~pQ*f{=>P_;!3=v$x~S z?Ao~qkXjy)`iO*p2OjbONC<=wAn}Goc|ZaI5=aOhPZ3=hMv z!8gNi!Vdf{d=GpXiv9o8->2xrqq+-Z#*YDsv z;a_V`9jfLz4&TB18TdZ*~{{p;+_805+4JhNj4UfU^L-FHR zQ2hUG{ryi+{P+vxPu=84?7RX+zbV9#{`W%}KU247q3C}K{(wDRfyZh8n?)|dqi<2_ zL-0J5_6v3Uhfvn@Hz@WFV_f{Wr{;Z7{C@z-_XQ|Ao`$pV3Vav*92C1>f%n0mLs|FB zQ0)C3ie9fkBrZ2!`X3?)MAx%W^!XH&ahp*36;S5=ER=pPzz@Q2z!UHfHD!=|e+a%G zo`gwpRZC~78_}&p zeUK_e_EpLPRWz3U)>J}GJxZ0hP)l*FbJN$k)3NIn1DoY)$y+^ig$_miu$P3bvWHD= zZgsvzHT|wW5gxzO&fzw_y&bsSJ2kz(b7MNsO>axvYe`5l95Vf&o=6L;mR;&Rzuu&3 z*;|7Lncb^8EDuelRw}ppsoOAV^?s$+LMK6+ltJ-OKJ;y@P0%wZ!i-vtlUz@ZS@qs| z9gDGg0d$;W)O?u1`#CG$=Yv{hg-ws3KI*N_qEFZ~b$jaRE%WI_J(Kjea^4Tsn(4D4 zMy(Yg*S#(0g4H%bf3HpBgl1Bcm4262U1nR=fF194lh|sL>(m-7@JYOAsb|f=s%I+^ z)CF&{zEziOOs#eS?ewO1gHcQbwN8+T-`d2nsE|=h#c711*RvsP7HK+cy}IW?A8#|b z)bU{3RS3M+)XjEDAmpK1POsedruW1;i=CKwxb;I&R}$ngBLQYZ6&N2+(o}C)-OOLA zWO&z{9%igJvyw-KsqrJnNKS(4l|fnl>P&W{T4J-QO;ZL}N~qBUdXETb4q+9GmRMBs zBeRwEtMw@vPt_?}ln=zjj`ewBgES?cM|PVRNp1(_*Xl=aI$xTkf6x=-FM79adwKL! z99^+KBrfafHN%0@t1D}lr!UzZ=ksVS^piMxqUeWc9oMHXURaOHQ%L`41@XIjv9quc z@wd3B7Z$pUr=!lPPKS=sCA-UEzNKI1lbvZ^N$vHI^amzMTRk`UFvGKc!7+>0tr>LnZaWc8;aC4ej}n@vgREdhMyT)v;0w ztA`&#tkE`221&-al;?V=1jXZbFoYW@<(xGd!ETU&g7;_%gZO zdi|&>&GEU86eWp{tW8ii$3jWUN^ESn$tFKc&fIiH7-f9^(sz1==rj4cc@CqwNQMM- Ksl)+O1odB8U{Ig{ diff --git a/apps/tags/locale/es/LC_MESSAGES/django.po b/apps/tags/locale/es/LC_MESSAGES/django.po index 1bd56cabd7..06404c5505 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. 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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:19+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 +#: __init__.py:21 msgid "tag list" msgstr "lista de etiquetas" -#: __init__.py:29 +#: __init__.py:22 msgid "create new tag" msgstr "crear nueva etiqueta" -#: __init__.py:30 +#: __init__.py:23 msgid "attach tag" msgstr "adjuntar etiqueta" -#: __init__.py:31 __init__.py:32 +#: __init__.py:24 __init__.py:25 msgid "remove" msgstr "remover" -#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 +#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 msgid "tags" msgstr "etiquetas" -#: __init__.py:34 __init__.py:37 +#: __init__.py:27 __init__.py:30 msgid "delete" msgstr "eliminar" -#: __init__.py:35 +#: __init__.py:28 msgid "edit" msgstr "editar" -#: __init__.py:36 +#: __init__.py:29 msgid "tagged documents" msgstr "documentos etiquetados" -#: __init__.py:41 models.py:46 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: __init__.py:35 models.py:13 msgid "color" msgstr "color" -#: __init__.py:45 +#: __init__.py:39 msgid "color name" msgstr "nombre del color" -#: forms.py:14 -msgid "New tag" -msgstr "Nueva etiqueta" +#: __init__.py:43 +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:153 views.py:205 views.py:219 msgid "tag" msgstr "etiqueta" -#: models.py:49 +#: 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 "" + +#: 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 "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:129 views.py:256 msgid "Must provide at least one tag." msgstr "Debe proveer al menos una etiqueta." -#: views.py:176 +#: views.py:144 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Etiqueta \"%s\" borrada exitosamente." -#: views.py:178 views.py:294 +#: views.py:146 views.py:268 #, 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:161 #, 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:162 views.py:165 msgid "Will be removed from all documents." msgstr "Se removerá de todos los documentos." -#: views.py:196 +#: views.py:164 #, 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:193 msgid "Tag updated succesfully." msgstr "Etiqueta actualizada exitosamente." -#: views.py:230 +#: views.py:202 #, python-format msgid "edit tag: %s" msgstr "editar la etiqueta: %s" -#: views.py:245 +#: views.py:216 #, python-format msgid "documents with the tag \"%s\"" msgstr "documentos con la etiqueta \"%s\"" -#: views.py:258 +#: views.py:235 #, python-format msgid "tags for: %s" msgstr "etiquetas para: %s" -#: views.py:292 +#: views.py:266 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Etiqueta \"%s\" removida exitosamente." -#: views.py:308 +#: views.py:282 #, 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:284 #, 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 index e7c323701a9f190dba53036ae784466638a28df0..8c6c87fca7202f1f46a444735ed9d71c2ec1839d 100644 GIT binary patch delta 1273 zcmX}rUr3Wt7{~Fm+NRCTnUklFGBJ08k zikI*vvMw@$ph$u)x`=KPqKK%Fpdd(su7c>Ii>U8!zIJ%eKIgpeyK|oNobx^ie`=ii zTV20ndvNz!ekgn0#?;_G?8M_3#Tlpn#OW_1m#Og>!)59nn=weg4fQ;M zTQG?cW2Vd~4L>)gk;`1;XC2OB8Q#WbyoVZK5xw{d72`W>z$I+KpQ!h1cuB@l3pj-J zm~kwkoB7QwjaDAqKrZu)A0NKJ_4pPU(|mRAf5%Gtzns3CC~2A?HexL*&^T&gea`a% zRKSB+jzd_<{N^Z)Dm;by!#UId7oGkLDuuK7f$h1AVfsbVl)zh4ilcd!?ikjn%sR#x7C0s0}-09_cuUep95s4W{sW$L8!d>q^8 zU%?1Ia{3=p0sO5X|4lUNShiNwgBoZAbx6{v0H;xVco{e1oOAy%GM0IY+S^6c)_g&w z_y_6?{C4{FtU?oqQ42{1$iF7+=Y|FzL=BX7`sW?5qTZWFor#C2L-!on5z|H0*Q26< zRrK8Xh)O{!Q#zngs^;jVHfjGAVFy(cCdsPYC1Ryfhf8T(EioF~S39_ks(n{c z_K2-i6tK>hwpdx*K~B`}NI{AOoVm85NPuzz!3hLC@eoLW;QMnnAsuD>*%{By%>O^* zeABl!Q2(~O`BjJV0QGL_Z%vLfhc|ZfK}jYYCyje>6#FrY55?`}xP28h?n`XOACN!i zR_rg>Mf*?G_sJH=>2{pD)4{_a9R}~f8O-3L*nt;K05Jt zR0f+#kH+_)-XDzH8PpMs<4unFB-RJ$*q5RcCvh5|LZ$Rt>;`H>NoLiAL#U08AjxoY z*o#wf|7jee{TLSTBI^A$oW$#>jPB|n|4Pw*4qB-hK%IGp4^2FQn&3e+_zY?Tmr;?t zh6LeUL%shI8vGcK;sy?5E9udOvY5d$aeGDi*UsOeqaQy(W#ntr#D8EOn^;YkbPN^w zJSu{7*n^94|0N_@&P%Af@)k0MvyM8d&ro;kdffi0&Vx4aD=Oj?2dIV9sEPYg6OF~~ zhhxv9#x0{R*DC5(zk*Gu_ox6S=Dhfo$aEv-i<#g(e^CkF3IT|bOqU!8a z^t0Sqbcs}ScXXagxzennd!VAMD6=`Lj#NcQsG=j)arEmJ86LQh&T;C&Xtw$D^ocNZ ziwnjsdx2Lio6s!>QFr3dUR$xDHRXzb-mPr*P9=uBN?v$d-`T`S`z)`9@w?G#V)Srv z!S@4etQRiWCF7c^eO5CVpGLK@Qe(JZwMU{462q;hHouQ~>3~ zXrSdl^mpRj^t{I?*OdHX?P*&LGl2=$-)LEFn#gDK`D~$J^7-k)WHvXR%e9@J%bu|p z2*|HyPr9L9WAGk}NzqDRU{?pVq<5w!S>>3+-#RW@N zj135kwQRK5Ha;}tR*SY$aaWjiD>2rT=*n!pVx#xk#`_-eOWu=S(KTT$B!v|+5l?BO zjkc-u>{e@g0Wa!IWwSximMflJvZhugX*K`C&dvCZ-v75Wk;-(Px_wM^HZ^%-bL)e{ z!Ju)=Wv^CMAjWOP#$(a1nxIxJ+92?qt(~}L$N1<\n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,245 +19,227 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:13 -msgid "Create new tags" -msgstr "Crea un nuova etichetta" - -#: __init__.py:14 -msgid "Attach exising tags" -msgstr "Collega etichetta esistente" - -#: __init__.py:15 -msgid "Remove tags from documents" -msgstr "Rimuovi etichetta dal documento" - -#: __init__.py:16 -msgid "Delete global tags" -msgstr "Cancellazione globale dell'etichette" - -#: __init__.py:17 -msgid "Edit global tags" -msgstr "Modifica tutte le etichette" - -#: __init__.py:18 -msgid "View a document's tags" -msgstr "Visualizza tutti i documenti con questa etichetta" - -#: __init__.py:20 -msgid "Tags" -msgstr "Etichette" - -#: __init__.py:28 +#: __init__.py:21 msgid "tag list" msgstr "lista delle etichette" -#: __init__.py:29 +#: __init__.py:22 msgid "create new tag" msgstr "crea una nuova etichetta" -#: __init__.py:30 +#: __init__.py:23 msgid "attach tag" msgstr "allega un'etichetta" -#: __init__.py:31 __init__.py:32 +#: __init__.py:24 __init__.py:25 msgid "remove" msgstr "rimuovi" -#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 +#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 msgid "tags" msgstr "etichette" -#: __init__.py:34 __init__.py:37 +#: __init__.py:27 __init__.py:30 msgid "delete" msgstr "cancella" -#: __init__.py:35 +#: __init__.py:28 msgid "edit" msgstr "modifica" -#: __init__.py:36 +#: __init__.py:29 msgid "tagged documents" msgstr "documenti etichettati" -#: __init__.py:41 models.py:46 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: __init__.py:35 models.py:13 msgid "color" msgstr "colore" -#: __init__.py:45 +#: __init__.py:39 msgid "color name" msgstr "nome colore" -#: forms.py:14 -msgid "New tag" -msgstr "Nuova etichetta" +#: __init__.py:43 +msgid "tagged items" +msgstr "articoli etichettati." -#: forms.py:15 forms.py:24 -msgid "Color" -msgstr "Colori" - -#: forms.py:16 -msgid "Existing tags" -msgstr "Etichette esistenti" - -#: forms.py:23 +#: forms.py:24 msgid "Name" msgstr "Nome" -#: models.py:18 +#: forms.py:25 +msgid "Color" +msgstr "Colori" + +#: forms.py:42 permissions.py:7 +msgid "Tags" +msgstr "Etichette" + +#: literals.py:18 msgid "Blue" msgstr "Blue" -#: models.py:19 +#: literals.py:19 msgid "Cyan" msgstr "Ciaono" -#: models.py:20 +#: literals.py:20 msgid "Coral" msgstr "Corallo" -#: models.py:21 +#: literals.py:21 msgid "Green-Yellow" msgstr "Verdognolo" -#: models.py:22 +#: literals.py:22 msgid "Khaki" msgstr "Khaki" -#: models.py:23 +#: literals.py:23 msgid "LightGrey" msgstr "Grigio chiaro" -#: models.py:24 +#: literals.py:24 msgid "Magenta" msgstr "Magenta" -#: models.py:25 +#: literals.py:25 msgid "Red" msgstr "Rosso" -#: models.py:26 +#: literals.py:26 msgid "Orange" msgstr "Arancione" -#: models.py:27 +#: literals.py:27 msgid "Yellow" msgstr "Giallo" -#: models.py:45 views.py:185 views.py:233 views.py:248 +#: models.py:12 views.py:153 views.py:205 views.py:219 msgid "tag" msgstr "etichetta" -#: models.py:49 +#: models.py:16 msgid "tag properties" msgstr "proprità dell'etichetta" -#: models.py:50 +#: models.py:17 msgid "tags properties" msgstr "proprietà delle etichette" -#: views.py:33 +#: 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:40 +#: views.py:50 msgid "Tag created succesfully." msgstr "Etichetta creata con successo" -#: views.py:46 +#: views.py:56 msgid "create tag" msgstr "crea etichetta" -#: views.py:73 views.py:112 -msgid "Must choose either a new tag or an existing one." -msgstr "Devi scegliere una nuova etichetta o una esistente" - -#: views.py:77 views.py:116 +#: views.py:77 #, python-format msgid "Document is already tagged as \"%s\"" msgstr "Il documento è giià stato etichettato come \"%s\"." -#: views.py:86 -#, python-format -msgid "Tag \"%s\" added successfully." -msgstr "Etichetta \"%s\" aggiunta con successo." - -#: views.py:124 -#, python-format -msgid "Tag \"%s\" added and attached successfully." -msgstr "Etichetta \"%s\" aggiunta e allegata con successo" - -#: views.py:126 +#: views.py:82 #, python-format msgid "Tag \"%s\" attached successfully." msgstr "Eticetta \"%s\" allegata con successo." -#: views.py:133 +#: views.py:88 #, python-format msgid "attach tag to: %s" msgstr "allega etichetta a:%s" -#: views.py:149 -msgid "tagged items" -msgstr "articoli etichettati." - -#: views.py:166 views.py:280 +#: views.py:129 views.py:256 msgid "Must provide at least one tag." msgstr "Devi fornire almeno un'etichetta" -#: views.py:176 +#: views.py:144 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Etichetta \"%s\" cancellata con successo." -#: views.py:178 views.py:294 +#: views.py:146 views.py:268 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" msgstr "Errore nel cancellare l'etichetta \"%(tag)s\": %(error)s" -#: views.py:193 +#: views.py:161 #, python-format msgid "Are you sure you wish to delete the tag: %s?" msgstr "Sei sicuro di voler cancellare questa etichetta: %s?" -#: views.py:194 views.py:197 +#: views.py:162 views.py:165 msgid "Will be removed from all documents." msgstr "Sarà rimossa da tutti i documenti" -#: views.py:196 +#: views.py:164 #, 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:221 +#: views.py:193 msgid "Tag updated succesfully." msgstr "Etichetta aggiornata con successo" -#: views.py:230 +#: views.py:202 #, python-format msgid "edit tag: %s" msgstr "modifica l'etichetta:%s" -#: views.py:245 +#: views.py:216 #, python-format msgid "documents with the tag \"%s\"" msgstr "documenti con l'etichetta \"%s\"" -#: views.py:258 +#: views.py:235 #, python-format msgid "tags for: %s" msgstr "etichette per: %s" -#: views.py:292 +#: views.py:266 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Etichetta \"%s\" rimossa con successo." -#: views.py:308 +#: views.py:282 #, python-format msgid "Are you sure you wish to remove the tag: %s?" msgstr "Sei sicuro di voler rimuovere le etichetta: %s ?" -#: views.py:310 +#: views.py:284 #, python-format msgid "Are you sure you wish to remove the tags: %s?" msgstr "Sei sicuro di voler rimuovere le etichette: %s ?" diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.mo b/apps/tags/locale/pt/LC_MESSAGES/django.mo index db86c8cc36bd83b989e2ba849e1e37d9f03ea8f9..992d243914f4ba7cbe184e0cb3bbf1c4211edb88 100644 GIT binary patch delta 1359 zcmYk*OK1~89LMpACaKM%RjajHwP~wH+opLaYJ-Sk5hWGhAX33?4Y8<+CMjr@7Ev!f z2r@`fEY*t-@F4Ueh#(ZygL;r2^y0}Pcr7Xv4}O1f5r>)m?96Uq z;0!Ln{aC~N<`_2%F^BrWMbrmwxcyO72*>a<>3M`}=wBsFNqmT#@sr!HW%V2B??ioP z5H;}-Y9qtA6tClm2JUjR7Vl#MUt<`5p`QDK#!yX=3v-)gxDK086YO@!GpL;%Mx~+` zmFp|02v4|9;S&1ag2Z2k?l%JwT+a5D`!s5TZq$TlP!TAhR(=h&qdUk?%{VH@Pf)3O ziTd3;)ESsYrDzuQ-kkfqCQSUb;(E5b7@JUsB!%^uL4B|fwXh4Q_b%gdyoqGQbkejD z6-}g~L#aioXpxGPq7tKNjt<%?T<`}P0z6)~kx zMPX-cm7+te^QFJIcE5q9O{wft-c?9-B`0mDh(u^A%9{!it3*V*R#7^1Hs;ZqX$rTo zKHmrX%@?)J{#JX`AGM?YHap{QvZ1Pky;e0b*|lJYCv&=7KA(=qa|7kmgMFR-g>&&@ zq2v??3dQ(2=aQ3;50pxS*;3%Z{v)wn#jH~vDCA?^PC1*7q!P(gETI}nZb~P&*zxMd zeg8(brjuRm2}+>HDV1YKicY?C)+rZ?>Byl%U$$5-U}dJrw&LG`PIv0gTp>T?oXrl| zpVcRAf8cnq$I0ggog9;%pL`K$@z}Xwo82CY+Tl>bPK9DN8jjlD@OC>Jelhv3=9K3T D*esnh literal 4144 zcma);ON<;x8Gwsq0echkNJzrVNqH0FUE-d{;sj@m<7{>}$l$e&GZ-P6L%F+lwoOmh zq^o-$1`fah35g35APz)|0t$+vaNvSCA^939LP5#}ArKNoBqtzJA|&AZ`!O?)S=Obk z{-(OC{#X4~|Nh~QnI974oOvsQGvJe#UP>`M&QxO5Fhuz&WVl2jDV10{id){5rfHeiw?oAHn_bC-A-S zIoN@}fcL^bLXrQU`uhx%_^ED(;?kY)qwpTM02iV7eF@$Ncc94mam`;r@#|IiVfcE@ znSGU>gYa(N&%yiQBT)2x1hFJo;>T-{KlKI=k@F^$_{|U;nSU3Q^>g+32$c9AgU_rlgQLqel|3J<~;q3C}JioSn9iQ~VZ_A#z)Eu}_-VC%!dpfghiwAE)=|a%V`Byla}o z^g+7hu-Gk4{E%GxH2o-@ttj^h7s}SIDG*;|-=xWYPB+O1X>zWP&?Vjy6KRq|(&Vh& zLzi4TM3*M}FHQ1VVl4Zr>7z`rE+VKxXUJ~-mlcL(6QGhVNtXr9|ktk#_PGmeon1MajvJ= ztY(?ZbR@!R1DH6^ss%rX_w!c1FL#sN6utHk(HoFw|P z)s6l#N``mM=|N+?nN@gXnVS6M7|BUcVVRWWQ>U^Um5I%!HbYrlMM8}g=q)m!IfPX% zT5?gzL$sChEBlnJr|X1Rlt0LckPC z8|K03D7a`dAG@@t*9-?rudb{;IeWp5T$TrGeh^2&tr;z!<3c>H` z#ZI>y@VB_AyWQU6!$Id*r^CeHg5BgW-!QMUs5{->v4-A?MyVO91Xpi#t!dPZckMh~I(`&1fz;s)k*=3jJ9Ot0F zGs5fKZX+=gUP%R3AF2y9={i?{P=~O{Te&o+@n4?KLu)(Ua@mslFZRkfg9z$#<)n z2E4suxKzTVh~=_rmP;m_QWsr#?Rh+yteaX?<|`Ue)vT(o=-m}n>3XB0n^|5&DG=8MzAP3jmqMY98%MWMpy#L(oU#Qf3~_D>hE}WNy(=%Z$`j69WP>I2 z+Qg}4^HdRIc*-6wCnj^_+OcA(t8OHwa3FOtq;lZzI6Rt4FE2}1RhdpfvaGpw9Py~#E5mkF8?Hhh zVugvYl1jsN@{7Pqp`p&W*7Zv$NmZ8bF>7x@Wg5o+U(6nJCSjbiGR)%LT`+lJlKASb z6R1V(KofE=N3@t!W~ZLC8TnV6#kr=&yNHeAZxZB|YBHsa=R}@*$5@;4vJW{TDSNBS zU}V&z=Aeu%soyn*srs@Q7b^72o=s(1`G1p?DU+4eYU*^9O6yxdjYUe?D(|G`jaO2D nve-t3D@uHAzD%oa-Vp^wHA{VSIw!g2$4aUTvDCktY_I+c54bkv diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.po b/apps/tags/locale/pt/LC_MESSAGES/django.po index bbc0936a4d..c0b69116a7 100644 --- a/apps/tags/locale/pt/LC_MESSAGES/django.po +++ b/apps/tags/locale/pt/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: # , 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: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-02 14:17-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" "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 +#: __init__.py:21 msgid "tag list" msgstr "lista de etiquetas" -#: __init__.py:29 +#: __init__.py:22 msgid "create new tag" msgstr "criar nova etiqueta" -#: __init__.py:30 +#: __init__.py:23 msgid "attach tag" msgstr "anexar etiqueta" -#: __init__.py:31 __init__.py:32 +#: __init__.py:24 __init__.py:25 msgid "remove" msgstr "remover" -#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 +#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 msgid "tags" msgstr "Etiquetas" -#: __init__.py:34 __init__.py:37 +#: __init__.py:27 __init__.py:30 msgid "delete" msgstr "excluir" -#: __init__.py:35 +#: __init__.py:28 msgid "edit" msgstr "editar" -#: __init__.py:36 +#: __init__.py:29 msgid "tagged documents" msgstr "documentos etiquetados" -#: __init__.py:41 models.py:46 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: __init__.py:35 models.py:13 msgid "color" msgstr "cor" -#: __init__.py:45 +#: __init__.py:39 msgid "color name" msgstr "nome da cor" -#: forms.py:14 -msgid "New tag" -msgstr "Nova etiqueta" +#: __init__.py:43 +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:153 views.py:205 views.py:219 msgid "tag" msgstr "etiqueta" -#: models.py:49 +#: 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 "" + +#: 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 "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:129 views.py:256 msgid "Must provide at least one tag." msgstr "Deve fornecer pelo menos uma etiqueta." -#: views.py:176 +#: views.py:144 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Etiqueta \"%s\" removida com sucesso." -#: views.py:178 views.py:294 +#: views.py:146 views.py:268 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" msgstr "Erro ao excluir etiqueta \" %(tag)s \": %(error)s " -#: views.py:193 +#: views.py:161 #, 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:162 views.py:165 msgid "Will be removed from all documents." msgstr "Será removido de todos os documentos." -#: views.py:196 +#: views.py:164 #, 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:193 msgid "Tag updated succesfully." msgstr "Etiqueta atualizada com sucesso." -#: views.py:230 +#: views.py:202 #, python-format msgid "edit tag: %s" msgstr "editar etiqueta: %s" -#: views.py:245 +#: views.py:216 #, python-format msgid "documents with the tag \"%s\"" msgstr "documentos com a etiqueta \"%s\"" -#: views.py:258 +#: views.py:235 #, python-format msgid "tags for: %s" msgstr "etiquetas para: %s" -#: views.py:292 +#: views.py:266 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Etiqueta \"%s\" removida com sucesso." -#: views.py:308 +#: views.py:282 #, 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:284 #, python-format msgid "Are you sure you wish to remove the tags: %s?" msgstr "Tem certeza de que deseja remover as etiquetas: %s?" @@ -265,3 +246,5 @@ msgstr "Tem certeza de que deseja remover as etiquetas: %s?" #: templatetags/tags_tags.py:17 msgid "Add tag to document" msgstr "Adicionar etiquetas para o documento" + + diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.mo b/apps/tags/locale/ru/LC_MESSAGES/django.mo index 9caaeae59d439a2ac82272fe066fd84b2467f25b..b520139771cceb0421833a330ddeb6482a000c2b 100644 GIT binary patch delta 1370 zcmX}rOGs2v9LMov>6nwFsil^sV``=~&LhK|B&6(x_AZJj;uga+pfho2gc8a{wUH>| z6c!W_6cGf0Zd$g}jV>ahP0=C=f*^<$I^)bE|R8oRO8 zm{D_rhf-c#K`wKXTM3S1F+Rk4e2Qvd8hto}8slqRfp4(^zoEXb;v*SDC2#<1G2wX$ z3+dmC^U%Z(_mIoHYdcDd%i&>Qone< z!!}$>J%(#=CypwUG!LD45&Ligm*Y>=NGljs4X(gSjNvBSj>`O!_x>uXy*s!OpP=^C zJI~*!C8`PJ*WPpmn18L^DPCx;Mo=TZi<|Kg@*nd7HA7!e-~T}kY&pGY%2#7EZb1$F z404%^+*VFfs7H3fH{m}fY!(!%F8CIeiY{ypIfodR)`tBBL1|Fckn?MeX>7Xc6 zg=R#d4!uKUn8^H+D*F&c8*x2lmDXRGucK(!FQX{bNjU#BKQLvd4mGHM5#>SI{0psV z#H;9tF-iH*CRVmO;yMX!6eb`adz76**=cjMQ#7?fib5wtp=GG1XnGYSo<9}rN7G1Q zPa0#3ie~MnqE_4JYqCdtt#-`UZs&XrwzN26FBd|WGc(0?|UI~Na!ld0U<;nN*w zGDBfElXcuw#tjcS7o2oBmCX((vi|-14u`h62`87zq(gm9E)fsLBGFhVqAM8fj7Pid z{gS$)|KDtiN4wWW2>*bS&4muTPC7g2sMueCMYEsurS2NmV>kt#n zexNZ5!Nk+Z5*Hw7^bdn&V{uL#iT@eryap4ZF=qZ@Bmw_1I!!d_`_ml?A?TCdz3!fS zeto~s)4AHY;NW-Vo;M82y?@efKRhjB>*mG)i~~P+{UNxEUL87na}w^y4e20pG+T9K%9<7sL1g z-huO|3I1}wduYU?;YY<(fz?=rjm&REc~Im}U@bm}8fesY3KiJ}T!oihJ-)?>YVcO- z16Yq6Q4>Ci%Q22+m_`LK?AE`8E12JS&8;|r>i9n1h7+hrzC>lUuuuo^iWMih5rCu#x5 zQ5pIgSK>UX-2(D6iU@BVuEI^Y9d))2p|<#x>*uJgzF12B8+h=MHyw&FYVWtAB7Fv1 zZ~*lWc^e7Nm`8rbPu$e+3MzorY_zs6fXcvqr~tcB3w$1fco@}he2|AVJbZx~Z~--O zAz>*K<){JIq89oPYJe1~-RsEDIL1xw#*wYfr#*x!Is^A`X$zKcDRT-^85!g-=ToLZ zv=FU|bCHi)saDbH*MYlQ8hKdDr7daaQf5>Xz}2F2(Zr=i>EEHEe~+@##?{Qlt`8bf z9@vh2x!YAJZHiPydv$GD@4hGl$_nQ+pI%k#FQ!5w^BD|dohm3g3n~#VZC8zEHhIvV zZse-BJ3Vt14`ed2?jF=t!va`;N$wCiNHRNRTF)-OozUtal zo3v%QHx01G?(jcYIi{Wr^Xk9xX6+aJyPtZ?jXoO)_6JO6W(_1@oG}$#mf=n3+;s_c yzqA<6Kb_5+^tQkCe-_eq%;bg@5n&9OWP8$?(1I4{o6a3vOeG((6DLcWmi!I8Jnaks diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.po b/apps/tags/locale/ru/LC_MESSAGES/django.po index 1e057efbd3..06e294b4da 100644 --- a/apps/tags/locale/ru/LC_MESSAGES/django.po +++ b/apps/tags/locale/ru/LC_MESSAGES/django.po @@ -1,263 +1,243 @@ # 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: \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-02 14:17-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" "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: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 +#: __init__.py:21 msgid "tag list" msgstr "список меток" -#: __init__.py:29 +#: __init__.py:22 msgid "create new tag" msgstr "создать новую метку" -#: __init__.py:30 +#: __init__.py:23 msgid "attach tag" msgstr "пометить" -#: __init__.py:31 __init__.py:32 +#: __init__.py:24 __init__.py:25 msgid "remove" msgstr "удаление" -#: __init__.py:33 __init__.py:58 utils.py:14 views.py:144 +#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 msgid "tags" msgstr "метки" -#: __init__.py:34 __init__.py:37 +#: __init__.py:27 __init__.py:30 msgid "delete" msgstr "удалить" -#: __init__.py:35 +#: __init__.py:28 msgid "edit" msgstr "редактировать" -#: __init__.py:36 +#: __init__.py:29 msgid "tagged documents" msgstr "помеченные документы" -#: __init__.py:41 models.py:46 +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: __init__.py:35 models.py:13 msgid "color" msgstr "цвет" -#: __init__.py:45 +#: __init__.py:39 msgid "color name" msgstr "название цвета" -#: forms.py:14 -msgid "New tag" -msgstr "Новая метка" +#: __init__.py:43 +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:153 views.py:205 views.py:219 msgid "tag" msgstr "метка" -#: models.py:49 +#: 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:129 views.py:256 msgid "Must provide at least one tag." msgstr "Должна быть хотя бы одна метка." -#: views.py:176 +#: views.py:144 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Метка \"%s\"удалён." -#: views.py:178 views.py:294 +#: views.py:146 views.py:268 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" msgstr "Ошибка при удалении метки \"%(tag)s\": %(error)s" -#: views.py:193 +#: views.py:161 #, python-format msgid "Are you sure you wish to delete the tag: %s?" msgstr "Вы действительно хотите удалить метку: %s?" -#: views.py:194 views.py:197 +#: views.py:162 views.py:165 msgid "Will be removed from all documents." msgstr "Будет удален из всех документов." -#: views.py:196 +#: views.py:164 #, python-format msgid "Are you sure you wish to delete the tags: %s?" msgstr "Вы действительно хотите удалить метки: %s?" -#: views.py:221 +#: views.py:193 msgid "Tag updated succesfully." msgstr "Метка обновлена." -#: views.py:230 +#: views.py:202 #, python-format msgid "edit tag: %s" msgstr "редактировать метку %s" -#: views.py:245 +#: views.py:216 #, python-format msgid "documents with the tag \"%s\"" msgstr "документы с тегом \"%s\"" -#: views.py:258 +#: views.py:235 #, python-format msgid "tags for: %s" msgstr "теги для:%s" -#: views.py:292 +#: views.py:266 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Метка \"%s\" удалена." -#: views.py:308 +#: views.py:282 #, python-format msgid "Are you sure you wish to remove the tag: %s?" msgstr "Вы действительно хотите снять метку: %s?" -#: views.py:310 +#: views.py:284 #, python-format msgid "Are you sure you wish to remove the tags: %s?" msgstr "Вы действительно хотите снять метку: %s?" @@ -265,3 +245,5 @@ msgstr "Вы действительно хотите снять метку: %s?" #: templatetags/tags_tags.py:17 msgid "Add tag to document" msgstr "Добавить тег к документу" + + diff --git a/apps/user_management/locale/en/LC_MESSAGES/django.po b/apps/user_management/locale/en/LC_MESSAGES/django.po index 2c85ff5f68..2a79d9f030 100644 --- a/apps/user_management/locale/en/LC_MESSAGES/django.po +++ b/apps/user_management/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,79 +17,43 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:8 -msgid "Create new users" -msgstr "" - -#: __init__.py:9 -msgid "Edit existing users" -msgstr "" - -#: __init__.py:10 -msgid "View existing users" -msgstr "" - -#: __init__.py:11 -msgid "Delete existing users" -msgstr "" - #: __init__.py:13 -msgid "Create new groups" -msgstr "" - -#: __init__.py:14 -msgid "Edit existing groups" -msgstr "" - -#: __init__.py:15 -msgid "View existing groups" -msgstr "" - -#: __init__.py:16 -msgid "Delete existing groups" -msgstr "" - -#: __init__.py:18 -msgid "User management" -msgstr "" - -#: __init__.py:28 msgid "user list" msgstr "" -#: __init__.py:29 views.py:31 +#: __init__.py:14 views.py:31 msgid "users" msgstr "" -#: __init__.py:30 __init__.py:39 +#: __init__.py:15 __init__.py:24 msgid "edit" msgstr "" -#: __init__.py:31 views.py:92 +#: __init__.py:16 views.py:97 msgid "create new user" msgstr "" -#: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 +#: __init__.py:17 __init__.py:18 __init__.py:26 __init__.py:27 msgid "delete" msgstr "" -#: __init__.py:34 __init__.py:35 +#: __init__.py:19 __init__.py:20 msgid "reset password" msgstr "" -#: __init__.py:37 +#: __init__.py:22 msgid "group list" msgstr "" -#: __init__.py:38 views.py:222 +#: __init__.py:23 views.py:228 msgid "groups" msgstr "" -#: __init__.py:40 views.py:270 +#: __init__.py:25 views.py:276 msgid "create new group" msgstr "" -#: __init__.py:43 views.py:226 +#: __init__.py:28 views.py:232 msgid "members" msgstr "" @@ -101,6 +65,42 @@ msgstr "" msgid "Confirm password" msgstr "" +#: permissions.py:7 +msgid "User management" +msgstr "" + +#: permissions.py:9 +msgid "Create new users" +msgstr "" + +#: permissions.py:10 +msgid "Edit existing users" +msgstr "" + +#: permissions.py:11 +msgid "View existing users" +msgstr "" + +#: permissions.py:12 +msgid "Delete existing users" +msgstr "" + +#: permissions.py:14 +msgid "Create new groups" +msgstr "" + +#: permissions.py:15 +msgid "Edit existing groups" +msgstr "" + +#: permissions.py:16 +msgid "View existing groups" +msgstr "" + +#: permissions.py:17 +msgid "Delete existing groups" +msgstr "" + #: views.py:35 msgid "full name" msgstr "" @@ -113,140 +113,144 @@ msgstr "" msgid "active" msgstr "" -#: views.py:58 +#: views.py:47 +msgid "has usable password?" +msgstr "" + +#: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." msgstr "" -#: views.py:65 +#: views.py:68 #, python-format msgid "User \"%s\" updated successfully." msgstr "" -#: views.py:71 +#: views.py:74 #, python-format msgid "edit user: %s" msgstr "" -#: views.py:74 views.py:130 views.py:193 +#: views.py:77 views.py:135 views.py:198 msgid "user" msgstr "" -#: views.py:86 +#: views.py:91 #, python-format msgid "User \"%s\" created successfully." msgstr "" -#: views.py:108 views.py:162 +#: views.py:113 views.py:167 msgid "Must provide at least one user." msgstr "" -#: views.py:118 +#: views.py:123 msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." msgstr "" -#: views.py:121 +#: views.py:126 #, python-format msgid "User \"%s\" deleted successfully." msgstr "" -#: views.py:123 +#: views.py:128 #, python-format msgid "Error deleting user \"%(user)s\": %(error)s" msgstr "" -#: views.py:138 +#: views.py:143 #, python-format msgid "Are you sure you wish to delete the user: %s?" msgstr "" -#: views.py:140 +#: views.py:145 #, python-format msgid "Are you sure you wish to delete the users: %s?" msgstr "" -#: views.py:173 +#: views.py:178 msgid "Passwords do not match, try again." msgstr "" -#: views.py:178 +#: views.py:183 msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." msgstr "" -#: views.py:182 +#: views.py:187 #, python-format msgid "Successfull password reset for user: %s." msgstr "" -#: views.py:184 +#: views.py:189 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" msgstr "" -#: views.py:200 +#: views.py:205 #, python-format msgid "Reseting password for user: %s" msgstr "" -#: views.py:202 +#: views.py:207 #, python-format msgid "Reseting password for users: %s" msgstr "" -#: views.py:243 +#: views.py:249 #, python-format msgid "Group \"%s\" updated successfully." msgstr "" -#: views.py:249 +#: views.py:255 #, python-format msgid "edit group: %s" msgstr "" -#: views.py:252 views.py:305 views.py:350 +#: views.py:258 views.py:311 views.py:356 msgid "group" msgstr "" -#: views.py:264 +#: views.py:270 #, python-format msgid "Group \"%s\" created successfully." msgstr "" -#: views.py:286 +#: views.py:292 msgid "Must provide at least one group." msgstr "" -#: views.py:296 +#: views.py:302 #, python-format msgid "Group \"%s\" deleted successfully." msgstr "" -#: views.py:298 +#: views.py:304 #, python-format msgid "Error deleting group \"%(group)s\": %(error)s" msgstr "" -#: views.py:313 +#: views.py:319 #, python-format msgid "Are you sure you wish to delete the group: %s?" msgstr "" -#: views.py:315 +#: views.py:321 #, python-format msgid "Are you sure you wish to delete the groups: %s?" msgstr "" -#: views.py:345 +#: views.py:351 #, python-format msgid "non members of group: %s" msgstr "" -#: views.py:346 +#: views.py:352 #, python-format msgid "members of group: %s" msgstr "" diff --git a/apps/user_management/locale/es/LC_MESSAGES/django.mo b/apps/user_management/locale/es/LC_MESSAGES/django.mo index ff5716ae9b4fa9195cfd4faee43e10fe68457e67..35124521903544c855b106c546f62eade747cccf 100644 GIT binary patch delta 1400 zcmX}sO>7Kd9LMp8*4uVzwO&fmQCcl_x7&JYHcABX9<7&4MPio8c9XSRJF}GvsYDP7 z304n;q)i;^MkIA0-Z@AQ5{I5N;UW?@7m17SZ+3Vx&wS>2X7+jh&;Oa(XN_Y`gOk9{8*v%#LfubcGhV@?_y~J2 zJkywyx{vkDZ^r!#V}1sPXBkt;18Y$cZ$d@fjm&8r)QU5x=gtTH*OBCy+c*dB;A|X4 z)@a6%!#oe#A27uHW}FKRJb{{U5((D)3fh0LmUdOBG;j-Qq7LMi=|oMi6Th*2`%zof zN_ygWJn$B_(|(8AlHWL}mCYecbu{2&>_EK>hfovu1^rjCjrN1U3EV?F#B!DLBiMum zT#5IB{@1vi_E*$9QbyVo$oxw3zlw|9bVTtqZo*-7@e7{DZt{H*-=YTI$tW^|jd&C5 z@F{8`pK&4nKxKAHb!p<6s0A-ZcH2a&$-f@hNQd@xGjf;%ob+H4iNW-vQhXU%w7G`* z-CfkmM^FR4M!oePaS?t+1@Z^Ar8NvnOr{R?d_?(Y%lv%=zpyR-=ctsim3~>xSpjOY ze??mq2^tDUMZxN8n5srl6tG2AruBX;rLLzoQ3sWFMWUiqD(VXA3TiV|`%mzGiF4MA zr=oPXQk500@Lvi3HcT5GYlBX`Q~v649aS09r%Gw^_bbL#3stFUr>gMh;D1KiXY=Gz z`POOkdTrM#xOOt*SbetZp2_7;ZYjQ>bz^U@=k+CGu~gdYEhM8Sa;IYXoNMRPxqR%D zJz!^JY1b_{Zm8?P;mEeUV|(dbHnQFJoP^cZ8gGlV>agPL67h}2flyuee@{oEy*M1I ztvr}ZI(aW=9V`u7d=$Ys5}?K*EC S+g8C#XVPaC_m<+0>i)kbp`5M& delta 1296 zcmZA1OGs2v9LMp0;ShwBMPb-NTBMr`jSmoqW=1G5rV^qy zB@BU!lolavDoBaQg#=NnYEkVff;KIpO%hQp`u@fnM29)|bI-Zg^Z5VI^yBl=dc>5unOmJ zJuYICS=L^0vzv}z*n#y$W)U3lJ?}f~yM)_#{t-*jip_RF8E!=v^}H7wF^T;+ji+!K zPwV+wy_Ypx$lsW~@m>me*ZWU6q~?uyohBuh3w5{ zk)Pf6+xIZQ{I13yp`SF?Qew_ps9`cB|6+V@eR{)r7(%PQ-z3)Me} z+wn5$Y}`RD zHB?0Bke}VqNqPSfEws9>Xi55 zCLBa9-~uX@)5wr^3-$g3BvbjckSz--|9^`@r9qmh%D+OY$yZZ}SU&fAP({)Bzc_TX z`kmTsgxcu0mDZiqEq+^R&{y;C{P{;QuF8#erGEhmtBOlisyKtj`N~I45z!~7qTT7N zX!q?@?OrKT6m=F9HI9|O`TXY&D&@A9s}7sO6rP_c=qk*8E4f}5IMLhZ984v=%t&&~ zIpk#$@kq>#Mjd{!SR@*a$2xK^0^#PU<90f2Zp3YmN8Kiu66o>L8K*DhjipDuOfnUZ nq>^bbHIhu_!okVX9&c=D+#6!NL^?MU?4K_zy;+od5*q&l#`=7e diff --git a/apps/user_management/locale/es/LC_MESSAGES/django.po b/apps/user_management/locale/es/LC_MESSAGES/django.po index 11f2ee564d..ffca035a57 100644 --- a/apps/user_management/locale/es/LC_MESSAGES/django.po +++ b/apps/user_management/locale/es/LC_MESSAGES/django.po @@ -1,96 +1,60 @@ # 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:10+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-02 14:17-0400\n" +"PO-Revision-Date: 2012-02-02 18:30+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:8 -msgid "Create new users" -msgstr "Crear nuevos usuarios" - -#: __init__.py:9 -msgid "Edit existing users" -msgstr "Editar usuarios existentes" - -#: __init__.py:10 -msgid "View existing users" -msgstr "Ver usuarios existentes" - -#: __init__.py:11 -msgid "Delete existing users" -msgstr "Eliminar usuarios existentes" - #: __init__.py:13 -msgid "Create new groups" -msgstr "Crear nuevos grupos" - -#: __init__.py:14 -msgid "Edit existing groups" -msgstr "Editar grupos existentes" - -#: __init__.py:15 -msgid "View existing groups" -msgstr "Ver grupos existentes" - -#: __init__.py:16 -msgid "Delete existing groups" -msgstr "Eliminar grupos existentes" - -#: __init__.py:18 -msgid "User management" -msgstr "Administración de usuarios" - -#: __init__.py:28 msgid "user list" msgstr "lista de usuarios" -#: __init__.py:29 views.py:31 +#: __init__.py:14 views.py:31 msgid "users" msgstr "usuarios" -#: __init__.py:30 __init__.py:39 +#: __init__.py:15 __init__.py:24 msgid "edit" msgstr "editar" -#: __init__.py:31 views.py:92 +#: __init__.py:16 views.py:97 msgid "create new user" msgstr "crear nuevo usuario" -#: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 +#: __init__.py:17 __init__.py:18 __init__.py:26 __init__.py:27 msgid "delete" msgstr "eliminar" -#: __init__.py:34 __init__.py:35 +#: __init__.py:19 __init__.py:20 msgid "reset password" msgstr "restablecer contraseña" -#: __init__.py:37 +#: __init__.py:22 msgid "group list" msgstr "list de group" -#: __init__.py:38 views.py:222 +#: __init__.py:23 views.py:228 msgid "groups" msgstr "grupos" -#: __init__.py:40 views.py:270 +#: __init__.py:25 views.py:276 msgid "create new group" msgstr "crear nuevo grupo" -#: __init__.py:43 views.py:226 +#: __init__.py:28 views.py:232 msgid "members" msgstr "miembros" @@ -102,6 +66,42 @@ msgstr "Nueva contraseña" msgid "Confirm password" msgstr "Confirmar contraseña" +#: permissions.py:7 +msgid "User management" +msgstr "Administración de usuarios" + +#: permissions.py:9 +msgid "Create new users" +msgstr "Crear nuevos usuarios" + +#: permissions.py:10 +msgid "Edit existing users" +msgstr "Editar usuarios existentes" + +#: permissions.py:11 +msgid "View existing users" +msgstr "Ver usuarios existentes" + +#: permissions.py:12 +msgid "Delete existing users" +msgstr "Eliminar usuarios existentes" + +#: permissions.py:14 +msgid "Create new groups" +msgstr "Crear nuevos grupos" + +#: permissions.py:15 +msgid "Edit existing groups" +msgstr "Editar grupos existentes" + +#: permissions.py:16 +msgid "View existing groups" +msgstr "Ver grupos existentes" + +#: permissions.py:17 +msgid "Delete existing groups" +msgstr "Eliminar grupos existentes" + #: views.py:35 msgid "full name" msgstr "nombre completo" @@ -114,38 +114,42 @@ msgstr "correo electrónico" msgid "active" msgstr "activo" -#: views.py:58 +#: views.py:47 +msgid "has usable password?" +msgstr "¿Tiene contraseña utilizable?" + +#: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." msgstr "" -"No se permite editar el super usuario y usuario de personal, use la interfaz " -"de administración para estos casos." +"No se permite editar el super usuario y usuario de personal, use la interfaz" +" de administración para estos casos." -#: views.py:65 +#: views.py:68 #, python-format msgid "User \"%s\" updated successfully." msgstr "Usuario \"%s\" actualizado exitsamente." -#: views.py:71 +#: views.py:74 #, python-format msgid "edit user: %s" msgstr "editar usuario: %s" -#: views.py:74 views.py:130 views.py:193 +#: views.py:77 views.py:135 views.py:198 msgid "user" msgstr "usuario" -#: views.py:86 +#: views.py:91 #, python-format msgid "User \"%s\" created successfully." msgstr "Usuario \"%s\" ha creado exitosamente." -#: views.py:108 views.py:162 +#: views.py:113 views.py:167 msgid "Must provide at least one user." msgstr "Debe proveer al menos un usuario." -#: views.py:118 +#: views.py:123 msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." @@ -153,31 +157,31 @@ msgstr "" "No se permite eliminar el super usuario y usuario de personal, use la " "interfaz de administración para estos casos." -#: views.py:121 +#: views.py:126 #, python-format msgid "User \"%s\" deleted successfully." msgstr "Usuario \"%s\" eliminado exitosamente." -#: views.py:123 +#: views.py:128 #, python-format msgid "Error deleting user \"%(user)s\": %(error)s" msgstr "Error eliminando el usuario \"%(user)s\": %(error)s " -#: views.py:138 +#: views.py:143 #, python-format msgid "Are you sure you wish to delete the user: %s?" msgstr "¿Está seguro que desea eliminar el usuario: %s?" -#: views.py:140 +#: views.py:145 #, python-format msgid "Are you sure you wish to delete the users: %s?" msgstr "¿Está seguro que desea eliminar los usuarios: %s?" -#: views.py:173 +#: views.py:178 msgid "Passwords do not match, try again." msgstr "Las contraseñas no coinciden, vuelva a intentarlo." -#: views.py:178 +#: views.py:183 msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." @@ -185,76 +189,78 @@ msgstr "" "No se permite cambiar la contraseña del super usuario y usuarios de " "personal, use la interfaz de administración para estos casos." -#: views.py:182 +#: views.py:187 #, python-format msgid "Successfull password reset for user: %s." msgstr "Restablecimiento exitoso de contraseña para el usuario: %s." -#: views.py:184 +#: views.py:189 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" msgstr "" "Error de restaurando la contraseña para el usuario \"%(user)s\": %(error)s " -#: views.py:200 +#: views.py:205 #, python-format msgid "Reseting password for user: %s" msgstr "Restaurando contraseña del usuario: %s" -#: views.py:202 +#: views.py:207 #, python-format msgid "Reseting password for users: %s" msgstr "Restaurando la contraseña de los usuarios: %s" -#: views.py:243 +#: views.py:249 #, python-format msgid "Group \"%s\" updated successfully." msgstr "Grupo \"%s\" actualizado exitosamente." -#: views.py:249 +#: views.py:255 #, python-format msgid "edit group: %s" msgstr "editar grupo: %s" -#: views.py:252 views.py:305 views.py:350 +#: views.py:258 views.py:311 views.py:356 msgid "group" msgstr "grupo" -#: views.py:264 +#: views.py:270 #, python-format msgid "Group \"%s\" created successfully." msgstr "Grupo \"%s\" creado exitosamente." -#: views.py:286 +#: views.py:292 msgid "Must provide at least one group." msgstr "Debe proveer al menos un grupo." -#: views.py:296 +#: views.py:302 #, python-format msgid "Group \"%s\" deleted successfully." msgstr "Grupo \"%s\" eliminado con exitosamente." -#: views.py:298 +#: views.py:304 #, python-format msgid "Error deleting group \"%(group)s\": %(error)s" msgstr "Error al eliminar el grupo \"%(group)s\": %(error)s " -#: views.py:313 +#: views.py:319 #, python-format msgid "Are you sure you wish to delete the group: %s?" msgstr "¿Está seguro que desea eliminar el grupo: %s?" -#: views.py:315 +#: views.py:321 #, python-format msgid "Are you sure you wish to delete the groups: %s?" msgstr "¿Está seguro que desea eliminar los grupos: %s?" -#: views.py:345 +#: views.py:351 #, python-format msgid "non members of group: %s" msgstr "no miembros del grupo: %s" -#: views.py:346 +#: views.py:352 #, python-format msgid "members of group: %s" msgstr "miembros del grupo: %s" + + diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.mo b/apps/user_management/locale/it/LC_MESSAGES/django.mo index bb05dd71b6d93923629a2e2cb14ec33574086f68..eeadde4b8c0327af1f9e13a582b93e0576a1a22b 100644 GIT binary patch delta 538 zcmX}oze@sP9LMpmNE+vlvL8bTaYUE>QdEM(q_N2wB!Y&Z3oHcj=#&N{Zj7X$@E>Sw zs=%SCXo%LJp*;#3+G}a({p3T(!}EGR-+S(!A1&+5x_8 zrpO+~@KSq^L*!?S;|KPkKO!=MgV>KrT);&vU=vsH22Bh^#glOciKzTp#8L9D_7rJy zMQ7oi_8k*sgHG%)qf0Ls+)+R%46Co944nH8K^5;(uGYuVGp@gIncS) zsraXZk!&)pnwgo)XXe}IMtu3dlFMguGie^9XxAIbRoAZ7t9HY2^JdA}D!UB_>$Y2Q Y%!1o3q}*;Hwd2&9cD3B>_(Dg)U(aVp(EtDd delta 531 zcmXxg&nv@m9LMqZS~G2i`Ek%{eUc5EulD^aKW3#A7ebP9(pMa&wP{;Y4m(I94)PCh z;<#FolZ%6La2Ms^&c#jf{LIIt*g<~82)h~V74PVfQA4qfZh59>Q9_o__pw1CvH+GWy`n=pkHv!H;S zrfi$MSIc@6{*Z0iw&gg=w$sk=*?Ax`O~tY7A(a|SJEO@IS76pHm93?sn=j?ua-o=3 f3)zk0mRrab)TEnRck?Q<^\n" +"POT-Creation-Date: 2012-02-02 14:17-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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,79 +18,43 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:8 -msgid "Create new users" -msgstr "Crea un nuovo utente" - -#: __init__.py:9 -msgid "Edit existing users" -msgstr "Modifica utenti " - -#: __init__.py:10 -msgid "View existing users" -msgstr "Visualizza utenti" - -#: __init__.py:11 -msgid "Delete existing users" -msgstr "Cancella utenti" - #: __init__.py:13 -msgid "Create new groups" -msgstr "Crea nuovi gruppi" - -#: __init__.py:14 -msgid "Edit existing groups" -msgstr "Modifica gruppi esistenti" - -#: __init__.py:15 -msgid "View existing groups" -msgstr "Visualizza i gruppi" - -#: __init__.py:16 -msgid "Delete existing groups" -msgstr "Cancella i gruppi esistenti" - -#: __init__.py:18 -msgid "User management" -msgstr "Gestione utenti" - -#: __init__.py:28 msgid "user list" msgstr "lista utenti" -#: __init__.py:29 views.py:31 +#: __init__.py:14 views.py:31 msgid "users" msgstr "utenti" -#: __init__.py:30 __init__.py:39 +#: __init__.py:15 __init__.py:24 msgid "edit" msgstr "modifica" -#: __init__.py:31 views.py:92 +#: __init__.py:16 views.py:97 msgid "create new user" msgstr "crea un nuovo utente" -#: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 +#: __init__.py:17 __init__.py:18 __init__.py:26 __init__.py:27 msgid "delete" msgstr "cancella" -#: __init__.py:34 __init__.py:35 +#: __init__.py:19 __init__.py:20 msgid "reset password" msgstr "riassegna la password" -#: __init__.py:37 +#: __init__.py:22 msgid "group list" msgstr "lista dei gruppi" -#: __init__.py:38 views.py:222 +#: __init__.py:23 views.py:228 msgid "groups" msgstr "gruppi" -#: __init__.py:40 views.py:270 +#: __init__.py:25 views.py:276 msgid "create new group" msgstr "crea un nuovo gruppo" -#: __init__.py:43 views.py:226 +#: __init__.py:28 views.py:232 msgid "members" msgstr "membri" @@ -102,6 +66,42 @@ msgstr "Nuova password" msgid "Confirm password" msgstr "Conferma password" +#: permissions.py:7 +msgid "User management" +msgstr "Gestione utenti" + +#: permissions.py:9 +msgid "Create new users" +msgstr "Crea un nuovo utente" + +#: permissions.py:10 +msgid "Edit existing users" +msgstr "Modifica utenti " + +#: permissions.py:11 +msgid "View existing users" +msgstr "Visualizza utenti" + +#: permissions.py:12 +msgid "Delete existing users" +msgstr "Cancella utenti" + +#: permissions.py:14 +msgid "Create new groups" +msgstr "Crea nuovi gruppi" + +#: permissions.py:15 +msgid "Edit existing groups" +msgstr "Modifica gruppi esistenti" + +#: permissions.py:16 +msgid "View existing groups" +msgstr "Visualizza i gruppi" + +#: permissions.py:17 +msgid "Delete existing groups" +msgstr "Cancella i gruppi esistenti" + #: views.py:35 msgid "full name" msgstr "nome completo" @@ -114,7 +114,11 @@ msgstr "email" msgid "active" msgstr "attivo" -#: views.py:58 +#: views.py:47 +msgid "has usable password?" +msgstr "" + +#: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." @@ -122,30 +126,30 @@ msgstr "" "Super utente e utente modifica il personale non è consentito, utilizzare " "l'interfaccia di amministrazione per questi casi." -#: views.py:65 +#: views.py:68 #, python-format msgid "User \"%s\" updated successfully." msgstr "Utente \"%s\" aggiornato con successo." -#: views.py:71 +#: views.py:74 #, python-format msgid "edit user: %s" msgstr "modifica utente:%s" -#: views.py:74 views.py:130 views.py:193 +#: views.py:77 views.py:135 views.py:198 msgid "user" msgstr "utente" -#: views.py:86 +#: views.py:91 #, python-format msgid "User \"%s\" created successfully." msgstr "Utente \"%s\" creato con successo." -#: views.py:108 views.py:162 +#: views.py:113 views.py:167 msgid "Must provide at least one user." msgstr "Devi fornire almeno un utente." -#: views.py:118 +#: views.py:123 msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." @@ -153,31 +157,31 @@ msgstr "" "Al super utente e utente non è consentito la cancellazione del personale, " "utilizzare l'interfaccia di amministrazione per questi casi." -#: views.py:121 +#: views.py:126 #, python-format msgid "User \"%s\" deleted successfully." msgstr "Utente \"%s\" cancellato con successo." -#: views.py:123 +#: views.py:128 #, python-format msgid "Error deleting user \"%(user)s\": %(error)s" msgstr "Errore nella cancellazione dell'utente \"%(user)s\": %(error)s" -#: views.py:138 +#: views.py:143 #, python-format msgid "Are you sure you wish to delete the user: %s?" msgstr "Sei sicuro di voler cancellare l'utente: %s?" -#: views.py:140 +#: views.py:145 #, python-format msgid "Are you sure you wish to delete the users: %s?" msgstr "Sei sicuro di voler cancellare gli utenti: %s?" -#: views.py:173 +#: views.py:178 msgid "Passwords do not match, try again." msgstr "La password non corrisponde, riprova." -#: views.py:178 +#: views.py:183 msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." @@ -185,77 +189,77 @@ msgstr "" "Al super utente e utente non è consentito di reimpostare la password " "personale, utilizzare l'interfaccia di amministrazione per questi casi." -#: views.py:182 +#: views.py:187 #, python-format msgid "Successfull password reset for user: %s." msgstr "Password reimpostata per l'utente: %s." -#: views.py:184 +#: views.py:189 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" msgstr "" "Errore per il reimpostamento della password per l'utente \"%(user)s\": " "%(error)s" -#: views.py:200 +#: views.py:205 #, python-format msgid "Reseting password for user: %s" msgstr "Reimposta la password per l'utente:%s" -#: views.py:202 +#: views.py:207 #, python-format msgid "Reseting password for users: %s" msgstr "Reimposta la password per gli utenti:%s" -#: views.py:243 +#: views.py:249 #, python-format msgid "Group \"%s\" updated successfully." msgstr "Gruppo \"%s\" aggiornato con successo." -#: views.py:249 +#: views.py:255 #, python-format msgid "edit group: %s" msgstr "modifica gruppo: %s" -#: views.py:252 views.py:305 views.py:350 +#: views.py:258 views.py:311 views.py:356 msgid "group" msgstr "gruppo" -#: views.py:264 +#: views.py:270 #, python-format msgid "Group \"%s\" created successfully." msgstr "Gruppo \"%s\" creato con successo." -#: views.py:286 +#: views.py:292 msgid "Must provide at least one group." msgstr "Devi almeno indicare un gruppo" -#: views.py:296 +#: views.py:302 #, python-format msgid "Group \"%s\" deleted successfully." msgstr "Gruppo \"%s\" cancellato con successo." -#: views.py:298 +#: views.py:304 #, python-format msgid "Error deleting group \"%(group)s\": %(error)s" msgstr "Erroro nella cancellazione del gruppo\"%(group)s\": %(error)s" -#: views.py:313 +#: views.py:319 #, python-format msgid "Are you sure you wish to delete the group: %s?" msgstr "Sei sicuro di voler cancellare il gruppo: %s?" -#: views.py:315 +#: views.py:321 #, python-format msgid "Are you sure you wish to delete the groups: %s?" msgstr "Sei sicuro di voler cancellare i gruppi: %s?" -#: views.py:345 +#: views.py:351 #, python-format msgid "non members of group: %s" msgstr "non membri del gruppo: %s" -#: views.py:346 +#: views.py:352 #, python-format msgid "members of group: %s" msgstr "membri del gruppo: %s" diff --git a/apps/user_management/locale/pt/LC_MESSAGES/django.mo b/apps/user_management/locale/pt/LC_MESSAGES/django.mo index b5441bf67866cc65d4305d26118aef4b1c5ec45d..652f660de4cdc7d4338bcdd89a8e83bb03c452f0 100644 GIT binary patch delta 599 zcmX}o&r2Io5Ww+~V$_Yljnp5dY_&miNH%K)B`6-WAhpm|JlRXvX4xzx*|^zIltK_s zf(K!RLJ$54A}HPj3*HK%-g@bwJqf+_P+AcDE_oCl`*|~On4R~&KHW+lT{P9dHHqk& zNJd2d#YM81Y8Nqa6`$cQcHuep;uZGePaMR*IE;NAA_Hh(6fdHIdF4JnC%(YPsC7zR zbT+9@kr8~MEMby(51CC)aSXqx{H=<+m}-*z6s}_tYxo^M;!3y36THSz{EboHhdm67 zvpx03P2P}*CU&qHw~<=eQH7teh4>I-c&g6N)cK{#|3EG$w;1*LgUlj#>b!&Ji~1xm zfse-7L{Dg9RJeq#_!e1`=hKECj@<{pVoQY}sN@X8af3o_E%V+h8NOGweAn}hlC@!# z4YyjY*;VcJtCjS;Z(D)umD3AWVCVFStT~a+MoTv*bLLdIp$%*QGt=RLHk4ZS)@(oU s^yNlVea3GjGU_iG$187IMSC;6(cXn~@zwZCtL)S)hyIo0Pw|u3JypPA^#A|> delta 567 zcmXZYPbdU&6u|Mf$zs=kwrER(-6-vv*%jKPgd0)hK*>+0ZEM?QcE~~PIw{I!FXEzH z94OhdgD3|F7bOSE#mUV{F1}-Dn&$I+@BRACd%xZAW9aJMlRxu_Xg-msh}`={bo@pG zL$xAtT)+n0$7Vdn0A6A{-eC~munm9QxVcWGpE&BejFZHN*n!V=k{6A|H;FE6tuH%- zVd6!kHz{Bb9=Q3E8^7WJc@N!f;2>_|IqqObqev&7U^m{NbM6PWU{zDTJV~&rJb{6g z6sD0qGKbE_HLSvI^kTuS@459OH-CZ5A|-UrxkY-B2eJQe=zm6! zYkE9k4EO0gzA2TnBlDKZ, 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-03 03:18+0000\n" -"Last-Translator: renataoliveira \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-02 14:17-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" "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:8 -msgid "Create new users" -msgstr "Criar novos usuários" - -#: __init__.py:9 -msgid "Edit existing users" -msgstr "Editar usuários existentes" - -#: __init__.py:10 -msgid "View existing users" -msgstr "Ver os usuários existentes" - -#: __init__.py:11 -msgid "Delete existing users" -msgstr "Exclui usuários existentes" - #: __init__.py:13 -msgid "Create new groups" -msgstr "Criar novos grupos" - -#: __init__.py:14 -msgid "Edit existing groups" -msgstr "Editar grupos existentes" - -#: __init__.py:15 -msgid "View existing groups" -msgstr "Ver grupos existentes" - -#: __init__.py:16 -msgid "Delete existing groups" -msgstr "Excluir grupos existentes" - -#: __init__.py:18 -msgid "User management" -msgstr "Gerenciar usuários" - -#: __init__.py:28 msgid "user list" msgstr "lista de usuários" -#: __init__.py:29 views.py:31 +#: __init__.py:14 views.py:31 msgid "users" msgstr "usuários" -#: __init__.py:30 __init__.py:39 +#: __init__.py:15 __init__.py:24 msgid "edit" msgstr "editar" -#: __init__.py:31 views.py:92 +#: __init__.py:16 views.py:97 msgid "create new user" msgstr "criar novo usuário" -#: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 +#: __init__.py:17 __init__.py:18 __init__.py:26 __init__.py:27 msgid "delete" msgstr "excluir" -#: __init__.py:34 __init__.py:35 +#: __init__.py:19 __init__.py:20 msgid "reset password" msgstr "redefinir senha" -#: __init__.py:37 +#: __init__.py:22 msgid "group list" msgstr "lista de grupos" -#: __init__.py:38 views.py:222 +#: __init__.py:23 views.py:228 msgid "groups" msgstr "grupos" -#: __init__.py:40 views.py:270 +#: __init__.py:25 views.py:276 msgid "create new group" msgstr "criar novo grupo" -#: __init__.py:43 views.py:226 +#: __init__.py:28 views.py:232 msgid "members" msgstr "membros" @@ -103,6 +66,42 @@ msgstr "Nova senha" msgid "Confirm password" msgstr "Confirmar senha" +#: permissions.py:7 +msgid "User management" +msgstr "Gerenciar usuários" + +#: permissions.py:9 +msgid "Create new users" +msgstr "Criar novos usuários" + +#: permissions.py:10 +msgid "Edit existing users" +msgstr "Editar usuários existentes" + +#: permissions.py:11 +msgid "View existing users" +msgstr "Ver os usuários existentes" + +#: permissions.py:12 +msgid "Delete existing users" +msgstr "Exclui usuários existentes" + +#: permissions.py:14 +msgid "Create new groups" +msgstr "Criar novos grupos" + +#: permissions.py:15 +msgid "Edit existing groups" +msgstr "Editar grupos existentes" + +#: permissions.py:16 +msgid "View existing groups" +msgstr "Ver grupos existentes" + +#: permissions.py:17 +msgid "Delete existing groups" +msgstr "Excluir grupos existentes" + #: views.py:35 msgid "full name" msgstr "nome completo" @@ -115,7 +114,11 @@ msgstr "e-mail" msgid "active" msgstr "ativo" -#: views.py:58 +#: views.py:47 +msgid "has usable password?" +msgstr "" + +#: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." @@ -123,30 +126,30 @@ msgstr "" "Edição de super usuário e usuário pessoal não é permitida, use a interface " "de administração para esses casos." -#: views.py:65 +#: views.py:68 #, python-format msgid "User \"%s\" updated successfully." msgstr "Usuário \"%s\" atualizado com sucesso." -#: views.py:71 +#: views.py:74 #, python-format msgid "edit user: %s" msgstr "editar usuário: %s" -#: views.py:74 views.py:130 views.py:193 +#: views.py:77 views.py:135 views.py:198 msgid "user" msgstr "usuário" -#: views.py:86 +#: views.py:91 #, python-format msgid "User \"%s\" created successfully." msgstr "Usuário \"%s\" criado com sucesso." -#: views.py:108 views.py:162 +#: views.py:113 views.py:167 msgid "Must provide at least one user." msgstr "Deve fornecer pelo menos um usuário." -#: views.py:118 +#: views.py:123 msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." @@ -154,31 +157,31 @@ msgstr "" "Excluir super usuário e usuário pessoal não é permitido, use a interface de " "administração para esses casos." -#: views.py:121 +#: views.py:126 #, python-format msgid "User \"%s\" deleted successfully." msgstr "Usuário \"%s\" removido com sucesso." -#: views.py:123 +#: views.py:128 #, python-format msgid "Error deleting user \"%(user)s\": %(error)s" msgstr "Erro ao excluir usuário \"%(user)s\": %(error)s " -#: views.py:138 +#: views.py:143 #, python-format msgid "Are you sure you wish to delete the user: %s?" msgstr "Tem certeza de que deseja excluir o usuário: %s?" -#: views.py:140 +#: views.py:145 #, python-format msgid "Are you sure you wish to delete the users: %s?" msgstr "Tem certeza de que deseja excluir os usuários: %s?" -#: views.py:173 +#: views.py:178 msgid "Passwords do not match, try again." msgstr "Senhas não coincidem, tente novamente." -#: views.py:178 +#: views.py:183 msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." @@ -186,75 +189,77 @@ msgstr "" "Redefinir senha de super usuário e usuário pessoal não é permitido, use a " "interface de administração para esses casos." -#: views.py:182 +#: views.py:187 #, python-format msgid "Successfull password reset for user: %s." msgstr "Redefinição de senha do usuário bem-sucedida: %s." -#: views.py:184 +#: views.py:189 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" msgstr "Erro de redefinição de senha para o usuário \"%(user)s\": %(error)s " -#: views.py:200 +#: views.py:205 #, python-format msgid "Reseting password for user: %s" msgstr "Redefinindo senha para o usuário: %s" -#: views.py:202 +#: views.py:207 #, python-format msgid "Reseting password for users: %s" msgstr "Redefinindo senha para os usuários: %s" -#: views.py:243 +#: views.py:249 #, python-format msgid "Group \"%s\" updated successfully." msgstr "Grupo \"%s\" atualizado com sucesso." -#: views.py:249 +#: views.py:255 #, python-format msgid "edit group: %s" msgstr "editar grupo: %s" -#: views.py:252 views.py:305 views.py:350 +#: views.py:258 views.py:311 views.py:356 msgid "group" msgstr "grupo" -#: views.py:264 +#: views.py:270 #, python-format msgid "Group \"%s\" created successfully." msgstr "Grupo \"%s\" criado com sucesso." -#: views.py:286 +#: views.py:292 msgid "Must provide at least one group." msgstr "Deve fornecer pelo menos um grupo." -#: views.py:296 +#: views.py:302 #, python-format msgid "Group \"%s\" deleted successfully." msgstr "Grupo \"%s\" removido com sucesso." -#: views.py:298 +#: views.py:304 #, python-format msgid "Error deleting group \"%(group)s\": %(error)s" msgstr "Erro ao excluir o grupo \"%(group)s\": %(error)s " -#: views.py:313 +#: views.py:319 #, python-format msgid "Are you sure you wish to delete the group: %s?" msgstr "Tem certeza de que deseja excluir o grupo: %s?" -#: views.py:315 +#: views.py:321 #, python-format msgid "Are you sure you wish to delete the groups: %s?" msgstr "Tem certeza de que deseja excluir os grupos: %s?" -#: views.py:345 +#: views.py:351 #, python-format msgid "non members of group: %s" msgstr "não-membros do grupo: %s" -#: views.py:346 +#: views.py:352 #, python-format msgid "members of group: %s" msgstr "membros do grupo: %s" + + diff --git a/apps/user_management/locale/ru/LC_MESSAGES/django.mo b/apps/user_management/locale/ru/LC_MESSAGES/django.mo index 6783d4921d06c0cd39a0c385c840a4cb4d36e72b..5aa4e055bc98d4f01114de8258e4b9861ab13b2d 100644 GIT binary patch delta 613 zcmX}o&r1|>7{~F)iVm}Dnd|1Sz_BO=-5p0omq9^E!ca-HLx`8JGR_X{?#Rq6sFwx7 zlSsrKJw(ts5(zJPi%yG|APDr}A-dG9KcM%QS%NR~`hK3n_j#UqYyGr7erc(hH$+TB zWJyG3(}}O~75NI+aH3V@5x&7E_z5TQ62~!fM`RA?aR!fY882`i`|gUYViDKzGn&}l zCN=5j;V{i5jmKEPA9#W7?II1l#_#wcBQk^s9f>EH zBVVD7scbEIa5|f85F$g%8R|{HqHg%7S$}w6q=#&yes~e}06VA`IYD~LH{|EZFVqYC zZRRwA*`ymy93JGNH(x@IM0~pN5C`ymGdE8Co4;=_6ytc?u`JJzi`9+%W>B`mAX1?p zgjQMYs*2@DQPqu%Vek305ceb?x1{a-0KcA@^x z=p0)KHry}{%$4L_b1F;<`DUZM7gY9C$=#dr%E~Y48R`vVwLY9$OE0R5S5+R(!s_Wk Hswe#q7XoSw delta 561 zcmXZYPbdU&6u|L^TD80W|L5}aUoq@Vn`K&2{)Z@(keZ^kS-aU?>$pyGaoXbGfRme) zyAw{!MJaOS!ofi~xcH9UX`0XPyN}K(B5?-KGiskt+7GIZ19YxnRtC#_gqn~PfESjdV;qNWPO5@1w)\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-02 14:17-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" "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:8 -msgid "Create new users" -msgstr "Создание новых пользователей" - -#: __init__.py:9 -msgid "Edit existing users" -msgstr "Редактирование существующих пользователей" - -#: __init__.py:10 -msgid "View existing users" -msgstr "Просмотр существующих пользователей" - -#: __init__.py:11 -msgid "Delete existing users" -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:13 -msgid "Create new groups" -msgstr "Создание новых групп" - -#: __init__.py:14 -msgid "Edit existing groups" -msgstr "Редактирование существующих групп" - -#: __init__.py:15 -msgid "View existing groups" -msgstr "Просмотр существующих групп" - -#: __init__.py:16 -msgid "Delete existing groups" -msgstr "Удалить существующие группы" - -#: __init__.py:18 -msgid "User management" -msgstr "Управление пользователями" - -#: __init__.py:28 msgid "user list" msgstr "список пользователей" -#: __init__.py:29 views.py:31 +#: __init__.py:14 views.py:31 msgid "users" msgstr "пользователи" -#: __init__.py:30 __init__.py:39 +#: __init__.py:15 __init__.py:24 msgid "edit" msgstr "редактировать" -#: __init__.py:31 views.py:92 +#: __init__.py:16 views.py:97 msgid "create new user" msgstr "создать нового пользователя" -#: __init__.py:32 __init__.py:33 __init__.py:41 __init__.py:42 +#: __init__.py:17 __init__.py:18 __init__.py:26 __init__.py:27 msgid "delete" msgstr "удалить" -#: __init__.py:34 __init__.py:35 +#: __init__.py:19 __init__.py:20 msgid "reset password" msgstr "сброс пароля" -#: __init__.py:37 +#: __init__.py:22 msgid "group list" msgstr "список групп" -#: __init__.py:38 views.py:222 +#: __init__.py:23 views.py:228 msgid "groups" msgstr "группы" -#: __init__.py:40 views.py:270 +#: __init__.py:25 views.py:276 msgid "create new group" msgstr "создать новую группу" -#: __init__.py:43 views.py:226 +#: __init__.py:28 views.py:232 msgid "members" msgstr "Участники" @@ -103,6 +65,42 @@ msgstr "Новый пароль" msgid "Confirm password" msgstr "Подтвердите пароль" +#: permissions.py:7 +msgid "User management" +msgstr "Управление пользователями" + +#: permissions.py:9 +msgid "Create new users" +msgstr "Создание новых пользователей" + +#: permissions.py:10 +msgid "Edit existing users" +msgstr "Редактирование существующих пользователей" + +#: permissions.py:11 +msgid "View existing users" +msgstr "Просмотр существующих пользователей" + +#: permissions.py:12 +msgid "Delete existing users" +msgstr "Удаление существующих пользователей" + +#: permissions.py:14 +msgid "Create new groups" +msgstr "Создание новых групп" + +#: permissions.py:15 +msgid "Edit existing groups" +msgstr "Редактирование существующих групп" + +#: permissions.py:16 +msgid "View existing groups" +msgstr "Просмотр существующих групп" + +#: permissions.py:17 +msgid "Delete existing groups" +msgstr "Удалить существующие группы" + #: views.py:35 msgid "full name" msgstr "полное имя" @@ -115,38 +113,42 @@ msgstr "электронная почта" msgid "active" msgstr "активно" -#: views.py:58 +#: views.py:47 +msgid "has usable password?" +msgstr "" + +#: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." msgstr "" -"Редактирование суперпользователя и персонала не допускается, используйте для " -"этого интерфейс администратора." +"Редактирование суперпользователя и персонала не допускается, используйте для" +" этого интерфейс администратора." -#: views.py:65 +#: views.py:68 #, python-format msgid "User \"%s\" updated successfully." msgstr "Пользователь \"%s\"обновлён" -#: views.py:71 +#: views.py:74 #, python-format msgid "edit user: %s" msgstr "редактировать пользователя: %s." -#: views.py:74 views.py:130 views.py:193 +#: views.py:77 views.py:135 views.py:198 msgid "user" msgstr "пользователь" -#: views.py:86 +#: views.py:91 #, python-format msgid "User \"%s\" created successfully." msgstr "Пользователь \"%s\" создан." -#: views.py:108 views.py:162 +#: views.py:113 views.py:167 msgid "Must provide at least one user." msgstr "Должен быть хотя бы один пользователь." -#: views.py:118 +#: views.py:123 msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." @@ -154,31 +156,31 @@ msgstr "" "Удаление суперпользователя и персонала не допускается, используйте " "интерфейс администратора для этих случаев." -#: views.py:121 +#: views.py:126 #, python-format msgid "User \"%s\" deleted successfully." msgstr "Пользователь \"%s\" удален." -#: views.py:123 +#: views.py:128 #, python-format msgid "Error deleting user \"%(user)s\": %(error)s" msgstr "Ошибка при удалении пользователя \"%(user)s\": %(error)s" -#: views.py:138 +#: views.py:143 #, python-format msgid "Are you sure you wish to delete the user: %s?" msgstr "Вы действительно хотите удалить пользователя:%s?" -#: views.py:140 +#: views.py:145 #, python-format msgid "Are you sure you wish to delete the users: %s?" msgstr "Вы действительно хотите удалить пользователей:%s?" -#: views.py:173 +#: views.py:178 msgid "Passwords do not match, try again." msgstr "Пароли не совпадают, попробуйте еще раз." -#: views.py:178 +#: views.py:183 msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." @@ -186,75 +188,77 @@ msgstr "" "Сброс паролей суперпользователя и персонала не допускается, используйте " "интерфейс администратора для этих случаев." -#: views.py:182 +#: views.py:187 #, python-format msgid "Successfull password reset for user: %s." msgstr "Пароль пользователя %s сброшен." -#: views.py:184 +#: views.py:189 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" msgstr "Ошибка сброса пароля для пользователя \"%(user)s\": %(error)s" -#: views.py:200 +#: views.py:205 #, python-format msgid "Reseting password for user: %s" msgstr "Сброс пароля пользователя: %s" -#: views.py:202 +#: views.py:207 #, python-format msgid "Reseting password for users: %s" msgstr "Сброс пароля для пользователей: %s" -#: views.py:243 +#: views.py:249 #, python-format msgid "Group \"%s\" updated successfully." msgstr "Группа \"%s\" обновлены." -#: views.py:249 +#: views.py:255 #, python-format msgid "edit group: %s" msgstr "редактировать группу: %s" -#: views.py:252 views.py:305 views.py:350 +#: views.py:258 views.py:311 views.py:356 msgid "group" msgstr "группа" -#: views.py:264 +#: views.py:270 #, python-format msgid "Group \"%s\" created successfully." msgstr "Группа \"%s\"создана." -#: views.py:286 +#: views.py:292 msgid "Must provide at least one group." msgstr "Должна быть хотя бы одна группа." -#: views.py:296 +#: views.py:302 #, python-format msgid "Group \"%s\" deleted successfully." msgstr "Группа \"%s\" удалена." -#: views.py:298 +#: views.py:304 #, python-format msgid "Error deleting group \"%(group)s\": %(error)s" msgstr "Ошибка при удалении группы \"%(group)s\": %(error)s" -#: views.py:313 +#: views.py:319 #, python-format msgid "Are you sure you wish to delete the group: %s?" msgstr "Вы действительно хотите удалить группу: %s?" -#: views.py:315 +#: views.py:321 #, python-format msgid "Are you sure you wish to delete the groups: %s?" msgstr "Вы действительно хотите удалить группы: %s?" -#: views.py:345 +#: views.py:351 #, python-format msgid "non members of group: %s" msgstr "не входят в группу: %s" -#: views.py:346 +#: views.py:352 #, python-format msgid "members of group: %s" msgstr "входят в группу: %s" + + diff --git a/apps/web_theme/locale/en/LC_MESSAGES/django.po b/apps/web_theme/locale/en/LC_MESSAGES/django.po index 230b0e0867..a8daed9146 100644 --- a/apps/web_theme/locale/en/LC_MESSAGES/django.po +++ b/apps/web_theme/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-02 14:17-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -44,19 +44,19 @@ msgstr "" msgid "close" msgstr "" -#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:34 msgid "Login" msgstr "" -#: templates/web_theme_login.html:17 +#: templates/web_theme_login.html:18 msgid "You are already logged in" msgstr "" -#: templates/web_theme_login.html:20 +#: templates/web_theme_login.html:21 msgid "Redirecting you to the website entry point in 5 seconds." msgstr "" -#: templates/web_theme_login.html:23 +#: templates/web_theme_login.html:24 #, python-format msgid "" "Or click here if redirection doesn't " diff --git a/apps/web_theme/locale/es/LC_MESSAGES/django.mo b/apps/web_theme/locale/es/LC_MESSAGES/django.mo index 937619e07a84258fe260febc0c874b5e68617ffa..c0c6863e92b7e0a00f2e3df30fbd061aad098fa7 100644 GIT binary patch delta 151 zcmdnRdyscROX_Y$28KUO3=GQ{7#Mc2Ffcd+>3CKK27VyD7)Wyh>CHeo3`p+<(i}iq zgpGm05lG7dX<;B852S&Jp%_T;0O=|qEf1vIfwUx$UcT{VJQJ^xt^o)s7@Alanoka8 bw&xGZPf9H+$yW%1OX?Oz28KUO3=GQ{7#KFPFfcd+=?GQ^27Vwt2S{@Q=`}z)3`lPS(i}jV zmyLnJ5lD*xX<;B80i=P5AqPnC0O?{NEf1s{fV3o#Ua;|HJQJ^>uA!l>k&%L-p_P%@ W\n" +"Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" "mayan-edms/team/es/)\n" "Language: es\n" @@ -48,19 +48,19 @@ msgstr "cerrar esta notificación" msgid "close" msgstr "cerrar" -#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:34 msgid "Login" msgstr "Iniciar sesión" -#: templates/web_theme_login.html:17 +#: templates/web_theme_login.html:18 msgid "You are already logged in" msgstr "Usted ya ha entrado" -#: templates/web_theme_login.html:20 +#: templates/web_theme_login.html:21 msgid "Redirecting you to the website entry point in 5 seconds." msgstr "Se va a redirigir al punto de entrada al sitio web en 5 segundos." -#: templates/web_theme_login.html:23 +#: templates/web_theme_login.html:24 #, python-format msgid "" "Or click here if redirection doesn't " diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.mo b/apps/web_theme/locale/it/LC_MESSAGES/django.mo index 1dd30bb263840b82d76ddd4a5118e4dc43aa9896..ee22c2a67190fc975a02b6721dac0a3ab504da9d 100644 GIT binary patch delta 175 zcmX@ZyOeiAOX>7#NnaFfb?q=`dCX1|VXn1QJ|8x*kXu0O>9$|2L4f z2lCn27#PHWv>T8HB8FHX!40HSfV3o#E&$R}K)P$=OAjU$t^ofKUFV|I#FEVXJYAQ> vl2j`NBLhPtT>}tOFf_3;G@o328KUO3=A6>7#Pm5Ffb?q=~`9>1|VWs03^78^fDk_0HilU`ATdI z4E8|2E|3-j(z!qyh!|Rc1UHcG2GWv1dODDn0@52dzVu*H&nPJ=u+rC0&n(F(P0~xw z&($x=FHS7V%rDZ, 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" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-02 14:17-0400\n" "PO-Revision-Date: 2011-12-09 18:07+0000\n" "Last-Translator: Pierpaolo Baldan \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: conf/settings.py:10 @@ -48,19 +49,19 @@ msgstr "respingere questa notifica" msgid "close" msgstr "chiudi" -#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:34 msgid "Login" msgstr "Login" -#: templates/web_theme_login.html:17 +#: templates/web_theme_login.html:18 msgid "You are already logged in" msgstr "Sei pronto per entrare" -#: templates/web_theme_login.html:20 +#: templates/web_theme_login.html:21 msgid "Redirecting you to the website entry point in 5 seconds." msgstr "Reindirizzamento al tuo punto di ingresso al sito in 5 secondi." -#: templates/web_theme_login.html:23 +#: templates/web_theme_login.html:24 #, python-format msgid "" "Or click here if redirection doesn't " @@ -78,5 +79,3 @@ msgstr "Precedente" #: templates/pagination/pagination.html:28 msgid "Next" msgstr "Successivo" - - diff --git a/apps/web_theme/locale/pt/LC_MESSAGES/django.mo b/apps/web_theme/locale/pt/LC_MESSAGES/django.mo index 24ff710f54bb16fac7d9360141199e778dc8f3a8..56d6afffc98af4edf380975a66bc245f26108784 100644 GIT binary patch delta 26 fcmbQiJA-$F2Q#mct^o)s7@Alanr{wec4h_uSr!Hx delta 26 hcmbQiJA-$F2Q#msuA!l>k&%L-p_P%@=1^v5W&l|Q1{nYV diff --git a/apps/web_theme/locale/pt/LC_MESSAGES/django.po b/apps/web_theme/locale/pt/LC_MESSAGES/django.po index 44231ccd0b..a51db3747c 100644 --- a/apps/web_theme/locale/pt/LC_MESSAGES/django.po +++ b/apps/web_theme/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-02 14:17-0400\n" "PO-Revision-Date: 2011-11-04 00:46+0000\n" "Last-Translator: emersonsoares \n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" @@ -49,19 +49,19 @@ msgstr "descartar essa notificação" msgid "close" msgstr "fechar" -#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:34 msgid "Login" msgstr "Login" -#: templates/web_theme_login.html:17 +#: templates/web_theme_login.html:18 msgid "You are already logged in" msgstr "Você já está logado" -#: templates/web_theme_login.html:20 +#: templates/web_theme_login.html:21 msgid "Redirecting you to the website entry point in 5 seconds." msgstr "Redirecionando você para o ponto de entrada do site em 5 segundos." -#: templates/web_theme_login.html:23 +#: templates/web_theme_login.html:24 #, python-format msgid "" "Or click here if redirection doesn't " diff --git a/apps/web_theme/locale/ru/LC_MESSAGES/django.mo b/apps/web_theme/locale/ru/LC_MESSAGES/django.mo index 53af98872f39e8c61599d3881f69bc0ecb3a9247..f9648438ef51d150198598fc120c19a6762fc178 100644 GIT binary patch delta 148 zcmeC;pU6LJ7#JdebUiBr0~e6K0i=b1^kX312Bg0MX%Qe@ z%f`SE1*9hdX$>I#7D)2}X)$&N22mib3Z%7wv^A7Y+xRk`iPuQi0E83_O{@&fCxT)91*E%yv<8rV2Bi6bG(S57gD8-e1JYVR+5}3+Z+scg#A~Q)XsBysq+n=hWn?xv Sl-Zs&y|~QWVDkdzkIVp3#}}~x diff --git a/apps/web_theme/locale/ru/LC_MESSAGES/django.po b/apps/web_theme/locale/ru/LC_MESSAGES/django.po index 4f4ba45d35..63943d0479 100644 --- a/apps/web_theme/locale/ru/LC_MESSAGES/django.po +++ b/apps/web_theme/locale/ru/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-02 14:17-0400\n" "PO-Revision-Date: 2011-11-04 15:22+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" @@ -49,19 +49,19 @@ msgstr "убрать это уведомление" msgid "close" msgstr "закрыть" -#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:33 +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:34 msgid "Login" msgstr "Войти" -#: templates/web_theme_login.html:17 +#: templates/web_theme_login.html:18 msgid "You are already logged in" msgstr "Вы уже вошли в систему" -#: templates/web_theme_login.html:20 +#: templates/web_theme_login.html:21 msgid "Redirecting you to the website entry point in 5 seconds." msgstr "Перенаправит вас на вход веб-сайта через 5 секунд." -#: templates/web_theme_login.html:23 +#: templates/web_theme_login.html:24 #, python-format msgid "" "Or click here if redirection doesn't " From cc9ce7c21292dbe5bf10986f272330c025032c4e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 15:37:06 -0400 Subject: [PATCH 377/484] Don't hide and raise errors on assign_remove view when in DEBUG mode --- apps/common/views.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/common/views.py b/apps/common/views.py index c5d995bb59..799ccf1a56 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -13,6 +13,7 @@ from django.contrib.auth.views import login from django.utils.simplejson import dumps, loads from django.contrib.auth.views import password_change from django.contrib.auth.models import User +from django.conf import settings from .forms import (ChoiceForm, UserForm, UserForm_view, LicenseForm, EmailAuthenticationForm) @@ -87,8 +88,11 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef messages.success(request, _(u'%(selection)s added successfully added to %(right_list_title)s.') % { 'selection': label, 'right_list_title': right_list_title}) except: - messages.error(request, _(u'Unable to add %(selection)s to %(right_list_title)s.') % { - 'selection': label, 'right_list_title': right_list_title}) + if settings.DEBUG: + raise + else: + messages.error(request, _(u'Unable to add %(selection)s to %(right_list_title)s.') % { + 'selection': label, 'right_list_title': right_list_title}) elif u'%s-submit' % right_list_name in request.POST.keys(): selected_list = ChoiceForm(request.POST, @@ -111,8 +115,11 @@ def assign_remove(request, left_list, right_list, add_method, remove_method, lef messages.success(request, _(u'%(selection)s added successfully removed from %(right_list_title)s.') % { 'selection': label, 'right_list_title': right_list_title}) except: - messages.error(request, _(u'Unable to add %(selection)s to %(right_list_title)s.') % { - 'selection': label, 'right_list_title': right_list_title}) + if settings.DEBUG: + raise + else: + messages.error(request, _(u'Unable to add %(selection)s to %(right_list_title)s.') % { + 'selection': label, 'right_list_title': right_list_title}) unselected_list = ChoiceForm(prefix=left_list_name, choices=left_list()) selected_list = ChoiceForm(prefix=right_list_name, From ca193252c289d07393263b11f8605261ddda401c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 15:37:36 -0400 Subject: [PATCH 378/484] Add option group support to the document type default metadata types and sets view --- apps/metadata/classes.py | 6 ++++ apps/metadata/views.py | 73 +++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/apps/metadata/classes.py b/apps/metadata/classes.py index b370dcae21..5bb9db0709 100644 --- a/apps/metadata/classes.py +++ b/apps/metadata/classes.py @@ -1,5 +1,7 @@ from django.utils.translation import ugettext_lazy as _ +from acls.classes import EncapsulatedObject + class MetadataClass(object): def __init__(self, dictionary): @@ -10,3 +12,7 @@ class MetadataClass(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/views.py b/apps/metadata/views.py index 370271f04a..31e9a74549 100644 --- a/apps/metadata/views.py +++ b/apps/metadata/views.py @@ -16,7 +16,7 @@ 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 .permissions import (PERMISSION_METADATA_DOCUMENT_EDIT, @@ -31,6 +31,7 @@ from .forms import (MetadataFormSet, AddMetadataForm, 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): @@ -523,40 +524,57 @@ 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): @@ -569,8 +587,8 @@ def setup_document_type_metadata(request, document_type_id): 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, @@ -580,4 +598,5 @@ def setup_document_type_metadata(request, document_type_id): 'navigation_object_name': 'document_type', 'object_name': _(u'document type'), }, + grouped=True, ) From 40f6eb6c0c8a55772ec708f0fcf93017465aa7c5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 16:02:59 -0400 Subject: [PATCH 379/484] Add permission topic to the documentation --- docs/index.rst | 11 +++++------ docs/topics/permissions.rst | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 docs/topics/permissions.rst diff --git a/docs/index.rst b/docs/index.rst index 060a132d72..f136d65e9f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,14 +17,12 @@ Mayan EDMS documentation .. _indexing: http://en.wikipedia.org/wiki/Index_card .. _Open source: http://en.wikipedia.org/wiki/Open_source -Links of interest -================= +On the Web +===================== * Website: http://www.mayan-edms.com * Source: http://github.com/rosarior/mayan -* Video: http://bit.ly/pADNXv -* Issue tracker: http://github.com/rosarior/mayan/issues -* Mailing list: http://groups.google.com/group/mayan-edms +* Video: http://bit.ly/Mayan-Intro First steps @@ -39,12 +37,13 @@ First steps Understanding Mayan EDMS ======================== - :doc:`Transformations ` | :doc:`Indexes ` | :doc:`Smart links ` | + :doc:`Permission system ` | :doc:`Document visualization ` | :doc:`OCR ` | :doc:`File storage ` + :doc:`Transformations ` Between versions diff --git a/docs/topics/permissions.rst b/docs/topics/permissions.rst new file mode 100644 index 0000000000..37fc689b06 --- /dev/null +++ b/docs/topics/permissions.rst @@ -0,0 +1,32 @@ +=========== +Permissions +=========== + +**Mayan EDMS** provides very exact control over what activies users can +perform. This control is divided into two levels of operation: + +* 2-tier permission assignment - 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. + +* 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. + +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. From 79c793b74bd5ecdcadd18a5dbe25053410eecfed Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 16:20:55 -0400 Subject: [PATCH 380/484] Improve list format --- docs/topics/software_used.rst | 148 +++++++++++++++++++++------------- 1 file changed, 94 insertions(+), 54 deletions(-) diff --git a/docs/topics/software_used.rst b/docs/topics/software_used.rst index b6b0fccf79..0725bd6d66 100644 --- a/docs/topics/software_used.rst +++ b/docs/topics/software_used.rst @@ -3,114 +3,154 @@ 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. + + * 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/ + + * Copyright Django Software Foundation + * http://www.djangoproject.com/ * django-pagination - * Copyright Eric Florenzano (floguy@gmail.com) - * http://django-pagination.googlecode.com/ + + * 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 + + * 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 + + * 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/ + + * 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 + + * 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/ + + * 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/ + + * 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/ + + * 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/ + + * 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 + + * 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/ + + * http://code.google.com/p/tesseract-ocr/ * Image file 1068504_92921456 "Mayan piramid" (Stock Exchange) - * Andres Ojeda (http://www.sxc.hu/profile/andres_ol) + + * 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 + + * http://kde-look.org/usermanager/search.php?username=InFeRnODeMoN * Fat cow icon set - * http://www.fatcow.com/free-icons + + * http://www.fatcow.com/free-icons * Python-magic - python-magic is a simple wrapper for libmagic - * Adam Hupp - * https://github.com/ahupp/python-magic + + * 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 + + * http://fancybox.net * unpaper - post-processing scanned and photocopied book pages - * Jens Gulden 2005-2007 - unpaper@jensgulden.de. - * http://unpaper.berlios.de/ + + * Jens Gulden 2005-2007 - unpaper@jensgulden.de. + * http://unpaper.berlios.de/ * favicon - * http://www.iconfinder.com/icondetails/21581/24/draw_pyramid_icon - * Gnome Project + + * 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/ + + * 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/ + + * 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 + + * 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 + + * 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 + + * 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) + * Alex Gaynor (alex.gaynor@gmail.com) + * http://pypi.python.org/pypi/django-taggit -* djangorestframework +* Image 392336_7079 (stock exchange) "Chichen Itza" (Stock Exchange) -* South + * Joerg Witthoeft "Beamer29" (http://www.sxc.hu/profile/Beamer29) + * http://www.sxc.hu/browse.phtml?f=view&id=392336 -* python-gnupg +* 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 -* python-hkp From db3b64b35eefa61b94f926da93da525846ce91a3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 16:21:11 -0400 Subject: [PATCH 381/484] Add link to Samba, link to settings option --- docs/topics/file_storage.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/topics/file_storage.rst b/docs/topics/file_storage.rst index 054df85465..c00ca9d466 100644 --- a/docs/topics/file_storage.rst +++ b/docs/topics/file_storage.rst @@ -2,7 +2,7 @@ File storage ============ -The files are stored and placed under Mayan EDMS "control" to avoid +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, @@ -12,14 +12,19 @@ index which would create a directory tree like structure in the database and then turn on the index filesystem mirror options which would create an actual directory tree and links to the actual stored files but using the filename of the documents as stored in the database. This -filesystem mirror of the index can them be shared with Samba across the +filesystem mirror of the index can them be shared with Samba_ across the network. This access would be read-only, and new versions of the files would have to be uploaded from the web GUI using the new document versioning support. -Mayan's EDMS components are as decoupled from each other as possible, +**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 +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. + +.. _Samba: http://www.samba.org/ From 1a24c185981f99a273732ae8e36de900ce593f3f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 2 Feb 2012 16:21:34 -0400 Subject: [PATCH 382/484] Add file storage topic --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index f136d65e9f..63e5f32cd8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -42,7 +42,7 @@ Understanding Mayan EDMS :doc:`Permission system ` | :doc:`Document visualization ` | :doc:`OCR ` | - :doc:`File storage ` + :doc:`File storage ` | :doc:`Transformations ` From a13f0482420f1df84c79dcbbd4dd5909f93cbff4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 4 Feb 2012 17:20:13 -0400 Subject: [PATCH 383/484] Fix indentation --- apps/converter/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/converter/api.py b/apps/converter/api.py index 2c3269fab9..3c0b2ea08d 100644 --- a/apps/converter/api.py +++ b/apps/converter/api.py @@ -106,7 +106,7 @@ def get_page_count(input_filepath): input_filepath = office_converter.output_filepath except OfficeConversionError: - raise UnknownFileFormat('office converter exception') + raise UnknownFileFormat('office converter exception') return backend.get_page_count(input_filepath) From 735d3db97a4ad54a45be6d3d1b9c171738b5a231 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 5 Feb 2012 00:19:54 -0400 Subject: [PATCH 384/484] Merge django_gpg's verify_file + verify_w_retry methods --- apps/django_gpg/api.py | 57 ++++++++++++---------------- apps/document_signatures/managers.py | 2 +- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 21b41df4fd..7071135af6 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -173,31 +173,11 @@ class GPG(object): self.keyservers = keyservers self.gpg = gnupg.GPG(**kwargs) - - def verify_w_retry(self, file_input, detached_signature=None): - logger.debug('file_input type: %s' % type(file_input)) - - input_descriptor = GPG.get_descriptor(file_input) - - try: - verify = self.verify_file(input_descriptor, detached_signature, close_descriptor=False) - if verify.status == 'no public key': - # Try to fetch the public key from the keyservers - try: - self.receive_key(verify.key_id) - return self.verify_w_retry(input_descriptor, detached_signature) - except KeyFetchingError: - return verify - else: - input_descriptor.close() - return verify - except IOError: - return False - - def verify_file(self, file_input, detached_signature=None, close_descriptor=True): - ''' + + def verify_file(self, file_input, detached_signature=None, close_descriptor=True, fetch_key=False): + """ Verify the signature of a file. - ''' + """ input_descriptor = GPG.get_descriptor(file_input) @@ -213,15 +193,28 @@ class GPG(object): else: verify = self.gpg.verify_file(input_descriptor) - if close_descriptor: - input_descriptor.close() - + logger.debug('verify.status: %s' % getattr(verify, 'status', None)) if verify: + logger.debug('verify ok') + if close_descriptor: + input_descriptor.close() return verify - #elif getattr(verify, 'status', None) == 'no public key': - # # Exception to the rule, to be able to query the keyservers - # return verify + elif getattr(verify, 'status', None) == 'no public key': + # Exception to the rule, to be able to query the keyservers + if fetch_key: + try: + self.receive_key(verify.key_id) + return self.verify_file(input_descriptor, detached_signature, close_descriptor, fetch_key=False) + except KeyFetchingError: + if close_descriptor: + input_descriptor.close() + return verify + else: + return verify else: + logger.debug('No verify') + if close_descriptor: + input_descriptor.close() raise GPGVerificationError() def verify(self, data): @@ -234,12 +227,12 @@ class GPG(object): raise GPGVerificationError(verify.status) def sign_file(self, file_input, key=None, destination=None, key_id=None, passphrase=None, clearsign=False): - ''' + """ Signs a filename, storing the signature and the original file in the destination filename provided (the destination file is overrided if it already exists), if no destination file name is provided the signature is returned. - ''' + """ kwargs = {} kwargs['clearsign'] = clearsign diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index f1c7bd39dc..af967f30ca 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -59,6 +59,6 @@ class DocumentVersionSignatureManager(models.Manager): args = (document.open(raw=True),) try: - return gpg.verify_w_retry(*args) + return gpg.verify_file(*args, fetch_key=True) except GPGVerificationError: return None From 9c036639240402b64e3933a19217d16e3196fc2b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 5 Feb 2012 00:48:31 -0400 Subject: [PATCH 385/484] Move tree node widget code to the widgets.py file and prettify a bit --- apps/document_indexing/views.py | 7 ++----- apps/document_indexing/widgets.py | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 3f2e7f3c6e..4da5b595ce 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ @@ -8,7 +6,6 @@ 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.html import conditional_escape, mark_safe from django.core.exceptions import PermissionDenied from permissions.models import Permission @@ -22,7 +19,7 @@ from acls.models import AccessEntry from .forms import IndexForm, IndexTemplateNodeForm from .models import (Index, IndexTemplateNode, IndexInstanceNode) from .tools import do_rebuild_all_indexes -from .widgets import (index_instance_item_link, get_breadcrumbs) +from .widgets import (index_instance_item_link, get_breadcrumbs, node_level) from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES, PERMISSION_DOCUMENT_INDEXING_SETUP, @@ -164,7 +161,7 @@ def index_setup_view(request, index_pk): 'title': _(u'tree template nodes for index: %s') % index, 'hide_object': True, 'extra_columns': [ - {'name': _(u'level'), 'attribute': encapsulate(lambda x: u''.join([mark_safe(conditional_escape(u'--') * (getattr(x, x._mptt_meta.level_attr) - 0)), unicode(x if x.parent else 'root') ] ))}, + {'name': _(u'level'), 'attribute': encapsulate(lambda x: node_level(x))}, ], } diff --git a/apps/document_indexing/widgets.py b/apps/document_indexing/widgets.py index 4448c63e0b..e678feebb7 100644 --- a/apps/document_indexing/widgets.py +++ b/apps/document_indexing/widgets.py @@ -1,6 +1,8 @@ +# -*- coding: utf-8 -*- from __future__ import absolute_import -from django.utils.safestring import mark_safe +#from django.utils.safestring import mark_safe +from django.utils.html import conditional_escape, mark_safe from .models import IndexInstanceNode @@ -71,3 +73,18 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou else: output.insert(0, u' / '.join(result)) return mark_safe(u' '.join(output)) + + +def node_level(x): + """ + Render an indented tree like output for a specific node + """ + return mark_safe( + u''.join( + [ + u'     ' * (getattr(x, x._mptt_meta.level_attr) - 1), + u'' if x.parent else u'', + unicode(x if x.parent else 'root') + ] + ) + ) From 4d546f74152a3d54a0bddcae8069e21e38aac822 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 5 Feb 2012 00:51:31 -0400 Subject: [PATCH 386/484] Remove celery code line --- wsgi/dispatch.wsgi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wsgi/dispatch.wsgi b/wsgi/dispatch.wsgi index fc2615a09a..39c427a61a 100644 --- a/wsgi/dispatch.wsgi +++ b/wsgi/dispatch.wsgi @@ -2,9 +2,13 @@ import os import sys import site +from django.core.handlers.wsgi import WSGIHandler + 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 +20,5 @@ 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() From 2147923eb01e17811ecd6c5e1888c4afdf1622c9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 5 Feb 2012 02:47:11 -0400 Subject: [PATCH 387/484] Documentation updates, permissions diagrams and inkscape sources --- docs/figure_src/ACL.svg | 591 ++++++++++++++++++++++++++++++++ docs/figure_src/permissions.svg | 392 +++++++++++++++++++++ docs/releases/0.12.rst | 9 + docs/topics/ACL.png | Bin 0 -> 37624 bytes docs/topics/file_storage.rst | 16 +- docs/topics/indexes.rst | 14 +- docs/topics/permissions.png | Bin 0 -> 20275 bytes docs/topics/permissions.rst | 7 + docs/topics/settings.rst | 217 +++++------- 9 files changed, 1104 insertions(+), 142 deletions(-) create mode 100644 docs/figure_src/ACL.svg create mode 100644 docs/figure_src/permissions.svg create mode 100644 docs/topics/ACL.png create mode 100644 docs/topics/permissions.png diff --git a/docs/figure_src/ACL.svg b/docs/figure_src/ACL.svg new file mode 100644 index 0000000000..61132ca3a5 --- /dev/null +++ b/docs/figure_src/ACL.svg @@ -0,0 +1,591 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + Roles + Groups + Users + Users + Groups + Users + Permissions + Documents + Tags + Folders + Tier 1: Actor + Tier 2: Access + Tier 3: Object + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + Users + Users + Groups + Roles + Permissions + Tier 1: Actor + Tier 2: Access + + + diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 748520b87c..350f07e141 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -136,6 +136,15 @@ 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. + Upgrading from a previous version ================================= diff --git a/docs/topics/ACL.png b/docs/topics/ACL.png new file mode 100644 index 0000000000000000000000000000000000000000..acd3458113767a91b6c7d926cdc404ea94ae12b8 GIT binary patch literal 37624 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%0DVS;_=+afzM1}QgdYjn=SD_ yX0qcGWtkMM!a5rrXoNptwRHYPr^j=HRo5#{N=Jfbt}4sPn)eZ3k81bOoBsy1f?cWr literal 0 HcmV?d00001 diff --git a/docs/topics/file_storage.rst b/docs/topics/file_storage.rst index c00ca9d466..8d980a15cf 100644 --- a/docs/topics/file_storage.rst +++ b/docs/topics/file_storage.rst @@ -7,15 +7,9 @@ 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 access to the files the recommended way is to create and -index which would create a directory tree like structure in the database -and then turn on the index filesystem mirror options which would create -an actual directory tree and links to the actual stored files but using -the filename of the documents as stored in the database. This -filesystem mirror of the index can them be shared with Samba_ across the -network. This access would be read-only, and new versions of the files -would have to be uploaded from the web GUI using the new document -versioning support. +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 @@ -27,4 +21,6 @@ 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. -.. _Samba: http://www.samba.org/ +.. rubric:: Footnotes + +.. [#f1] http://en.wikipedia.org/wiki/File_server diff --git a/docs/topics/indexes.rst b/docs/topics/indexes.rst index ed4ab46e51..8807b594ae 100644 --- a/docs/topics/indexes.rst +++ b/docs/topics/indexes.rst @@ -5,8 +5,20 @@ Indexes Administrators first define the template of the index and 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 againts the metadata -of the documents. The index cannot be edited manually, only changing +of the documents. Indexes can be mirrored to the operating system filesystem +using the configuration option +:setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`. 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. This +filesystem mirror of the index can them be served with Samba_ across the +network. This access would be read-only, and new versions of the files +would have to be uploaded from the web GUI using the new document +versioning support. + +The index cannot be edited manually, 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/permissions.png b/docs/topics/permissions.png new file mode 100644 index 0000000000000000000000000000000000000000..3c3809f405b648916d73554fdbe906a5f03f3f42 GIT binary patch literal 20275 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 literal 0 HcmV?d00001 diff --git a/docs/topics/permissions.rst b/docs/topics/permissions.rst index 37fc689b06..41980bb04c 100644 --- a/docs/topics/permissions.rst +++ b/docs/topics/permissions.rst @@ -12,6 +12,9 @@ perform. This control is divided into two levels of operation: 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 @@ -19,6 +22,9 @@ perform. This control is divided into two levels of operation: 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 @@ -30,3 +36,4 @@ 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 index d01de8049d..a57beb99b5 100644 --- a/docs/topics/settings.rst +++ b/docs/topics/settings.rst @@ -5,82 +5,76 @@ Settings **Mayan EDMS** has many configuration options that make it very adaptable to different server configurations. -.. contents:: - :local: - :depth: 1 - - Documents ========= .. setting:: DOCUMENTS_CHECKSUM_FUNCTION -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 ------------------------ +.. 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 -------------------------- +**DOCUMENTS_STORAGE_BACKEND** Default: ``FileBasedStorage`` class +The storage backend that will be used to store every document. + .. setting:: DOCUMENTS_PREVIEW_SIZE -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 --------------------- +**DOCUMENTS_PRINT_SIZE** Default: ``1400`` .. setting:: DOCUMENTS_MULTIPAGE_PREVIEW_SIZE -DOCUMENTS_MULTIPAGE_PREVIEW_SIZE --------------------------------- +**DOCUMENTS_MULTIPAGE_PREVIEW_SIZE** Default: ``160x120`` .. setting:: DOCUMENTS_THUMBNAIL_SIZE -DOCUMENTS_THUMBNAIL_SIZE ------------------------- +**DOCUMENTS_THUMBNAIL_SIZE** Default: ``50x50`` .. setting:: DOCUMENTS_DISPLAY_SIZE -DOCUMENTS_DISPLAY_SIZE ----------------------- +**DOCUMENTS_DISPLAY_SIZE** Default: ``1200`` .. setting:: DOCUMENTS_RECENT_COUNT -DOCUMENTS_RECENT_COUNT ----------------------- +**DOCUMENTS_RECENT_COUNT** Default: ``40`` @@ -90,8 +84,7 @@ remember per user. .. setting:: DOCUMENTS_ZOOM_PERCENT_STEP -DOCUMENTS_ZOOM_PERCENT_STEP ---------------------------- +**DOCUMENTS_ZOOM_PERCENT_STEP** Default: ``50`` @@ -100,8 +93,7 @@ Amount in percent zoom in or out a document page per user interaction. .. setting:: DOCUMENTS_ZOOM_MAX_LEVEL -DOCUMENTS_ZOOM_MAX_LEVEL ------------------------- +**DOCUMENTS_ZOOM_MAX_LEVEL** Default: ``200`` @@ -110,8 +102,7 @@ Maximum amount in percent (%) to allow user to zoom in a document page interacti .. setting:: DOCUMENTS_ZOOM_MIN_LEVEL -DOCUMENTS_ZOOM_MIN_LEVEL ------------------------- +**DOCUMENTS_ZOOM_MIN_LEVEL** Default: ``50`` @@ -120,8 +111,7 @@ Minimum amount in percent (%) to allow user to zoom out a document page interact .. setting:: DOCUMENTS_ROTATION_STEP -DOCUMENTS_ROTATION_STEP ------------------------ +**DOCUMENTS_ROTATION_STEP** Default: ``90`` @@ -130,8 +120,7 @@ Amount in degrees to rotate a document page per user interaction. .. setting:: DOCUMENTS_CACHE_PATH -DOCUMENTS_CACHE_PATH --------------------- +**DOCUMENTS_CACHE_PATH** Default: ``image_cache`` (relative to the installation path) @@ -143,8 +132,7 @@ Converter .. setting:: CONVERTER_IM_CONVERT_PATH -CONVERTER_IM_CONVERT_PATH -------------------------- +**CONVERTER_IM_CONVERT_PATH** Default: ``/usr/bin/convert`` @@ -153,8 +141,7 @@ File path to imagemagick's convert program. .. setting:: CONVERTER_IM_IDENTIFY_PATH -CONVERTER_IM_IDENTIFY_PATH --------------------------- +**CONVERTER_IM_IDENTIFY_PATH** Default: ``/usr/bin/identify`` @@ -163,8 +150,7 @@ File path to imagemagick's identify program. .. setting:: CONVERTER_GM_PATH -CONVERTER_GM_PATH ------------------ +**CONVERTER_GM_PATH** Default: ``/usr/bin/gm`` @@ -173,41 +159,44 @@ File path to graphicsmagick's program. .. setting:: CONVERTER_GM_SETTINGS -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_GRAPHICS_BACKEND -CONVERTER_GRAPHICS_BACKEND --------------------------- +**CONVERTER_GRAPHICS_BACKEND** Default: ``converter.backends.python`` Graphics conversion backend to use. Options are: -* ``converter.backends.imagemagick`` -* ``converter.backends.graphicsmagick`` -* ``converter.backends.python`` +* ``converter.backends.imagemagick`` - Wrapper for ImageMagick +* ``converter.backends.graphicsmagick`` - Wrapper for GraphicsMagick +* ``converter.backends.python`` - Wrapper for Pillow and Ghostscript .. setting:: CONVERTER_UNOCONV_PATH -CONVERTER_UNOCONV_PATH ----------------------- + +**CONVERTER_UNOCONV_PATH** Default: ``/usr/bin/unoconv`` -Path to the unoconv program. +Path to the unoconv program used to call LibreOffice for office document convertion. .. setting:: CONVERTER_UNOCONV_USE_PIPE -CONVERTER_UNOCONV_USE_PIPE --------------------------- + +**CONVERTER_UNOCONV_USE_PIPE** Default: ``True`` @@ -219,8 +208,7 @@ Linking .. setting:: LINKING_SHOW_EMPTY_SMART_LINKS -LINKING_SHOW_EMPTY_SMART_LINKS ------------------------------- +**LINKING_SHOW_EMPTY_SMART_LINKS** Default: ``True`` @@ -232,32 +220,28 @@ Storage .. setting:: STORAGE_GRIDFS_HOST -STORAGE_GRIDFS_HOST -------------------- +**STORAGE_GRIDFS_HOST** Default: ``localhost`` .. setting:: STORAGE_GRIDFS_PORT -STORAGE_GRIDFS_PORT -------------------- +**STORAGE_GRIDFS_PORT** Default: ``27017`` .. setting:: STORAGE_GRIDFS_DATABASE_NAME -STORAGE_GRIDFS_DATABASE_NAME ----------------------------- +**STORAGE_GRIDFS_DATABASE_NAME** Default: ``document_storage`` .. setting:: STORAGE_FILESTORAGE_LOCATION -STORAGE_FILESTORAGE_LOCATION ----------------------------- +**STORAGE_FILESTORAGE_LOCATION** Default: ``document_storage`` @@ -267,40 +251,35 @@ Document indexing .. setting:: DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS -DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS ----------------------------------------------- +**DOCUMENT_INDEXING_AVAILABLE_INDEXING_FUNCTIONS** Default: ``proper_name`` .. setting:: DOCUMENT_INDEXING_SUFFIX_SEPARATOR -DOCUMENT_INDEXING_SUFFIX_SEPARATOR ----------------------------------- +**DOCUMENT_INDEXING_SUFFIX_SEPARATOR** Default: ``_`` (underscore) - + .. setting:: DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS -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 ---------------------------------------------- +**DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT** Default: ``1000`` .. setting:: DOCUMENT_INDEXING_FILESYSTEM_SERVING -DOCUMENT_INDEXING_FILESYSTEM_SERVING ------------------------------------- +**DOCUMENT_INDEXING_FILESYSTEM_SERVING** Default: ``{}`` @@ -312,8 +291,7 @@ OCR .. setting:: OCR_TESSERACT_PATH -OCR_TESSERACT_PATH ------------------- +**OCR_TESSERACT_PATH** Default: ``/bin/tesseract`` @@ -323,8 +301,7 @@ page's images. .. setting:: OCR_TESSERACT_LANGUAGE -OCR_TESSERACT_LANGUAGE ----------------------- +**OCR_TESSERACT_LANGUAGE** Default: ``eng`` @@ -333,8 +310,7 @@ Language code passed to the ``tesseract`` executable. .. setting:: OCR_REPLICATION_DELAY -OCR_REPLICATION_DELAY ---------------------- +**OCR_REPLICATION_DELAY** Default: ``0`` @@ -344,8 +320,7 @@ storage replication overhead. .. setting:: OCR_NODE_CONCURRENT_EXECUTION -OCR_NODE_CONCURRENT_EXECUTION ------------------------------ +**OCR_NODE_CONCURRENT_EXECUTION** Default: ``1`` @@ -354,8 +329,7 @@ Maximum amount of concurrent document OCRs a node can perform. .. setting:: OCR_AUTOMATIC_OCR -OCR_AUTOMATIC_OCR ------------------ +**OCR_AUTOMATIC_OCR** Default: ``False`` @@ -365,16 +339,14 @@ of existing documents for OCR. .. setting:: OCR_QUEUE_PROCESSING_INTERVAL -OCR_QUEUE_PROCESSING_INTERVAL ------------------------------ +**OCR_QUEUE_PROCESSING_INTERVAL** Default: ``10`` .. setting:: OCR_UNPAPER_PATH -OCR_UNPAPER_PATH ----------------- +**OCR_UNPAPER_PATH** Default: ``/usr/bin/unpaper`` @@ -387,16 +359,14 @@ Metadata .. setting:: METADATA_AVAILABLE_FUNCTIONS -METADATA_AVAILABLE_FUNCTIONS ----------------------------- +**METADATA_AVAILABLE_FUNCTIONS** Default: ``current_date`` .. setting:: METADATA_AVAILABLE_MODELS -METADATA_AVAILABLE_MODELS -------------------------- +**METADATA_AVAILABLE_MODELS** Default: ``User`` @@ -406,8 +376,7 @@ Common .. setting:: COMMON_TEMPORARY_DIRECTORY -COMMON_TEMPORARY_DIRECTORY --------------------------- +**COMMON_TEMPORARY_DIRECTORY** Default: ``/tmp`` @@ -418,23 +387,21 @@ using tempfile.mkdtemp() .. setting:: COMMON_DEFAULT_PAPER_SIZE -COMMON_DEFAULT_PAPER_SIZE -------------------------- +**COMMON_DEFAULT_PAPER_SIZE** Default: ``Letter`` .. setting:: COMMON_DEFAULT_PAGE_ORIENTATION -COMMON_DEFAULT_PAGE_ORIENTATION -------------------------------- +**COMMON_DEFAULT_PAGE_ORIENTATION** + Default: ``Portrait`` .. setting:: COMMON_AUTO_CREATE_ADMIN -COMMON_AUTO_CREATE_ADMIN ------------------------- +**COMMON_AUTO_CREATE_ADMIN** Default: ``True`` @@ -445,8 +412,7 @@ specified by COMMON_AUTO_ADMIN_PASSWORD .. setting:: COMMON_AUTO_ADMIN_USERNAME -COMMON_AUTO_ADMIN_USERNAME --------------------------- +**COMMON_AUTO_ADMIN_USERNAME** Default: ``admin`` @@ -455,8 +421,7 @@ Username of the automatically created superuser .. setting:: COMMON_AUTO_ADMIN_PASSWORD -COMMON_AUTO_ADMIN_PASSWORD --------------------------- +**COMMON_AUTO_ADMIN_PASSWORD** Default: ``admin`` @@ -465,8 +430,7 @@ Default password of the automatically created superuser .. setting:: COMMON_LOGIN_METHOD -COMMON_LOGIN_METHOD -------------------- +**COMMON_LOGIN_METHOD** Default: ``username`` @@ -477,12 +441,11 @@ such as AUTHENTICATION_BACKENDS = ('common.auth.email_auth_backend.EmailAuthBack .. setting:: COMMON_ALLOW_ANONYMOUS_ACCESS -COMMON_ALLOW_ANONYMOUS_ACCESS ------------------------------ +**COMMON_ALLOW_ANONYMOUS_ACCESS** Default: ``False`` -Allow non authenticated users, access to all views +Allow non authenticated users, access to all views. Search @@ -490,8 +453,7 @@ Search .. setting:: SEARCH_LIMIT -SEARCH_LIMIT ------------- +**SEARCH_LIMIT** Default: ``100`` @@ -500,8 +462,7 @@ Maximum amount search hits to fetch and display. .. setting:: SEARCH_RECENT_COUNT -SEARCH_RECENT_COUNT -------------------- +**SEARCH_RECENT_COUNT** Default: ``5`` @@ -509,22 +470,22 @@ Maximum number of search queries to remember per user. Web theme ---------- +========= .. setting:: WEB_THEME_THEME -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``. +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 ------------------------ +**WEB_THEME_VERBOSE_LOGIN** Default: ``True`` @@ -536,8 +497,7 @@ Main .. setting:: MAIN_SIDE_BAR_SEARCH -MAIN_SIDE_BAR_SEARCH --------------------- +**MAIN_SIDE_BAR_SEARCH** Default: ``False`` @@ -546,16 +506,14 @@ Controls whether the search functionality is provided by a sidebar widget or by .. setting:: MAIN_DISABLE_HOME_VIEW -MAIN_DISABLE_HOME_VIEW ----------------------- +**MAIN_DISABLE_HOME_VIEW** Default: ``False`` .. setting:: MAIN_DISABLE_ICONS -MAIN_DISABLE_ICONS ------------------- +**MAIN_DISABLE_ICONS** Default: ``False`` @@ -565,8 +523,7 @@ User management .. setting:: ROLES_DEFAULT_ROLES -ROLES_DEFAULT_ROLES -------------------- +**ROLES_DEFAULT_ROLES** Default: ``[]`` @@ -578,8 +535,7 @@ Signatures .. setting:: SIGNATURES_KEYSERVERS -SIGNATURES_KEYSERVERS ---------------------- +**SIGNATURES_KEYSERVERS** Default: ``['pool.sks-keyservers.net']`` @@ -588,8 +544,7 @@ List of keyservers to be queried for unknown keys. .. setting:: SIGNATURES_GPG_HOME -SIGNATURES_GPG_HOME -------------------- +**SIGNATURES_GPG_HOME** Default: ``gpg_home`` From c0d8e6f6674733fb384008adcca0fc6d61e36e9a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 5 Feb 2012 23:27:03 -0400 Subject: [PATCH 388/484] Move the RecentDocumentManager to the models.py file To be able to return a QuerySet and not a list of recent documents --- apps/documents/managers.py | 20 -------------------- apps/documents/models.py | 21 +++++++++++++++++++-- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/apps/documents/managers.py b/apps/documents/managers.py index 83555b9568..c69a007254 100644 --- a/apps/documents/managers.py +++ b/apps/documents/managers.py @@ -1,29 +1,9 @@ from __future__ import absolute_import from ast import literal_eval -from datetime import datetime from django.db import models -from .conf.settings import RECENT_COUNT - - -class RecentDocumentManager(models.Manager): - def add_document_for_user(self, user, document): - if user.is_authenticated(): - self.model.objects.filter(user=user, document=document).delete() - new_recent = self.model(user=user, document=document, datetime_accessed=datetime.now()) - new_recent.save() - to_delete = self.model.objects.filter(user=user)[RECENT_COUNT:] - for recent_to_delete in to_delete: - recent_to_delete.delete() - - def get_for_user(self, user): - if user.is_authenticated(): - return [recent_document.document for recent_document in self.model.objects.filter(user=user)] - else: - return [] - class DocumentPageTransformationManager(models.Manager): def get_for_document_page(self, document_page): diff --git a/apps/documents/models.py b/apps/documents/models.py index 135e2e3825..4d7136659a 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -29,11 +29,11 @@ from mimetype.api import (get_mimetype, get_icon_file_path, from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_PAGE_NUMBER) +from .conf.settings import RECENT_COUNT from .conf.settings import (CHECKSUM_FUNCTION, UUID_FUNCTION, STORAGE_BACKEND, DISPLAY_SIZE, CACHE_PATH, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL) -from .managers import (RecentDocumentManager, - DocumentPageTransformationManager) +from .managers import DocumentPageTransformationManager from .utils import document_save_to_temp_dir from .literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES, VERSION_UPDATE_MAJOR, VERSION_UPDATE_MINOR, VERSION_UPDATE_MICRO) @@ -616,6 +616,23 @@ class DocumentPageTransformation(models.Model): verbose_name_plural = _(u'document page transformations') +class RecentDocumentManager(models.Manager): + def add_document_for_user(self, user, document): + if user.is_authenticated(): + self.model.objects.filter(user=user, document=document).delete() + new_recent = self.model(user=user, document=document, datetime_accessed=datetime.datetime.now()) + new_recent.save() + to_delete = self.model.objects.filter(user=user)[RECENT_COUNT:] + for recent_to_delete in to_delete: + recent_to_delete.delete() + + def get_for_user(self, user): + if user.is_authenticated(): + return Document.objects.filter(recentdocument__user=user) + else: + return [] + + class RecentDocument(models.Model): """ Keeps a list of the n most recent accessed or created document for From 75ecbfdee014b9b85d9d453961b427e074dc1b25 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 14:37:40 -0400 Subject: [PATCH 389/484] Add PostgreSQL instructions --- docs/intro/installation.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/intro/installation.rst b/docs/intro/installation.rst index 346318a96a..a11166bc26 100644 --- a/docs/intro/installation.rst +++ b/docs/intro/installation.rst @@ -36,6 +36,11 @@ 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:: From 758661c280c43ec56e7e551550e9cf66ab0037a5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 14:38:08 -0400 Subject: [PATCH 390/484] Add requirements installation step to the upgrade procedure --- docs/releases/0.12.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 350f07e141..6ff52fe1fa 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -200,6 +200,10 @@ Again when a similar messages appears Type ``yes`` and press **Enter** +Add the new requirements:: + + $ pip install -r requirements/production.txt + The upgrade procedure is now complete. Backward incompatible changes From 248a5ea82d51d10422f7dece1b1e7ed59ea85e11 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 14:38:59 -0400 Subject: [PATCH 391/484] Add transaction rollback --- apps/history/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/history/api.py b/apps/history/api.py index 6bb8e42322..0f85c8b9c0 100644 --- a/apps/history/api.py +++ b/apps/history/api.py @@ -24,8 +24,8 @@ def register_history_type(history_type_dict): history_type_obj.save() except DatabaseError: # Special case for syncdb - pass - + transaction.rollback() + # Runtime history_types_dict.setdefault(namespace, {}) history_types_dict[namespace][name] = { From eef1114be2158338e518ca2cc1911a0819b1b39b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 14:56:27 -0400 Subject: [PATCH 392/484] Add transaction rollback --- apps/lock_manager/managers.py | 1 + apps/ocr/__init__.py | 13 +++++++++---- apps/sources/models.py | 6 ++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/lock_manager/managers.py b/apps/lock_manager/managers.py index 603a36c575..99145e8c5a 100644 --- a/apps/lock_manager/managers.py +++ b/apps/lock_manager/managers.py @@ -22,6 +22,7 @@ class LockManager(models.Manager): logger.debug('acquired lock: %s' % name) return lock except IntegrityError, msg: + transaction.rollback() logger.debug('IntegrityError: %s', msg) # There is already an existing lock # Check it's expiration date and if expired, reset it diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 5f160d4fce..c1c280503c 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext 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_multi_item_links from documents.models import Document, DocumentVersion @@ -64,10 +65,14 @@ 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) diff --git a/apps/sources/models.py b/apps/sources/models.py index 6fb3ca3f67..5e32cddb7a 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -9,6 +9,7 @@ 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 django.db.utils import DatabaseError from converter.api import get_available_transformations_choices from converter.literals import DIMENSION_SEPARATOR @@ -93,7 +94,7 @@ class BaseModel(models.Model): document = Document() if document_type: document.document_type = document_type - document.save() + document.save() apply_default_acls(document, user) @@ -119,7 +120,8 @@ class BaseModel(models.Model): new_version = document.new_version(file=file_object, **new_version_data) except Exception: # Don't leave the database in a broken state - document.delete() + # document.delete() + transaction.rollback() raise if filename: From 021959891293d394b153d7a3ba39091477c54f9c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 15:03:26 -0400 Subject: [PATCH 393/484] Fix bug introduced by last commits --- apps/sources/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 5e32cddb7a..617c90e77a 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -94,7 +94,7 @@ class BaseModel(models.Model): document = Document() if document_type: document.document_type = document_type - document.save() + document.save() apply_default_acls(document, user) From 02e83d5c776b624218066b6d91c80d9568acfc66 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 15:03:50 -0400 Subject: [PATCH 394/484] For folders app migration to depend of document's app migrations --- apps/folders/migrations/0001_initial.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/folders/migrations/0001_initial.py b/apps/folders/migrations/0001_initial.py index a821c8cd6e..1da53cfe4f 100644 --- a/apps/folders/migrations/0001_initial.py +++ b/apps/folders/migrations/0001_initial.py @@ -5,7 +5,10 @@ from south.v2 import SchemaMigration from django.db import models class Migration(SchemaMigration): - + depends_on = ( + ('documents', '0001_initial'), + ) + def forwards(self, orm): # Adding model 'Folder' From 35bd9a15193c31d88f04322f22a54b77ac3196e9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 16:01:20 -0400 Subject: [PATCH 395/484] Remove repeated update step --- docs/releases/0.12.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 6ff52fe1fa..93b2926a32 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -178,8 +178,6 @@ And continue migrating database schema with:: $ ./manage.py migrate documents $ ./manage.py migrate document_signatures - $ ./manage.py migrate permissions 0001 --fake - $ ./manage.py migrate permissions $ ./manage.py migrate folders 0001 --fake $ ./manage.py migrate folders $ ./manage.py migrate document_indexing 0001 --fake From 44ca1ccac6654ebfb96959833f6b803ea15181c3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 6 Feb 2012 16:20:00 -0400 Subject: [PATCH 396/484] Move dispatch to the correct place --- wsgi/dispatch.wsgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wsgi/dispatch.wsgi b/wsgi/dispatch.wsgi index 39c427a61a..68cd5368ac 100644 --- a/wsgi/dispatch.wsgi +++ b/wsgi/dispatch.wsgi @@ -2,8 +2,6 @@ import os import sys import site -from django.core.handlers.wsgi import WSGIHandler - sys.stdout = sys.stderr #TODO fix properly @@ -21,4 +19,6 @@ sys.path.insert(0, ve_path) os.environ['PYTHON_EGG_CACHE'] = '/tmp' os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' +from django.core.handlers.wsgi import WSGIHandler + application = WSGIHandler() From aa9d8783651984a2e68bc2bc52738a2296d0e85a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 7 Feb 2012 00:17:07 -0400 Subject: [PATCH 397/484] Add missing import --- apps/document_indexing/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 4da5b595ce..7f9afd2d14 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -7,6 +7,7 @@ from django.template import RequestContext from django.contrib import messages from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied +from django.utils.html import mark_safe from permissions.models import Permission from documents.permissions import PERMISSION_DOCUMENT_VIEW From 17fcf9877c8c765f8d8553ab6493a7ffb150a376 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 7 Feb 2012 01:46:20 -0400 Subject: [PATCH 398/484] Finished indexes topic of the documentation will full ilustrations --- docs/figure_src/ACL.svg | 5 +- docs/figure_src/index_instance.svg | 724 +++++++++++++++++++++++++++++ docs/figure_src/index_template.svg | 204 ++++++++ docs/figure_src/indexes.svg | 513 ++++++++++++++++++++ docs/topics/index_instance.png | Bin 0 -> 74262 bytes docs/topics/index_template.png | Bin 0 -> 17370 bytes docs/topics/indexes.png | Bin 0 -> 72705 bytes docs/topics/indexes.rst | 53 ++- 8 files changed, 1484 insertions(+), 15 deletions(-) create mode 100644 docs/figure_src/index_instance.svg create mode 100644 docs/figure_src/index_template.svg create mode 100644 docs/figure_src/indexes.svg create mode 100644 docs/topics/index_instance.png create mode 100644 docs/topics/index_template.png create mode 100644 docs/topics/indexes.png diff --git a/docs/figure_src/ACL.svg b/docs/figure_src/ACL.svg index 61132ca3a5..f0d4c66162 100644 --- a/docs/figure_src/ACL.svg +++ b/docs/figure_src/ACL.svg @@ -15,7 +15,10 @@ id="svg4485" version="1.1" inkscape:version="0.48.2 r9819" - sodipodi:docname="ACL.svg"> + sodipodi:docname="ACL.svg" + inkscape:export-filename="/home/rosarior/development/mayan/mayan/docs/topics/ACL.png" + inkscape:export-xdpi="100" + inkscape:export-ydpi="100"> + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + due_data = '1/1/2012'supplier = 'ABC inc' + due_date = '2/1/2012'supplier = 'Z inc' + Documents + Sample index + 'Due dates' + '1/1/2012' + Document A + Document B + '2/1/2012' + Document A + Document B + 'Suppliers' + 'ABC inc' + 'Z inc' + Document A + Document B + + due_date = '1/1/2012'supplier = 'Z inc' + Document C + + Document C + + Document C + Index (generated) + + + + + + + + + + + + + + + + + + + + + + + Sample index + 'Due dates' + metadata.due_date + 'Suppliers' + metadata.supplier + Index template + + + + + + + + + + + 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 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Sample index + 'Due dates' + metadata.due_date + 'Suppliers' + metadata.supplier + Index template + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + Database + Index templates + Documents + Generated indexes + Disk + Directory tree(that mirrors an index) + + + + File servingsoftware + + Mayan EDMS server or cluster + + Clients + Networks attached drivers + + + + + + + + + Continuous synchonizationof generated indexes anddirectory tree + Document usage with existing software + Users don't needto learn new software + + + diff --git a/docs/topics/index_instance.png b/docs/topics/index_instance.png new file mode 100644 index 0000000000000000000000000000000000000000..9310c1c0136ee381faac2b7fcc4b9df1bd912a9b GIT binary patch literal 74262 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 z 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 U_&!;4H3;}P9CSJG)Gpx4KgXziP5=M^ literal 0 HcmV?d00001 diff --git a/docs/topics/index_template.png b/docs/topics/index_template.png new file mode 100644 index 0000000000000000000000000000000000000000..6d5596dd89421fd661f311205eb92ab3eac974cd GIT binary patch literal 17370 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 literal 0 HcmV?d00001 diff --git a/docs/topics/indexes.png b/docs/topics/indexes.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a5c776e6d0f2317995bfc28da596e84b4f3f0c GIT binary patch literal 72705 zcmbTdXH=6x*EUKO5CN%?78DyLf`IfU3Zha4h0wc*AVs7G2t|4m1w^STMWiJloj|BT zQGy^4T4*9j5JE`;gd`{UJny^C`E|ba&01Nk40GR^*|WL%c{GNK|Z)%A!Fq~z$qpx>Av|wW{Bu~sb zhqS#_v%Z;i?WEGl+-flp=c-Q{zluuJodJBkegpEQPy;CS%bWPQi=az}uR7d?a-H4M zxCS_U3j7&-)TM3e-R(wipHIK^%zBQL8E7;&Hl{T8;me2l)i7I!F^2~Zb2V>11#Y#j zYHVps{--H!>wk!3_@6IY0(+@R|C+J+$wLGEf9;YKE9Jif`0x9ch^noMop$3oF@-oD zm?kg%!d+D`M2PoIp1n47;bw_0M;?UAB< zfIc0TvJ$7`SJRgqYccYF{MwJRk0hd#(u4ubX!fB(eF@%cZ z?=LWH1kSM^3GQEmRTZgTI$ouP34OBexeO?)qa&sTl#BWasvxJS(gCkV?K_ps&8-Ft zkF#ALGYN7hI!{HEFTvN*TN2SjJ@w4klc1W=&eNL}Zt3i)GDZ0(KrE(Aoyq@^!jvIh zO-fa1`s!=CiJOejMq#8L5>)*favpCUI?O2Bvt#9K*dH7SXJ}@x=E?kyVp_XYje>AZ zv^#onOsv5;L$x-b91}{^3k0(K!j_RWHgvwpLN+TnDc16DG(cV1c z*_SOeP+x#b;AN|`JOp#qM`jd~kHx=dL|@x|Twg4)H-#%zC6JrcM;i(Wy>$D~GwFw(3Vi?3inns50tta511&-~ z>K!K#T(aiP0-}kX%tPF2%xVhNf$De{XBE5!UDQYT*;`)`f1P?pi99_6Sf_MBKmk9I zQ21$5j_I-+Vwsj)_OtF3S!%TFW>u7<9ZH2EUnUn|4*dG!Ks}cgZ(Mz^k8!@gp6}C> z{?WsE5n_;ki^G|W)dLrCx*f9>1gdY$3cGPl(mltZbLnF4bGystdstHYJGw4adZ-HR zcbyPL&vP6xRAHR{o?gI#OB|n^n6R6RFYE8(3Khm1EQGlf7CXl%faA$LjNg@sLD$n! zo9_y^X`wBdu@s}2~su`CcU zb^Xs&U9hSZ;B33LIZDMyS{3}+O3bNo2sQzREiz=1>K%z8EziqHU4W{x5fPwnMTXn) zjQGNdo^GoOtVfcHFI`J`^Og&6LEw+ntI4=OU9;zk0cF{i4?W^Z*Vy<`~_S%AMpg+)bX<+MGlcb_T-}Q#T&173`>an@Y zOMG%Gr1gHKbM<173(~&jcxNZpSGcgDAIa29F_(D*)VLFQY z{pvQfetmTgxe9y75qXfQk#VkPT}bQ0Kp@A8WD?zj52&r~NG$-e;Pn3F&(^x{=pI#( zhq-x#)Pc|M(J+_0OL|frw9N#%O}Uo4PFuo9*up7)k@K)W40eCiMUn0B6cU;x*oBp; zIR5)tf2aQN5SIpy`{m2lKs!Ig);MnbC1Izoj0}n73uO|uz*pe|%amOx+1Mww7*C?Q zQye8mhfB0qm#xYW&tQeYXXp?wOGEFQqDu-O&*Lwxhzj) zvdZfr4INq?EE0Ni$``!gQH ze?el&^6tx|wCp#SGarhbEg3gO=6e4Hl{fo8$K)l?uL%B6P$rAg-|)|?B>jIvav3Q# z>D27vb!HeBShX$jUmP3NJPy>%Bynd(ywSpY7Yt1a-jkRgBbw+!qYoH$Q1WN@KW)we zWZYyJ#UGJldZQC#c;Zo1aWKa$+Y#zEuzK*i6g?6OL$Jvn{Ik)=K0a&lJ_Ght2W#Ga z!t65m=8@IHqXhxyTm8EzCX~w*w0Fe>Q*Fp_`JV6d)0O$LQCZ1VjB0#&TpK5VtP{+g zj}gppt96zZ35?@*0khTfmA^>tYQYW;4Ery5B?(xEDHqNY%$2ANMR+X+JxoANT8X2y zoMlE>eb{v+7>_tGV<>U~qu4299&$}oCfoDXyI>ir&qiOQCafWoV%m)*Gl9}+ewgey zgu2wMU&WE|!@9x|3Ppu6F@Y@P%taKwg?#!Iz+)*xY!`mSITQf)lg6{)8Ak5GX_c5& zHX_0hWANqSh7uoL{JS;_tS(`k{^G%N0cV8VtyNj>9|{CJG(0(z>30I=e}*JaW~57) zf9wuY70!RJ3@2q)s4BWIztAd(2E@oSy>^ZXEP86Tt4a?-AEL*R^D(qU)-|&aVvnFF z)BxVs)nv7TdHofH`X2hSVDGkeFD$#XC&tM31~Pau@Jxhe^5TQ5gF4N(_x~<7)-Mnp zkVEi=!$7bM5Xl*%JBg78ryjP$qqTQgCcx%K#s`6iTKF#_b&=rE4T+e{kzL6pCFJBE zYy!mMMdcDhhr8$1Y<$w-fQZ!pJh0gGhQLxb<4zwYY(cV0svl#gQzLrPIfm#2`xYbNtVeSNokoazr$^la)7TcND@eAUolJNMwYbL{ z${QLmjsx{FQG>wfV84d64#rSBaHssN9Fl3pkJ-~L{mdI-Fp_o#e<8Qud`OppCY);* zGX&?~8Vk39o^@U51tX#A6YOIw1xd|;n z@K2LR=O?b$d$VWIk*&Mrm-^pY6t;arUb5g`D!k;V2Anwb02#5Nu@>}T<{L`GdlOlU z;$|pHWTp5qQ3Z#tGYtJQf)6A=SR`0f_bzj6Xe?i7<7pT8)5vC`KhV78dKnf7!!C5W zRXW86$8>dI$N!?KI?Hcj??l&LN)P)9H=esNV6?ySxO;>aunZ)@a8|IWFB zajqGs8O<|7`Bk(S7k;OpX!qd}x6}Vd-KO`YAwpo1;W^Tg{Xp+Yt2cV)6xF8NtuZU< zNIy7`jCM_zpnU0UKGPyZ25psU-7h(8V99s6&Pa#ygLqB8sw(DOj{}|R>kFHB%opXR zR>7gAb_v{d#;VIK6D{)=@Xg*uB1dgbYCg2a(Jq&vs z1c#;wX4>Kn4wyU|w5RrRk%TXYmD$4ELv9-)+rM=bC6q-)GPk^VnzHW$YNYvPo2i9W z@6TRb3|6+9O;0dr!~E5dk304W@g260WQ+yDO?1b=u`7I)AKX9`?#KZ z05XAHjOm(dci`^~4Wgw{@Q(JijXFk%li8MAzJPZSoA-WR!Z<*!W1!8GiO1z8mtzu_ zDg#6!06Z*m!^-&$-&n7LJ1Q3?Vpxyf3B;^|=c1VikwwRr`Qa;a|K>CK1x{_;IYPzL z@}dyeN^(xK;IpkzM%>viKQ%n9hsCb7uD4dfZ1oLYg5GSRYA+t*^j}cY!v8rZm&?(O z;4S~$bu1syyFYfA~++yTt}4>9QKN)1-o#{+0xvE5d7|is~!ypPssJa6Bk&^SXCmo?4*<{9Cli$LpPR7@Z0*T zSW5br`FH|0j<9BiT4$#qT%EY9K73}v1wq9`H}}DzI#u;N6Ui@vLdBks@BbfFN*1_qPPEB z+Tj01$oyZj5l{aIUn;uNDF`IXsv(&{{}Y`B$=a4;de0NJ**-62{8(#}d^lV;tlp+E zT}#DuQI>Hr*JkPX_0oH$5r#fYm{R-e#T7U%^};M5W*EO~p4wx=rGCEGZGO4M8xznd zms=Q^j@--A730l{GN2t{%?jtWyotNHAO~V~MYU~$S!5S9QhY%YwazwCA2l~!W!v-w zvE(fQom`Q^19<fH~Wc06}zskY7@0N^;r3E`*?J{EBXune8 z487*j4FwP*g$zmlZC?K?_<>hz#q+yg0M{h0(w^Kau#3XH8~U;uSQyCJXFHA*&c*ZQ(@$wYmB!!pArY9KlBhmG;Jmo3R=ES!Aa@hLIc9y&Asnzr;w zoXri&)}FBSg06xI4!}pZw7Zt+h$+;sGLYhh%wE(K6J}DFSZHFyXn#dnyrKhdVYBxa zOg{XCSZvuem&J#pc0CIMtL@cZ{e--{_I;p-&U>VJzPg9hEfRoThj#@~Sq1Q!0B%v+ zu`igrB(`U8S;=LiU$6QudfipHW7F)RndNr9ImoWb(%9nVwf@V=H=%3>`tC>GXZ|w3 zV9dXd(s-3fk#hf-{$acEUSF)`x{3ffMHY7OUE>x~QuK-;jH1X8!MAH5Bvcb`& zS>*1RWrb=nT>d6GrLYh;p}XH~L|YxA1u4rc$dZNW;97Ar6qZ84E{naZ=;}hwPh9-T zd?tjyI)zT*6-y!!%ge8$%CCk^|1nc{7p^qJ)kSWB)}TwjlvV8aSa%*aaB;imS2|zNo-st^x(X$}*OvCCovCxrBw;$gwmG@nHg8kei zoEjrw%spFrLoQ_6tD+!wmt**~|9uuJmbyLim;6Ntu|;hRo2P^o#7Ut)h^k(}!lHUz zt2gyB|E#(%(3!@;mX|MImRGV;N(+L1er0?@Yi|eEKe3!~q+8j*XR(pfE4xOfnpAV( z)aSW+$_b=;UNbCt?g`{!UqI9)t9^gaw@MwX!02cF(eZ)w_S{|6L|LC)D8`|Tb>m$Zk~bq>ZvlMAZOx6U_d`mRL0e6ds~2BnKcL7wTU*INsjvg*0|LXX|I zY@g$D=l(KWxO4aA1>TexVveAtTrl571CjU7?KiHx4B=iq>lAH2{3=tswcvbk#*KoP zsi2X}8zsf8N9vwKS#e3(pMTz|yf4|9W-RzoO!AONUUE6D`9_r2Nvv(c2dPi8YauTA z*G#sV&midEKzsax&UF46Sjb(E#Pn5C=n)ooO<3mGAKTvvm>4TAzo4`7QIO3XdJ}ee zTl&u1m*HlgPPo&Ty4|ZM2MEBer$an9;oHj-=gh^AAfN@OtKJ&Bo@UJnaalUQIR+Hv z?v`SgpYqBzF-WW?1u6u{Ne&z82j~|xl<1~_zUzKsKfHn=^(|r_D;m;mN;;=H&@dtG z*vOqMG~u3?Nh`aaJRkGWz4=YK&DILK$7**@)6MXnzL??4pYUFoZgF_{@OS=)n_sNP zy`UqbKP^GIw;2Jb7PWZH;`<~i!1507z2V#sc?i8O!qJSiOH5a@^Ss_?5+txx=i(hc zR?5x)SSe6*F`G|Q&u0oNB!il0s3{~EC0{mCenJmOgY2n}gx{pXcK7i`zd?XVF876a zO+t~G<6*<;YqwekfyL8m@nxyM$7Z$8pPDy^&NGgzLTDu zt$ozLm6O=ldvECXi&CMz5Bzk4AH1FH6z~Ir&hI)}m_!$`Tj#1$h2jjLt zuFm(Wy7{f1)M_uW_NRJhrd2_TjT%6p$8}jS2yKFur~$iN`g4q@2X&m zSp6!x`Ri>y^@dzq_AAjZX|aFC!CU+}?vkk>FHVneDgBf`fGxyviiQ?MD& zF2?J-Dzej>XYul>^X@fn+ol(T06Z||URJHz-kHlB7poVYR;k^0?%YW+5Dk=QMRZ3A zXf9y}2wSFNkdzl1RqI<~FXGg=^`J}D%NH59key;uWxV}#|9&?Ye(vV2fALEC4_2D& z3fO*AO!4wlD5mZUa62hhxqj6tG^hLCTX#=h(CJtAL>%${3e1SWPDKs_Gv8n3)@u5R z$LI~~iP>y7OBIkv8T@9Jcy7aQHDyM4PztdI&$yWG*X)-6}{fZ z?oNCX3qo)4tVGJFGO{I;PODdK=6{N&2d6zC!2>l(7VFoOQ~fYC3Fq*h$>$&FQU7H?mM)&(4+ zfb)YDMHVm3{ndBk#pD3|tLK*@jPFaKw}G051*u7N9vJs0v*0qfC8G7`GM}NG=R4!d z>=%d6`(CT*w4K>PUM{TGSq$wUeFlb}eHBsPTvB%`mgMqSpJzC0`evvhJASAcp=(&% z!S~G0bL-kEo&4hN#BW>^I!Y>4lw0msdT2>;6>`$;EaylmTUd$ zW^zsYaPy>q;qb#(pKpH&@&CG%dOPN`Hz42fX_nxoiKWP00|JmI<{Cl3=pyb`A8papQpLkqQY zp%LuFp%43()~->@KR|impoQCQ)8O4DRVJXdjK#F3VA}g*G?n$TT)N+aiF@Zj?4E$# zi{jKTD{fC&+eyPe-Xb?mF>^U1_lyH7Q2?WTi{#H$`i5);I+`nZ^(=zcWofUM7BV?E z&O_C`XVnwUd_FnVy^D-{SzaVw)4rWajrXe243N9O9pVCl3drml!kYU=v7Ddrk?yaZ zrBxz}n>CCoL-q?ZN3cK2im2zxk9GHTHp0L$;%&X_mk6MJdsdDSU}s@E{oCWW-0uCZ z;xo3kHmyGAcxq+_yN3Wf_(Rm~yXV%dza9HDSBtGHhOllAilWEBHCOwS5|;05tRz`7u$n6v$iK9lq}%u)MpCRmVPA zpZl58xp*7)Y5SfSvviqj&rNTM^8q0Nn}06j^KsN~4Z~{5RlY4bs|5%5Cwws9Ud@Dj zd`eqrc~Hfz?(%2!qP>4NtJZcOzt3FT_~>C`5=pwj6YWAK{;hUIygeSY7{j*Nb;6`x z>(Q~oN8G8&Y0b+C7#ck^+6AM&zq zXJd~Q=Dh`vLs@p8`d$5vb>k^3nJjN9hT)WMgRBR!^6|L`7SGK(DE3S#8K2kIHe&nw zOKWc{+);Zr6;lv$sBpCO)-H@Fd^uo+0R64*Sc@ zc--Jk`{!yL{R=lniWC0Ky%ZP~;KScBhOdFOF2bv!TT`8Z03JUK-#W?1eY`$it0Rh^ zzQfmzaK0%HR^#(k%}}S6%c?3xo&MW5d=JL1e0!sv7$KJ#n6WaHyBIU?1i6CN!d3eY zF=SRdq{c-}LPEcb*xK6O9?LdJ1t_$_x1XKOjHT*X9tX>eUYTv7or9Rm5$ZF+Ytv

    `oV@$NFT3ZVcWB9S69F;#w`;bFm_2)?vEHwrMmf? zXltJCtbZhFz(A|MdsD)Zc7{9er}3V# z;pd#OauZL~aA7FVcN3Fq%Bl@+bdvt<+l^hPW?ylm*H`A+XMg_Gx3nCKp78ebJ05AA zuTuDDtfGb`%ItyCi&OuODQ0)O4vXdOS&vxr(i+KIsVtA!fT&yS#~>XqQv+GRLfSQE zphZK<*B~9tc(3*HYo_^d_x|q7fJlKWHlYmdGn!tqQ-8uNYLP#`giZMQygLU_a2vQU zax&i6>oC6j;oJO*Wy{Ro`hyOf<83U&Z;bG%H`Gbs;kQRRkj>dvpV^iysg$JUJhgh! z>v9>}z$K~4C+c<;Sb`+r$8=k&p{mZ;+19`}3Lg%97VI!V`5Wht1Ab8{MuH-a1fBrw zg~Ufzem_oR>|Z3!KBcrld|RVbug0g?OlPVselAM{hJ8yG_qq>m31z&}KI1jj$QJ$E z%koi?#v4>~v%(XLqKm1&6(SGs=MTu^fulbkQ{82lqgL&2^N#dslaW`PIwQOS19x9a zr(3o_36yFuyg*ztWVEd+=l7fM8?&vixH5g+x0eh+PMz5VQJ}~6`*@IDXLg}x@aXjP z-M~P8O*^~ZaLyrI{F8dh_kt;7h#{Mq7L_GcNbY@WYuJ~am7&+QHVqGzAH%0SkG+uA zo#?siY;n4N6=3klh#y+WloU#b*)^*%#e029b*PX9Fz0$uG&h=&A07h#& z7))!VUNiPB`6b4q^|^>YL-X1%4wiS0X0wL0($NfZKOZQJim=BR*GF^9sxcEP@or%LMzwbm@ZJcl3av{zOp z*UU8Wt-1msKD$^!;)WM99S|3N&sSYWR0KRezktUoMIJsw)+>~o6?dlzoA}H$71q|8 z?u5+@v>?d4SP||f-H6 zOL=N3dCDJn?{YxfFE3U}gze@Fhq6VZ5>EIUSR%(|ncgQPBwXa;Vr}yMdp1MTKKp?w z0~!28y(<5z$Bw(u6ZE1L*d1+!Sp!d^>*wCg;ejIEk>~cmRT$ z**vT(GOvVyl3(R-cJ7d!C;U#59YUt!b_1wrC^__j?H(v zjg6bL3wH|5uFTKGgxvdO*Q~q!$O6>ltbO!0%=6d2He`Ae+w_F|;~;`o`1hW`_E<6X z+d~WdgEIab(Gu#0I>lQJjEp|^w5BIBQw1Mh6&Y6T&tHxF^`DB2fjptD zNYo>VKJc#sZ-$2%!~h1i>k?%+luDvWx2ABO$fo#8(VPJ1{xn=TVj3PBy{yeX%k`Pi zV5($(CdTcL38PU}G21oxmgPmBTd^kN9r0A%I(P}cCichZI$~>Ey|Usz1%kJXRFup_ zg{~Ux`5^Jx71IyoX@g(NRj^Dxp3g*bwX8z#ab?CGpRA7CExVLY>zT?nDh63Up7^|B zep_5W3l@cti^Bc?w*r>m?sNR^RIQFL?<{QMhsU_)q^CFft5 zy^DEf@nsE|LC;Furrc6oLo>hX_5OXPFbrrg5c{?DVS9A&z{B&`86TY@Ns=2{T*G8k zto=n#Qt5i?E_NolM0Y^$rHFZnJQEReI?;~#Dk~LtT%cFjVEoxAO6Ev;i#jjxS7<E{Qv?QcxK6IaI5qVB2DdmQiL=DVb-Zqgsq*Q0epRQ_($V+iL&xgkJe-InuS2%WSx}GmDEsGk47><>yBAD;-7@Py?vB%sm~@^KCgyp)RMiCO0*R9k8XZrGiA>E{&i{-K%wJcp#>U4cEGA~s*{A!{aU=J}r3qh@A#E_9@z8vOAL_W};-ffQQ+2%-z^ zw|7OO6QgxU8U|->El`jM<&3{#3r4ltVX=A}asgj_1;A5p30e@W~Et-hv7*u{GHsX!78{*h37%kD zjMQZdz4%|}sedazmb#c_^5(U9Z4oUPB;Kh}2n02D={7_g!A`{5{vJ_U>(ZQsR7))c z!rB;lRnS`%Fc+4_-|@w9tQ1|gA}%q2uR*nGw;;V>;#Taps-7B)^AqOpY*>yLcgyNI z7vWn3&m)c@B`K$72eZHL-ba3^4GDp7HCS;q&btOR$)OZo410|?G}@ECZ#d3PCRlP1PHK+i~(BU0jcTs9hg8Q<0 z?K zB=f2CEnNLN#X3dZWGdp&I$sSHm@xO(!W*`c4xMM7N=_~cO}0i6iv-#?&qw;lt-=-{8bqU`SUmXdLFVJY{zKh<>PI3mwG(JG z@5C*Z)X22?34`JXi$rqgW9#Gr&gslUF>XC>&^nEB(*-iv`&azlGXa$$B)aFx#ffPv zWH{BYpNV$Mr##xvQcj>nz?)_22ReWbzv=j!%(l_y7g&fh8>khm^7Ik$We%GI#RZ{t zI)*>vHO7^!38ZjKxcA=TzWpT^Jzwo9eoHuMZa%=cM}r!^3`2L+p|757wh%`>Fk)uL zu|Go!fQCc4Cazz7u~j)iJ%nWDi1fDU9ErKmoPrg0x_IKsOQ3kk>Kl<|PZr_rJ!n-6 z?zFDh#`57c52&h(_8&HvWjv$l$sshoOx7ub!nbd$`O#m?|H?|PTIP4qbanXAr*x+qRm_dX_>vFzCfhK;i^kIx9;CnwPPgY9$JQJ#2O&k z$Y8&dxpxl5d|Es&tGMs+WA@O7W7-$V9?0F^ouL?cw?ZRb#?BZAZ|ccZO>Ab+8Szvu zCDzdMDjs_md52$oU5>fB(1=oo;!;cap{GZ7{_@q-Xm zJyv_Jx|yq`tQftr0%n`i0!175tZrXf_yijk1UtyW&cV8PhMamW{x*PS-Fk3g3*s2U zVO?|_9LWc2=@1@zkGUTpmI`;BL%9`ZNas4zWWr6CBXx4GXz}3sAi8sw+nFp>E?kQb zQUd^GIx_3;bX{=W&>VJq)2Vu|%Mxz9#JYGUTr_ywZi9AvqV+%$6cx@bWPRlXl_lcL zJ`YGIoP|t#)p|xWw}Xoeed8*OnSvBN=W5-Tp1Ai0f#PwS63&Ow8n#Z=k$5m66yOFe z@_D3ZKCI14_Y89N>L-D{t#&r4iqdD!f`n#QgQKXMB&*Wk4ZxuRMt<@Gc$^C5LHkvM zNv|>Bsxg?8IgDmM=>~N!PH$YNh>+d3+hC@-4{0naQ4$MXFx?`Q%aykIp3!6mY6|N* znyYSi6+i9Ah4w`3syf%W8o_n-Yg}lr@A+QrlhatbT@X2TDDIyfQdynR z1F>zkh+1w=#mxTLO;I?mtHPDQ;AoD*Rd<)C>#%Z`WRz+Vb}iv0H2rGFaZ}J~7S4?# zpn+C;l@xS=Z(@#1EH?5)jvmbg zL&_UJvQ6j*PG!%aT#KJP|1L+A61v^RTBZF$`D;h~)402`x&8TEyqoB5@CPFykXcW; zLS4>;E@!HV(~Sej6CSj3;%dW*EF63w+6F_am-B(>5D`u>k&cE;^Bi?u3e}`*)r;QT zLbAL>P0rLXxp%X?A}-sbG8?pCa~MzPnF&2jU#YeEkZ}Z=auC?^AlxCHpaH8S*Vb;& z@~ln0zmGuUdahV%GhZ)rdT!^0dM3CsG1NKRzd*$t-;o%^PbHKQyMVHrA$QV)hWldm zVBUi`*!8s#aK#u72BZZ_g(y;zHr)>WIO+R_LdBzI;Ma3gCR@ZghfUv!;h_LdfmP?5 zcPreq8^^T|EMdUuDrvU3Ho#1E%GU(9z0;ACo zTEyKknM)~3kQhmPctR-6DLE3=I2#>l^&O0-d2G-v{EHDNE^yoftI3VO7zkBv zPSdHvnd^j8FBX#gG;TZ-e&V$NIb&VAPv_xrF*LnR=|%u>e5;w_1p#(8k06(F#bJs^vuUiKow>A}=Sec4S7*tyekDihj%Ja1P!&+9 z_)43r^=QaQ*V~Abz@+(@ZGGpU1j}Ef9w9gIv~u{eYgC_qOud3 z9Gu*=*z}=HIB?Sk6qyURJ!s2eU9ES<{!qGjRHTz}ZpN2m0_XUL2h0$noEz!SlG_s{ zjIiz~PWT=iq?oIKzv6>=GO??R$@n?x+{fT4Z3ChMnAE>0L zflj2!77cZ-`sCpY!M#Q+o{l#9b=cU5DPqoy(4TfW8>e~ivf@PY0a%_U{28KazHr{z{dnOtbnIOCvk??8AQg}T)j{#Vws^6Tu$j?+ed z^3HU*i=8zB%o`tstiMZnV%8nL#+jYS?1N<58%QA>ev*U+VW?UlXIZO`*SA1;bogU4 z205;+75!?kePe$%gw&N$7A@Z=!t<%|IoY<@$PXd8yC6FkPN8cgWrr~M zaAaLCmi7ag2m>BDWGjJ3VZ+_v^9BTnRzcBfl`XA;Zr_W!y$RPlguNdPemcku`-df2 zHkit-&=Q#V(W>4ZS@@LGG~7`h7HbP|27E@J>AWc>=+q~oE{7W6NlgnW1iv81h@dIl zqJaoLPL1MZLX=!T^;U$aEcJv{KSdq0MGbI4Z1~+4+Vga)rp2;4&qx85hAhb4;mupU z1MOYnYT}$i4MANhNK#$`X)=kh2W67|6v>Ro;-jc3gr5?Ya0kvtZS#PQy8h7~bWiM` zbq1mtSg+Lv%+SUqYS$%1{$|>(GcVeULkM_Bhw|noP;+3#fporVvX`hpbeJ`0ZNa|z zDRDI}J&tybXmfOWsO?doq7wIjh<&h&*WRj|!5Jtob}LrHY1weG#U4Y{0o|@6wEj&k zPNaA&Z$fX9K+o$KikXF6(jA(emx(;6g!%$~G?r?+<-$C1cEaF5Y_hx4gkN3eAL%dY zY*3l8wwyba;m}bhI@K$xED9sF1!ZU6beE#=RZTe7aLVq4C<}=drV_M@V+hk$#Iz`Y zXfc8x$5B`PFiLa%)aJw3y&wIN zUtl9=WTH+oQ2AG;n6UR&iEgpGovSn+Is-E?dhLwTpGf<(q`lhsO}FA()3a1--mH>W zJ9)!D6z{Ljc-|}OTx)-}70+DtjBCZ~mDUO;mS+rN235+vp}~QZ4(k|Req#-vQvp4~ zI5e69+ZpmR35vC4kno2d>)R(lN$QH#`BTQEqIU*h`RQ7G+qiC=!~U&B_+O0LEHiA8 zTl0@xPwcxp;FwQ&JM&XlP8}^Zr(z-J6OB?yQ6J?-FAJ>NGZQt{rn#LTg`3K*NR!rd zx(5l5g<$jTK4}O3{uuN4H(;}ac0m38E7+Bj~0)8OULRna7G_S|~AMhTP6d@Zp-Z5qg;j!F}E+(vPrWYj5`{l_o%ia zu#?~A%OMXJ^wXTR%;&35!SdsF zvbkLn6K{BqWI8sx65S}=+GFH~u=+Y~w8wHrNW9y(llQ*>IjmCkufd?7heDio%Mn zX2CxWuDS0$`+;ae`s2Y1)()R*fT9WeU>T48-|KKuvYobo?OK;Y0QoF&zJJX#@vrlI z+%_M zjdPzyhkSr@bmlWwU@!Ch(CfO#1&D>{%0#iJzg~vz3V{MzTi%&V-AD6JSJl?m&h3Bx z3<<#z({YnE?WBw@AKQlCG1{jhPQ6I_8GJQ2!+r<{+kT$2+vbb>-8T+)5%$hauq%&@ zo>66x=NPg!mpfAC@@5Z}#)mxy6n+I7!HaSruz?!C2i3bLH$>?7M)h zD`7=S*3RkPHo@PlKx_0OD};klSkbDFOdWNDsYuk3_6n(Vf9 zQC^`8uG@zr$-Qo(@O3Qx1|rU8dHP!QYs7SlNT!1xY4K{avzz6ri{M~gEvB~Z%zeMj z5-sC%M*PDf%d!6c{tRtO>el1^9Ziui(prZPdZ z-i_P|)7o1>nt)}V0!5vU^oHAJ{o{WYrh*dzs6S*1;&9s^?xRLF#mem~ch3hhDK8b+$ z>_08h^Sh$f&?DD0XyS(Vi=x#M|g}?|F-n}UZCtp zjoFnJ*eUf&Apy6v9UL5j*eI>`^r}ZLE-rcwFXx(xbk1ELKQHz0A1^&Lr<(tm>z6_& zUB~)CNQ-1hpoS1009Q|Lc0t5f+yf5TS1K;d$0iMaG420d(J4UZ(0V@Y&U4QSPslniZ%mGd6?FB8oZ;?E5W7x698tpf zyrb=szCZGp%}oxZp8iXxvrFYp9-^A=D80?M1{HKY`ZBA|W)2dRgE@5gNlkdkpH0}DHDqd46TbAY228wOgT0^i z;{}sMuc9?Kqi%#;*i@GjjuWdYSn_LIyRrCqrwx%^Sx1t5d@r6U&8!o z8(N~Lq12kuui)X)FQge@3&_?BcbI~^KhQ69g}N_8ntzb5L7;uHFPLL86H&mP0Yzwj zk!69$SXrb9>ycvUj1(!4q^vxa0CQaN5y17jJw3!$|s^dnmWWnuS_g=oz)_S_#7SGbU|DZ+^TF=Z-hn*0$IEtdDnzffuIl0 z^!s8VE(U6{o@k7KW7X5VSpxV{_bz-O$qv@~z9FqR@{OD^{j7bR?$e$OSF}{7Tjr^T zsCc~`ZSz(wbZ}^qVxa_`pxKlZ&-LHa4;(vHZsP5ZowX6z30qT_s82eTz6-k!{JNVs z`O>w!`wmzGpN0JDZ)b)E4*CotHDL;v#sP)YpE#8^KmqQ1=Gv4I)TZS@J5Nh!Gz!kO z|41Cy=rYDmRL)r#-_w2e_u*l!6P_rNi6|Rz)8%Zw%jR0Kz>`?~nyHv$=*p?Bh(0fBCFZ z=AH!&&ILW~!I$mjW7_=sEKq_tUwh;OuA`f@PWyF@y>dkg<<*v!(??E(f!uWbP`5M~ zl5aj_lJJEAvca}ruzIp*FMAyEz6TyFy^;4^#YA5d9_DF z3E?$Bp`L9GABf+De-hnAo||l-)l7oo-dSf!i{m3eO~7rBV+!ZC+ZHa*^^JSBQjLGB zQUeujuDcR5=l}RvHgjd1Wio^e1alJJO#D`pU|D?$P2-OTy-PUv*aV7KO~;VqfB)*H zTONc32P^IEami;diq+UUA+D2-Ew+@e;pf8;!{pXqxC2kKfRU{G$pZ!+ux1)vHMLZ$ zwFg8@PUc!jJEuQSBpI0>&^iApV5x3v4J@oCjW6;R*&?T-TO-pUOO1NBmj6q6TzTGX zagk@F$wW?BSynki_o>WDyKT)|z+bkNwe6g|OV4X(2s-R4*l)T15%jHwcj212I|Rvr zqI?PVnm#mK;anG|C+}cv=8mJch+upmHjFc8bYA?*g}Q!l5LHBJ+HTc}S}&D#8MY?) zCn2T$pt8YjrhdE8RrNB?v)IAQcDdsq)cj7q5`1B$I9cV@0Fe4?W289X$(E|0n3#}y zdY=jmUuHhI+O7WMssQ`A#j_u^5_JI~WRBo1>F9{GmM|K;IKpHi!d7*O!Vgx1Is;EB zh{@Go^9nx@CL&UQEmhALL0~T|f}g*sn~vl4C3?UZ&4E^cd)XXXLfbET`8{A?*qU1l zW*;$X8D|!LZ@Z*u5?8+3D$WVF-<@<1%oiGI!yqlad=1_!Mz^-M-o9B*b=UsPEJA5T zIGFSxUTmQWH6d#V$7K$fCjVd+6&1y|(m1{Fed36rV`4Qb9cLX`ZC*{bJ^ni~|Et`y z*(Mst`=JP)Ybxx!;nQNRVk=xCCMtS(e{Bf-gk)s*%0}aITfX3^`zwj7qu4u&6HlHQ zeluWkz^69;0+V^W=h3?sAC}9o_++>2ot+ow55@gAP9B;)l5yFe(-LLAP+V9yx2{7a z%8rEK61QcO4N6ViW;@?UQ_z6&_IPvl1SmDhqY2cf(YFtky{yY*pNoo#J@fFeH`gRI zEx*5vWH7Y$UUgCJGbrd>p7rqW$R~tq;SPHn?}EV%4GnVU=2H`|3qcutS$cj9C$wfq zDLxnafIA77q8!*fsc&c+pP6V*8`HwSS+ldPG<9y$TuMIAN+|H%;Wmibr-jq;Ma3Is z*A0(43o`Px6J@{YMBQ@Jl557W!NohwN=iy^q(gh_OofaT({Rm29d^WTT8eb$l_`4QQH${O`g#6E~_DL$!*Mduhe6vbg#w3IXR~)Jxr%TbX z;_*la+Ng(*9x=!LNUcq*Hyz2H_p1ceO^>D#Q#LfL`X~Iz^Sr7g$EiP^eD^n@{Qi4y zH#0M)voop^ljq%ELebQMi993Ib&f}&1@ZBeod*}K)x2c=>m>^orlzu7T#rpYG1@(Q z=H~P*g79(2i!*vKnjsiHtu1;Zjeqa2zp^x{*N2bg{`{#7*>;xiXnhlZKjzkIpXuYr z2JU;TA*xzhf|`DQgX@|>;omH2Ml5G6eb$Z@A~e+G^GaJv-<+RQLq<{uoB}Z-LZcI7 z*NPM4HNx>llvFtcI=s;$aFY6#?E@l1l1GI_w#Mf!?XER#VcXBk^BYSlD#$5({Wm^U zRtf;cm4G0?g&J^@LFLC5>^u=BSUaItlqizcad8pK%F2qehv~bDW$f(S+nX5ACYmCi zJC4qigM_?<*#^&_=^HAnpXrwwzSq#y~Ws{{eLy*PED!gF;!& zSPrnq%Js?c`i~qN8}B{8DV-^k8b?**QPuV%0**kcq@-VpOL)Von{L2OpAFdm(Ak+* zR`yih%`J5Y-MbXb-D`FLR-=t+6GJ%`RpOsvC!S<~{xtG@^LNLxJ#qz%1wPxnBobd_cTuan$={-g^M_)^yJ6F;aN+ z!48o~d_=&XvC_?apJ9${af{k;x5h|7!;e;7*G=;R>*y&xejc5oxjPTk1+~n~N=sUp zwc5B}ZSj?uVAHRjC{20J)Y|{)xL9Z-_w%M=#FgcB9j==isyyFM)8SU9jk;eTUwZnk z@uz-4W~=`XA92O=XEM)mRBh}#Q=yw(ICR)U)CC0-riWw1;y!RvyYg-VrfGnh+pnOG zIKxnP$38L2$(cP#e0I#wX7DlyEAg+Zsv%N}^7-!8hq_O1hODMif3Ew-Vv2#=0c=^p z=hqjYm3sp&uiNHOAOSbH|H_Hrl54jo-4P}a=~CXhtRS$~HD*wdk$b>=fh`Dk@8+04 zt-;g5zaYTvXJe?2D^G3I(nf388@lf`6Q(Vmt;qN5Ndlf{ z!-95npAFC#om6Li4<+DQ?TmdHIhkuNn0c>cD!e8_gs+~OVs-vlpO%p<0x*Y9M8p06 znF40;>Ial}uox9*iLQ~x@$?od+`TdVI3xk_nu3EY(0NR9 z~t8V`BNTH@9Q5Pib$KV)Zf_8bgP=u8G84v)WuPJDuRdh1z{$o9}ahUj9Z zHFg$GNr$OX|Bi0L58w|%3*qYsZV-yJ2PDmQ_0bZl6CN&l6zGLYo3nIy>L)Iyl<*42 zkCCR8+gjGC^HClu_e@L61&0{jcc}Wo`pn&v|Gi{(aP zDspmv+Rpm(`KJaf^>uVew_z7{WRYq$t9Uog;#S{e^5^%EAa8dAKe?nN16D%7Lp?M% z%g}ZCSXm)Z&$s=MJ;QJ{=xI~w9r}w&4V3~RGIB<8V#P0yy<30+M*LdNm)(?t)o-L2 zm@x5Qz=s~#>pS{1xe7i5_OV>OvLld9OV@K;@3X48m*s#{d-7yHoo5cadfVI@TfJ($ zT=OqjG>tjf2&91GwZCM+ukkr3AYO=K?N}h0OO6^d3Mi12bX4M)+oddd1y=^OYeJiC z*ULtr8fUYqun5_>o~&{9nKAX})R3h_j?RPXi02#&Y zVfyz9x^wNwiXyPYWP6^jBC?jryjX9??ovW#GA6j@_uMmn%Bs(|p7uM9;i2+%{QS;7 zuzRXuU5+o?XOp+`q$ukO2eV!Sur+Yi?9aob8a7i|kKWVgiCnTV)-K7`5;~nb5_VQ=x8K(^_1$9Q@982tMS<@xgw*URhY!nRNRQEHxZDuw`(*WT5tUrIgjzWaA z*xcGj=6p}afO2t3z<>*ms9Zq&{QRQq@dT8y9rMDgq)bP4fdHSQp*yvs=Qlr5pBHe{biLlmQfkSBk=RQ|k%CbLd7e>fH^nk2p@`gWsAWM;;UWe)uZn?_N&`Swyqm zF2jT0-nafB9IuIVP*Z#_*jn?$!RxTmv8oa*!rb$qy$1l?oH>H8y^2(Gex?mQy?ATv z>=KIE-+lIOi>At^@4r2B6wh^&*Ech}Jzj1IFp{;Qo76kI9M508C@Ynt$ewS(rXL*G zhx4XNK7}Fb9+=(9l6UP(c3g=%x_9I8I!V+@A(><4n+vOlV^ zF#xty=zSpP(9qCbxrWrCrvoeirta81+o=!*5Tj%7!~-j(Z1>rKTKgVt%eQ$7>uVX8 z=kANaA=~L0E84m(+eh`C9JF_u7%mcS6#B( z_x)S&b>?7^8KWCY5JpLIKjO62g9X#f<#bp3PLJ5}x; zp|$?=uZ9&*D6zY?B<#~+J<18fj03{nGQ*MIKY6--O_61Fgngqj1af-p1o=1 z5LxWIFfB1r$=~e7Sg0|Q2a&6*(XNRw5=4AZdsY>N(Ld9NjA%A~u;tZa6KFSj5`amM zreNV#Dl3Zts+3JWRTp*g=iMgL8~~ptqPfrSKOiHkDt#cFD#>^V8FzjU+%j?N+VKDW zj*3Gb0+jGxZ}B_>Q{OoJT-wrdtvhG{{a?f{9kdz*$@TVFe$L0LcUvZGvH?Gam78Yb zJ{s>hsv7o5 zE#k4CM(-Pw5Fb>O>W_r3DtKDR)Omn_SjX4tYa)*=$B6yB`|ylJ$FtxkpAMGsx9g1n zZ7Y4j&Gr8PauNrad%D)uWi|8$ATwcsn66E_mlOX!5%y`-om06knLvcasXq&RHpgM~ z1afB$d~f>6+1by6kmFC!fjqF3K|S<D~X0G2(k2a1P#cHwz@Wb!HA=i6|zRa$IntG+aGibHTG}9#Rr4cU;%D zvzxORv{{o97i9zg;c$AL$C$9bg@TF8%ik3@uWRn}4O`u{ZDHG9FfqVQM8c1(BwOsT zuSxTpR{pv)A7F!V(ak5iEfyvDzYI?=%N7A-yDw%MW~Ccqnk3!+#b4R(jjW4&bcmEnmf;`1u7g*m4;i(*EL^Lk zHweR1CPD)VQ)PPFBYg9kNs|bsIiL<+5bu5T|6BgQTrDcQ0s1 zR?hK-Soi(=<>LTfVq&Ts^HA}}v@{c{lPq-cB7mkyTzs-4qOhYl3E(oGeywk68lPOy zcInJ`KigCjz1Er7IVkZ)sX{ zDNt5{5mo>qWRte=Vvv;Xjp}Yo1ND;f{oqigv~c`Y5Lb+6!}aAomjWOu3#JQf_R!26 zTt4<(RP^&(wp@#PnDHn9;9H0id~b>V#(Ahu2HMz38|I~IT2`Ou{C2nH%EH{xGJ+Rd zJ@BBG(ofq>v+|zvcbx|(6y6NR?}(U|-LLwb2a(ItD|PKls!7zyfvnntMpR>dw|16* z2mr$8SByO?Kyftwo9+y?(!^Bn{k7KVyJ~PXzuv~S@u+u(1HnJ1Bmn%P33^#&n3w{4 zSF;*+Et7MB zVO1*YHG9v+d53#luCcKx&9Gcr?OR-!yMBrA;6g9!iJ3r60DO~a$*wi_{Z#W5kTJmL zA(rZGrwn0gHY&zDr@F)=aNU{+oWL-hNNx_l{~GAu^Y0gH%4IB(^}XGXrYfiJUEnF% zD~m2SiWY^Sr3rTn#hmv7Yr=|sHm^|^9}`&>Em{V3!(aIBj?`MytzKguh%%3YV3VeIo7giuG<8xwzf3K%JbC>u=OhX^* zX@Wh4yyucAf4Nqjrp!Ck*@@n(n=HUo^FI`)mR=zC?0hzQ$~MlDB^N*zpwv{;TFzv!BI^^*do9?fHm!8CX=|DM7L&1KY?_dB}?wgR~fVwp+C4&xgNGrqd9J zijIYQU0$aT7YhSexo$Gd|Ko+dkyLLtL=DIznO{EogKkDBA))5 zE=$X1ji$0y=`;K^L?5m`xojBZ-n*>W@m*4s%M7^FBh^k7=&cs4GH5*7g`mXpgEdK&yhyW(YFu2kf$+u!e=`dFAw&wu$URM~L<-96*%x-afj z2Y`{@eiOB%NcOXsYwmk~#?Lu9}M@h*=oU#)q(#w4} zo43tXV>8=MgLe9}h9q)#v14Bc(W9@0%QtQ~U(YdZYxImEHoCSd{e#UI zPY>_UL8cMo4C>MAY3clGU}xWGHI;j|?YATyuc=0hz;K@CZK&o)$*qT0aex*g39Ki=E3 zKFXB!K@`&3QA@XM&rUs({P)b0b^J?JL&K*}RetLyBap{gjgw+0Hk&~<)b5T-&#o^e z;aIstsV51x=P?1uJQwjWY+CC{pGt#0dw1FUzvVpb7YB=_@OehX*Y7d2R<|{@x_|}n z-b8IFzKVpb04PAyUWXGqntHq}S|p0H5z6i4c~P17gVpmw1z;bApLj*!T)L0C_mB(M zuTLq=uLi#8WY6D9-0K4^Y>z(`Uuf*~&_6k?C&>g;=BS}a^E z8=PV1P92>ke%*rD>?Z2fAbWt5_QG8GjT8nY3}U0r(Hk^8dn1ac7701jRkw*W#Cq}_ zC{fy-Liu$3Y(q+u^4P5_(%%t{#U!qK6q+40!D*@c?xe8{X%_!zfSDsmzj_BJ#E;SA zHU|0tD$^J;AWkh3j?_7vZ41Ll9f}`^%QP!r4Nj{ZOVtB0>>xJMyy-MAho}B9RV((F z!cqgn=j(^G8h-3A#-Bc5Y{9oY&dxT31%s}prkZNdKD4OIq0f(+FpEZysJ=gCbQT^U zkkjm7i2Ma(PGD|%8vn)UhLMSv33Pg0g)k>L@7PMQ4B231v!QkNT`Dab4!y_}85bQ< zcCgu5YNfoSEi>nMI!U=;{>(Jb+0hkN>M2DMhW6f_i!C2f?F(&ZzgeNdghQ=r)w`_1 z;>hE~6NN#^+;U2qn9?-8{~aYAp1TJSV?Zj%dwJl`o)E)lrw7-&TzM&%`THJv4Hdn3 ztJI@Regq~F4ebHv1RRzM&3+t2twpA8=5QjxeG?rE$?ld(QChCPiCz7f!Itqviv9`qhEwz2NyWw1}owZ+V4GBxaX}%`{Dr#S)0oKP(j+(mFfQg3_K2 z!3vdtzF6x;`^%2;ymv)6>Y-+cD=iXYs zwC{OPaT&{8xn4UZzR{krKz*;K^W+q_Ndw1Md!`ADzGd6o6SDjFt#6zyYK`#Eb$rpk z9E-biwl{>||Ah0_*c4AgIVPk{hyL3C#t`jshqadEewxz-#3=ilUETgkpmKg18Np($ z&JX;Xzi@{CXWDL#L~m`oNe$@tL+5{!<<8&qI`9mO-bDY(SLU$Z$9fFyFYvUWi1sl< zl1GpNAf0t!NSF)pWB*E>`}%;*B%jY&JTPYXcSX((jn2mOaqA`$V07-k^)B8hh=d}r z*A5ctLY40#rCs*;%{pG*N|2#o@Q!m)lOJ z#NFsqd{LtBe|8H{;x!9!Aa@}B>w^Bx1H~E_Cl!h)`|CpKVIR+;3yFfogyYMqK+J1i z=*_>=CjP&jw7k!`P;d^Zqm{KaXmZ@kbJR&`EM@grC>ZHWq7F;iaQUOgj12ImSA5W=_b$ zyI+LdY>$lMe+CY4YN-q{poMYn!0z5M0-DObrGG(Y|8$3x9qrs5Undz5SA;f&QAFGQ z_J8u)M-(o*fwAJX z9y}gxk~S3gwTAy_YPL%b3L`<6XC_Z<2QPwwG+40kRT?dPQ5Ho~M-Ua)4*yTBmv63| zvw#%Ky)UsN3#1_w&HU2tvY_s!{rUNw-oT}=9@i(7lA}0}C4nVpVCyv1o@u3&zn?Z* zCO>_w|1E+mTrVY&ENu(i+!!9`fe&azyv!JzNKqHby_uvg@=Bg4zhP39jovOQ2$*b_ zQ^YB}rsb&ZH9F>{En{geTr-S;8hFWKf?x{hrgZkmufbzdldqe@S7U#s10s6L*F~s{ zZ%z73Gfc^xP$_si_IWqwTH6=y>811Mj~w!K5p@Ku@i_LT`CA?>RBB&VrUSvypMO9k zDF(>selUJCQfAcuZFmelT8Z?d@9G=m^%;yD$$8O9_l$(Oc@N89m(1qTBJS<+R^P49 zXZLONyEZwPQ;f`DT*XBsR=($8!khhMpZlp%l zao{|cE+QLD<5vP1w}|$M_tmkBAxjLtOqd_bm?n?|x<-xTWpZ98D;<)Dcp>5%7x^q! zX|DCyW9BZh`|zqL^oktR?5TG@xQheNX4MAA*3ACV@K+N#it;cb7|!-Gi=%5abOYa( zKxMxdH_xTo{jL9ie4iDYvOo745lXuZBvi3MOHFaWP~2p7N>SJFrWVJ}*C;SPv>%>; zYNLLcnRoC3S^rAl*q&|hW1r>ara_yh#X|Iwtv`$^L#(u@>j2F<0uxi^peMqYrwmRc zkW#Z+TIT5aawjMxW%>h9zJFuIGNnwQIG6*w)G!r49Zl|juWO9APNwlUJ?L~nRA5dY zZ~pGWy<3;6Poe{{{E^=PueU@EJ+vjUjt{KI{TxEeEzvgRv&=Qp`0oZY#j)R$JG$&e z`Y$37{6$dsZ0|#Ax;YiQ0Nk`n5SrX6)+id^4N_s zPw}@0T!^QysN)ca;W$#xJg|nH)HP5d1>!h*hGuFzNWKJ#OjSD`Mc6MX`di&rz zW?gn@`^JK6Q}91IwT%rND$w|DAgM*P$-nC{+ol>2jT|azggiMxGNy8aD2!`a~;cp69lnB*6gpK0i0HJHBZK@ z!W8Rbk2$)T5L~G0eDtAO2RdvD^l-{t z!8Z1cG{Y!f^=M*qc>E6f_#=4M;FqKxA@s+p*CVir!8l|Djs>}BOB<=iec6G4;ylA` zZ*K&p1iKSRXmrw~fVx;R!cXR2Wn8CMr;!YKU=mWLuFjA}IPTV%YoQkIqhCheXw;{o z(3CB;Fd_ceSj)90BIMx_3pnf}$3h$en?U=G2NV;3r<*4Yl#qqk!o8qDmnG7RGh6Q~ zhr8U#r?|XmziYblqUFrh_UTECd7xhp`_o@cPI@I zn>kaSNLJd+G@NBmm&vcuxR$CG%^|4#Sy6pwqB;m7k%ibJbtS{^L#?wfz zN1C@u1t)!oR{VPQPBbpUp01n(b+5;{Yyafdp1NK&rE^sG{EpKrp)gSfWm5b9yrT`t z9gicXL4L=B`c8nBdyECtd=oc$BX|J{Q_-7B6Ui&x<6g|hgwYFlD$v`MDUEyT@Qvn} zD=sjHBmE(NZ&XX%bGYzZA)|v_q<=nWc-d&<7Y{Tb%&LCBFBO7oLHx!N9$jFnRn7}J zxr=u_9gpYcpaB~!Lz|=XFY%AtN)x?{2!fxF*rjO%89tG`8$>FcRhlwnWC-_Ug)ENXkPd81dT4~m!SVM8;docr z+|&}8cw@43=1>H8pQvpQr@*n`XoCv5`G%c4CrE|B^$Dd&k2wl}CNd?+ zIs1BxIy_S%lJ3-$|FmLA*X6{Y;$vroS zggtaRIdnju)E|TQ9ycAt^5b?TK_c>W>&!##9MY!-Q13%^5W$s$^0AT^9=*r|qX2&0 zx{6n?QMq>xRgqoxI&?aFkd%<}P$Ys)iz~2S8k|)JA0+E@knT-Cb~88Xl16=EBsnw{ z2>}u#AsUM-LEQNV%jG6^3GTWPN6HWy6OYt?`1;dB=OzE?e#R*1DuZvEE6yvWn)oC= z;`9&w?wchWS2`nK=>e&gS8IhBzkLiv=BD$%xc*i1@t(%=oLuI(C8vbye*HHP8r@ZO zs0`(+jNmHmnRi($L;`QWYZCp|g9d7e5Gdct5m4-Xa~hUts|g}A6qN6@j;w!lZOArj ztS$dzr4#>?@zJxmpr3^dapbLRx|kp`xB@t10ZFAZ#~PH8I#(*q{CoDTB)x^qo)xWlTio%;in5_}1_6P!KXu&=zp9DKMS zdo9;(l$sgagzv(yo&E+Ef1B^GlOO<+XgnWvD68eVH-ArX62H^2fnW;#ew-)L zrKlj50yJ4;P!hh27wz0_7eU%Z_+z(>R9UI^|8s3r#agGNaYqj0Sb6Xezl11hX~zsl zD(4AF$;U@u`kHj6PA&m29?-h&siv`reqo%WMM;;XH4f(0C>n5YQ$BiA=!#T_KG>)? z;d~7xQVX&1=e7U!15NUh*_-+ctW{kM#G8EQt>j}!-GsCRl#=8}k?Q;D3nti%hTIAh z#sz5=NM~}PHV-aN`Ga8LUW2=pb2RdOlKfG4B+0v2n8Pssh<9<%BpSP~o@i^%d%1Zs zcXgmsWCZF&KnvQLj69o?`w|Kiy#g!+>D5}e_uCrQ5V zsxqcVrLXS@Ce+!pU2YCz?i@0OfQxGbFw1EYA@^oJ8j9WG}+r(?u zxbTJIN*yNPATG4=gM?M`njOLjLA(hq6m$m+b0HVJwhPe+mR)V6m7j2W0=0>6HS;I@ zmv@d|wpZt1E=gbFgB(ac?L)aAdD6ujG(gI?P5Zm!-s5zb zuvsf+grDG3?o%ipSK^!$wHgweLRYgSly-9Qyo5fGgznr^n`l&GP5;_OfKx#YM6O1Z zspzRKw79c*4bI8+cjWmAiS(V`N>FVr6!HfZwLesEt8)I==eez9y$D)NVpN`@6A^^& zctEUIzFuVIX0PG5va9N)>3~>0Bz@qSqfk~~_Q(R=OO@~j=8>!Ymf)2@QYz|=dUN{mq#04u$=P=ri%VdBS|_O^rGEOXU8P?(?vez)2Sn?iX!^Y_uE>~s;leB8z=SmS=x z3&Rzj_uEMKf9X|q6{+o~mQXt|eN%>&)|7@RL+aryVJc6Nc^c`ip+Ja`C?!hfh{ct_ zi}m5rm7X-|b1>_e+>~GY?D>7@R#$u=FF*hHyDQ93ex^yfdl%$uCK9b8lu?qPMYgF@wNP`= z7Hj%e^@66Jk{lB@&AWTD@JEuok|*DzD5G9(%u;p~G`U|xcT|6k7&F6VedCXPcTnhL zyWn|2V%9zJ)>J|PqKrOtlooXV=1anNN$a6}hNno**K5S&f!lB5hPjN%XX*W|eYKLi z%FGq;`?YMj5lzqUUER}i<(^0m%fOe86wl2G@f^R`dhNz+EW&rg)>IbmUv7J98VEgc zJ^M$&UfEE5^}0nUQJTqjuU^Iy#kO+&1v&BuPamOKfzx;hQD%#Wj6sP zwo|pU1k#wW3~G*%ctANFbNIMksF~;oG&|?N9PfA* z(8Gx<|JIlYb3PHz9Nv*)g{Gw4IMZ`#EzZZh@2iLXcTed0riAE@x_)u#_i_cCwqH3n z@%#|D!0f`J#1N~8oC5QQA>chf*ux+8`_{xTx_wE8^6B|#NQ%x(HB;P9+nZ|bH(%!! za+4rUaPk%vIfUarg-54efQN*^yF8)!7Lh;8!YlqrsZ*B~#1=Yr^K#4jzEHL1sh2?f zp&?QMO*_`Is}40awU4Nk~p~Os z#KT@}WpRD9{6G7@srw=%%I-a5aw7`5pB!OhCJsvRMg5W8K>#ZrKW5~u7CQSyiCdGh z{Ykz-buxp!A|1b1_?)Imis~Uct3T5AG3J7v&x@~aTJk1jW)t_&90Swb-oMMl`~2g9 z*NK}Zr#~sbR&F03T>&phcE>tHXJ?Hwip-c+8vHj&sOw_1{w>mFv_7T9Ji&MT@~%m^ zzx*-Ul(3yg1jSLhiNOQS3Iw35E*4X}rr%%4W&Na((+s(YilQr1pu91p#L z5vzOQP<$x&@m;SzY1*_dip%$$2~f$oDC^=N*puqdaY@3P{G;FXw{2Xue4!sAOE?#! z-{q~t?jGyRKZtjRMX7N)^ec=Rc&Pvv<)@pLSwtC&tZFAq7%tL0s=p zfP>^o@-x7+>t^%WKjwWTeM80lWnrBAy?Aw3^9^~au-^0Z2p<*@J%7*KLE3@4kO>TJ zhcs2D+2&+A;$OL&&Dp{7Z9k!lkFJCY@p^=pu6R_jiSJWVT7Ys3&rR@y@EcF_-LzS$ zJu-kfb(bhlZ+bt27G;h=6Uhx=0>?avBo30JK--8wT!QI0YBeZ4^B64yT2d#+UsN+M zesMglnmDl)u`ptQR83t(i7quDa#YnQ`OWz@{}F*bjp+VhmU&>Ogs{wSUdXAy37|

    SmTWMTxDl;akbs=1_)}lM95r_2iJZm_H*1 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/topics/indexes.rst b/docs/topics/indexes.rst index 8807b594ae..426ddc0a9c 100644 --- a/docs/topics/indexes.rst +++ b/docs/topics/indexes.rst @@ -2,23 +2,48 @@ Indexes ======= -Administrators first define the template of the index and 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 againts the metadata -of the documents. Indexes can be mirrored to the operating system filesystem -using the configuration option -:setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`. 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. This -filesystem mirror of the index can them be served with Samba_ across the -network. This access would be read-only, and new versions of the files -would have to be uploaded from the web GUI using the new document -versioning support. +Indexes are an automatic method to hierarchically organize documents in relation to their metadata and to each other. +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. -The index cannot be edited manually, only changing + .. image:: index_template.png + :alt: index template + +This 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 + +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. +curated. .. _Samba: http://www.samba.org/ From d457c752fad2e8d7f858c57fe3dae9e576bb0f59 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 7 Feb 2012 01:48:25 -0400 Subject: [PATCH 399/484] Ilustrations markup update --- docs/topics/indexes.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/topics/indexes.rst b/docs/topics/indexes.rst index 426ddc0a9c..093ddb1a5c 100644 --- a/docs/topics/indexes.rst +++ b/docs/topics/indexes.rst @@ -9,15 +9,15 @@ 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 +.. image:: index_template.png + :alt: index template This 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 +.. image:: index_instance.png + :alt: index instance Indexes can be mirrored to the operating system filesystem using the configuration option From fe6e3475924e0cad69d2fd29503bab7c02d9831e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 7 Feb 2012 10:42:07 -0400 Subject: [PATCH 400/484] Remove delete mode in the permission grant and remove views (Sergei Glita) --- apps/permissions/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/permissions/views.py b/apps/permissions/views.py index 33d94ccdb2..6e8673de12 100644 --- a/apps/permissions/views.py +++ b/apps/permissions/views.py @@ -165,7 +165,6 @@ def permission_grant(request): return HttpResponseRedirect(next) context = { - 'delete_view': True, 'previous': previous, 'next': next, 'form_icon': u'key_add.png', @@ -229,7 +228,6 @@ def permission_revoke(request): return HttpResponseRedirect(next) context = { - 'delete_view': True, 'previous': previous, 'next': next, 'form_icon': u'key_delete.png', From f026ef8bd41018943fc3e0b7ad6a16fe169d20e5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 7 Feb 2012 14:40:56 -0400 Subject: [PATCH 401/484] Handle unicode filenames in staging folder preview and upload (Sergei Glita) --- apps/converter/api.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/converter/api.py b/apps/converter/api.py index 3c0b2ea08d..fb6bfaa8ec 100644 --- a/apps/converter/api.py +++ b/apps/converter/api.py @@ -4,11 +4,12 @@ import os import subprocess import hashlib +from django.utils.encoding import smart_str + from common.conf.settings import TEMPORARY_DIRECTORY -from converter.literals import DEFAULT_PAGE_NUMBER, \ - DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_FILE_FORMAT - +from .literals import (DEFAULT_PAGE_NUMBER, + DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, DEFAULT_FILE_FORMAT) from . import backend from .literals import (TRANSFORMATION_CHOICES, TRANSFORMATION_RESIZE, TRANSFORMATION_ROTATE, TRANSFORMATION_ZOOM, DIMENSION_SEPARATOR, @@ -29,7 +30,7 @@ def cache_cleanup(input_filepath, *args, **kwargs): def create_image_cache_filename(input_filepath, *args, **kwargs): if input_filepath: - hash_value = HASH_FUNCTION(u''.join([input_filepath, unicode(args), unicode(kwargs)])) + hash_value = HASH_FUNCTION(u''.join([HASH_FUNCTION(smart_str(input_filepath)), unicode(args), unicode(kwargs)])) return os.path.join(TEMPORARY_DIRECTORY, hash_value) else: return None From e2ca6654f461aaf28f93f3667d13812f3bbe857d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 7 Feb 2012 15:07:17 -0400 Subject: [PATCH 402/484] Improve tag appeareance and elimate obsolete tag block color widget --- apps/tags/__init__.py | 11 +++-------- apps/tags/views.py | 1 + apps/tags/widgets.py | 18 +++++++++++++----- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index a00f69bf45..ea2a2444b9 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -12,8 +12,7 @@ from acls.permissions import ACLS_VIEW_ACL from taggit.models import Tag from taggit.managers import TaggableManager -from .widgets import get_tags_inline_widget_simple -from .widgets import tag_color_block +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) @@ -32,12 +31,8 @@ tag_acl_list = {'text': _(u'ACLs'), 'view': 'tag_acl_list', 'args': 'object.pk', register_model_list_columns(Tag, [ { - 'name': _(u'color'), - 'attribute': encapsulate(lambda x: tag_color_block(x)) - }, - { - 'name': _(u'color name'), - 'attribute': encapsulate(lambda x: x.tagproperties_set.get().get_color_display()), + 'name': _(u'preview'), + 'attribute': encapsulate(lambda x: single_tag_widget(x)) }, { 'name': _(u'tagged items'), diff --git a/apps/tags/views.py b/apps/tags/views.py index aa6799343b..4076571167 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -98,6 +98,7 @@ def tag_list(request, queryset=None, extra_context=None): 'title': _(u'tags'), 'hide_link': True, 'multi_select_as_buttons': True, + 'hide_object': True, } if extra_context: context.update(extra_context) diff --git a/apps/tags/widgets.py b/apps/tags/widgets.py index 521ad6a1b2..056d667498 100644 --- a/apps/tags/widgets.py +++ b/apps/tags/widgets.py @@ -6,6 +6,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: @@ -21,8 +22,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 +30,20 @@ def get_tags_inline_widget_simple(document): if tag_count: tags_template.append('

    ') return mark_safe(u''.join(tags_template)) -def tag_color_block(tag): - return mark_safe(u'
    ' % tag.tagproperties_set.get().get_color_code()) +def single_tag_widget(tag): + tags_template = [] + tags_template.append('
      ') + tags_template.append(get_single_tag_template(tag)) + tags_template.append('
    ') + return mark_safe(u''.join(tags_template)) + + +def get_single_tag_template(tag): + return '
  • %s
  • ' % (tag.tagproperties_set.get().get_color_code(), tag.name.replace(u' ', u' ')) From 7adb3a9ccd7bb610f6928aa73c136cbe759be44f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 8 Feb 2012 11:23:24 -0400 Subject: [PATCH 403/484] Remove debug logging command causing unicode error (Sergei Glita) --- apps/acls/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/acls/views.py b/apps/acls/views.py index 728cc16b65..2325a31114 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -382,7 +382,6 @@ def acl_holder_new(request, access_object_gid): # Setup views def acl_setup_valid_classes(request): Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL]) - logger.debug('DefaultAccessEntry.get_classes(): %s' % DefaultAccessEntry.get_classes()) context = { 'object_list': DefaultAccessEntry.get_classes(), From 2334a63fe4c27f6a3e2962448873efb27397ac86 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 11 Feb 2012 18:08:20 -0400 Subject: [PATCH 404/484] Ensure default document_storage directory is really relative to the installation directory (SaintGermain) --- apps/storage/conf/settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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}, ] ) From afb64f7472bc835d078bf18c0cef07ada3ee0982 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 11 Feb 2012 18:08:54 -0400 Subject: [PATCH 405/484] Also ensure that the default gpg_home directory is really relative to the installation directory (SaintGermain) --- apps/django_gpg/conf/settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/django_gpg/conf/settings.py b/apps/django_gpg/conf/settings.py index 03e5a8d622..e1eed62938 100644 --- a/apps/django_gpg/conf/settings.py +++ b/apps/django_gpg/conf/settings.py @@ -1,8 +1,10 @@ """ Configuration options for the django_gpg app """ +import os from django.utils.translation import ugettext_lazy as _ +from django.conf import settings from smart_settings.api import register_settings @@ -11,6 +13,6 @@ register_settings( module=u'django_gpg.conf.settings', settings=[ {'name': u'KEYSERVERS', 'global_name': u'SIGNATURES_KEYSERVERS', 'default': ['pool.sks-keyservers.net'], 'description': _(u'List of keyservers to be queried for unknown keys.')}, - {'name': u'GPG_HOME', 'global_name': u'SIGNATURES_GPG_HOME', 'default': 'gpg_home', 'description': _(u'Home directory used to store keys as well as configuration files.')}, + {'name': u'GPG_HOME', 'global_name': u'SIGNATURES_GPG_HOME', 'default': os.path.join(settings.PROJECT_ROOT, u'gpg_home'), 'description': _(u'Home directory used to store keys as well as configuration files.')}, ] ) From 028c134bfd10e80b2119d18777a0b679850adf32 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 11 Feb 2012 20:05:02 -0400 Subject: [PATCH 406/484] The OSError doesn't like unicode text, change it to plain Exception class (Sergei Glita) --- apps/sources/staging.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sources/staging.py b/apps/sources/staging.py index ca8c92be9e..8f6608ed3e 100644 --- a/apps/sources/staging.py +++ b/apps/sources/staging.py @@ -41,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(): @@ -136,7 +136,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) From f19d34cd8c8be68d2797f095aed11fe062b24cac Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 11 Feb 2012 20:30:37 -0400 Subject: [PATCH 407/484] Spanish and Russian language translation updates --- apps/acls/locale/es/LC_MESSAGES/django.mo | Bin 2658 -> 4107 bytes apps/acls/locale/es/LC_MESSAGES/django.po | 30 +++--- .../locale/es/LC_MESSAGES/django.mo | Bin 6325 -> 7289 bytes .../locale/es/LC_MESSAGES/django.po | 18 ++-- .../documents/locale/es/LC_MESSAGES/django.mo | Bin 19709 -> 22857 bytes .../documents/locale/es/LC_MESSAGES/django.po | 62 ++++++----- .../documents/locale/it/LC_MESSAGES/django.mo | Bin 18034 -> 18034 bytes .../documents/locale/it/LC_MESSAGES/django.po | 2 +- .../documents/locale/pt/LC_MESSAGES/django.mo | Bin 17598 -> 17598 bytes .../documents/locale/pt/LC_MESSAGES/django.po | 2 +- .../documents/locale/ru/LC_MESSAGES/django.mo | Bin 22801 -> 27359 bytes .../documents/locale/ru/LC_MESSAGES/django.po | 99 +++++++++--------- .../locale/es/LC_MESSAGES/django.mo | Bin 3304 -> 3398 bytes .../locale/es/LC_MESSAGES/django.po | 10 +- apps/sources/locale/es/LC_MESSAGES/django.mo | Bin 8518 -> 9982 bytes apps/sources/locale/es/LC_MESSAGES/django.po | 27 +++-- 16 files changed, 136 insertions(+), 114 deletions(-) diff --git a/apps/acls/locale/es/LC_MESSAGES/django.mo b/apps/acls/locale/es/LC_MESSAGES/django.mo index c53034197c9f4f7dfa2b5441b3b2af41ff0c9c59..c49ee5e0ec78b46713395bc7fb6b6c04f1664ea2 100644 GIT binary patch literal 4107 zcmbuBO>7)B6vqus3oKuy6bj|b{Ybk@Gy4&$QnsW`NRtvsN|mI!P(GX)XLrc#cx%rz z+1@IUkPsXSEhmKN0SOKWaX<)B38{q(*Y*Gsst`xS0SO5tgb@GdncZx<*^&xty+7M) zKfm|J7=!q*x9~;s&VYA< zAA=e2OK=eUCgoZPgJ?DiVu+1{B!4O$e;y?H0wnqKAld&aNP2$&k{+L?4%13rrWIyi~ul|a(-X^`f<0Ma@MlKgp)^g5Z2p8`pr*Fm!9GJvH^BnN&w}KyZ$Xl?W<6s# z9(E7vW>hNoq0*jIC`RZ!sN9{v`h#@YmGI&bLT$DUm3&3^mQbnC8PI-kzl}eN zWhxZQbgm96-NzzoFDe!CBNd8+EvOuoZ0<)TpXN{>LnXVYz$9Df9H{gqU@*}Zit}c< zKW&h&$j=lTbPjpcW})+8d`@ZJYe21Pwh<{pZ&tXG(mB(|MWChd8oVkz9#ti;OI`Dg z@m0vT_GXuQIkS~lvk)|SrxA~q&FM+Q6OJ3@!Xuhm@@~iZ@uBy zAwbI$YF_>i4OSGek_y8(I2ipJF<$npx|moR!5LrOF&|?M_YFnFsTBlG$jK>9h<64 z*B1dhYNR%7#)qQTe%o5X>cqn3QA8@1={lr8!V}uZ7H!=I6Q0MzmK&DhGFjO1qa98H zx9LPTJ*Va=bWz*~n*AVcM=ROAjv)voc_zs7X^7u4GHs zx~*y2+gzN0R52SMlofR9Jl5Rm=O^dUo3+Hc^`D#yn>Rr-&z~%qK)cgnZ=S z#8hTd)|HN&2~+Vs=c%}2oM~uMjiP$FP^kD(HJ;78s#eg-2<g-*bNBhl5?Tm!3^8Bz;=6h%T zsHJw9lWT)mi@+IGx@O8etlO>`=-9!tzK5=&L+N<5hD_H?F?|6U%b=0!$>oY#@Vy2_yI<%;Xm z06V}24ZWMImnqP>JKZf0*~hvK|1$74;Vvsi2?%?WN0*u$H@P{3jA^;}kdEsr&GCx+ zl#_g$l4O#M1kI*r1JCl|7}l$?>Wt0(AxO_yM^VQKRMB?93k)6zgphsaOq zh`9Kf@O;g~c7H7oZ7Zz%Jo~ftI!k>|IgC#Gnp(Dp3 aIm25Em(3?TJC-!GD7{~F)Kl{&J)71W`{TVe4yl6sH9@H@p&wrujZ=qhGj+_0MM&;|q1o`b0 z9e$SOqJ=J?-tbEFd}1+QVd(gz4!(@ z$#0+OoWQHlRV_y3~*w@?Y<>|W#AQS-V`73+_l zPc~40DrU_z4bWzkkRuC2o6#9-_X^exOW1`vOTE1|rX&hgMMu*~)0?)_6g@O@hTn~Y z)i|j0*N3k1>g*N!X!?*8eY9R$t8NHYWq0T;Re@@BR69<=D?7ava|&heM%cOOiILH< zol7_%UkuK~o(9wLLTth-x|Luu;b-#2T%}^+)eQ!cuY%^(a&mCUIdOV;XmIU)YP=?R oo_-zt$lOU?yj9B2c_k)pHoiz}iW^RJgW9H#$+A1|<#T1*1`i8opa1{> diff --git a/apps/acls/locale/es/LC_MESSAGES/django.po b/apps/acls/locale/es/LC_MESSAGES/django.po index 724cbd44ca..0955203ed3 100644 --- a/apps/acls/locale/es/LC_MESSAGES/django.po +++ b/apps/acls/locale/es/LC_MESSAGES/django.po @@ -3,12 +3,13 @@ # 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: http://github.com/rosarior/mayan/issues\n" "POT-Creation-Date: 2012-02-02 14:18-0400\n" -"PO-Revision-Date: 2012-02-02 18:20+0000\n" +"PO-Revision-Date: 2012-02-12 00:16+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" @@ -63,7 +64,7 @@ msgstr "Funciones" #: forms.py:47 msgid "Special" -msgstr "" +msgstr "Especial" #: managers.py:116 managers.py:128 msgid "Insufficient access." @@ -91,11 +92,11 @@ msgstr "entradas de acceso por defecto" #: models.py:109 msgid "Creator" -msgstr "" +msgstr "Creador" #: models.py:112 models.py:113 msgid "creator" -msgstr "" +msgstr "creador" #: permissions.py:7 permissions.py:8 msgid "Access control lists" @@ -149,7 +150,7 @@ msgstr "tiene permiso" #: views.py:185 views.py:279 views.py:529 views.py:609 msgid ", " -msgstr "" +msgstr ", " #: views.py:186 views.py:280 views.py:530 views.py:610 #, python-format @@ -174,7 +175,7 @@ msgstr "¿Está seguro que desea conceder los permisos de %(title_suffix)s?" #: views.py:199 views.py:543 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." -msgstr "" +msgstr "Permiso \"%(permission)s\" otorgado a %(actor)s para %(object)s." #: views.py:205 views.py:549 #, python-format @@ -182,6 +183,7 @@ msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" +"%(actor)s, ya tenía el permiso \"%(permission)s\", otorgado para %(object)s." #: views.py:281 views.py:611 #, python-format @@ -191,31 +193,31 @@ msgstr " de %s" #: views.py:284 views.py:614 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" -msgstr "" +msgstr "¿Está seguro que desea revocar el permiso %(title_suffix)s?" #: views.py:286 views.py:616 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" -msgstr "" +msgstr "¿Está seguro de querer revocar los permisos %(title_suffix)s?" #: views.py:293 views.py:623 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." -msgstr "" +msgstr "Permiso \"%(permission)s\" revocado del %(actor)s para %(object)s." #: views.py:299 views.py:629 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." -msgstr "" +msgstr "%(actor)s, no tenía el permiso \"%(permission)s\" para %(object)s." #: views.py:355 #, python-format msgid "add new holder for: %s" -msgstr "" +msgstr "añadir nuevo titular para: %s" #: views.py:356 views.py:489 msgid "Select" -msgstr "" +msgstr "Seleccionar" #: views.py:389 msgid "classes" @@ -228,12 +230,12 @@ msgstr "clase" #: views.py:410 #, python-format msgid "default access control lists for class: %s" -msgstr "" +msgstr "listas de control de acceso por defecto para la clase: %s" #: views.py:438 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" -msgstr "" +msgstr "permisos disponibles para: %(actor)s para la clase %(class)s " #: views.py:487 #, python-format diff --git a/apps/document_indexing/locale/es/LC_MESSAGES/django.mo b/apps/document_indexing/locale/es/LC_MESSAGES/django.mo index d364289b69a33d4b32d4cbfcd0db05f1d3013fb4..8b6871508c1c320ac2672c1901bfd3f9766c9631 100644 GIT binary patch delta 2313 zcmZ|Pe`r-@9LMqJZcev3U2XG6E%Wimbep=i)pSlvXZa%?LWC%qtK+@T+_8JlUH9C% zt$*%6Du(n&T!N4wgd)O>;1Xd4Nvnh~un_8xkSOUNB}Ahi6x923&YiHRhx^>ubIv`_ zukZ6c_r0z^dJ9(@X1r`DyQue3^A*N8yflL^$}=;K8AK1);04@>KVt{3nq|xa+>hHa zhuiQ2d=?Yc#@ve;Y{rwQ=U>M@V+!UY8uPgE8+PHGns_mra0l0?P#v$}J$Msau(mcH zs1w_`-hnGIhpl)T7vm(d7V{%+#_PybX7y|q&-|u`#!_y0xB`#i{dg8P;}^IPXV=9O zEH68N2e_Zd9=wdJaORxYZq$MXQ5!sgcjK!#AK%e6^PA6T(ARu}MAckFt?)YDg}Wp<0a{R}v=Mc5{m91*@}(VTupURT3XdZnbBZs5U`}H}557S|1D?Z1{1nyU z+p<@YkGaN|CcIs~{=IxXi&^x19csdc^7T?=?WPr%;M(&2efUFyh1L`QF@ESLF1>gj zH{mT*D7zctGatmgT#w_^cp0C^PF8F2EH1-KWpCnouA7?TiFe~#u18Sgyor18?g%;Th}zj{)PPq|{cCy07|OIET}(d`WwRf3 z1V>Q0HIB-m0bC|v zaSQ6X5EHsj-A;X+s_~|Z7Ndx%wCMfk56>*8>fE$L6@^fxGR7=I?M7#==&YbB{0gOZ zqlvXB747l?>NZ`Ji*iWOd4&2fbu*Q9njOp^{V71S8>5hPgP=Shk7Ga*2YBV zx}Nq%s*Xs}>!qr!j)~qTH8)TfQQbumP4h43qTh!6v&_&qySi;>XJ7Za((O4L5`{g1 z!jX)^;b-l0qwGBN4+oxgX~xPNA^<6xljj1Sb9TbIfTt$kvLjxO{pq*RS5!RO*2}Sq zquEe{4rlN53Y|UbST$uq^C`X`Dv=2g!pT0x#zMxzi~=3>dE zRQ<)uA-0*-;M1O&T2M0QJbrfLem)y=a6#U6n5iBN_n(~<;eYokwKujW*6S2CmrMH@ zKk$AJq0$)lA`Fhg{x^fJ=_-BXu9HX?T`}PQ MEG0S@f5AZFAJt%PE&u=k delta 1541 zcmYk+OGs2v9LMqhj5V6(V>Gq0hmR&rOC2>EAC*0{$5a#*SrK6oT2V-=2x^FkqJ>05 z8EuNlm4wMfuuT!w#xM|CMP)@vi-@3F2)(|)J2&VsXFli7z32J=&z+16g=25Br(8A4 z8tNQso!@LXZkoau<=#}YB{+zcIF9+45inba3$YE4<53*K*;tfpR)Ec@=i9LnyD=C0 zF>DsIM>L}R@D11F%9KRMi#UtxI~c+TsDVCU8UDoi7@B5AS8K%<+>G3^9<0D#EXK#) z{Ry1Ob!jS<`K`rmn04V^Zd}Ht_!%`oaazJHSjzP&)DCWA5Qi}jM{qj6Lk_{dpce82 zv+y^nUnUQ+1`A;x^IH`Sopu{$U=+2ZJ(!6HkW;r4-u;uv+Ux@Axhtpz+`t?hL_Po1 z^BHQ~G1NS7z3Yz{(+}TisKX>`!av@1X1W<4%jK&GOHj|X;(H$p#R%7xbgIBkRLJ7E z3-987oXYl3;UO%k;AevRBnu;a$q7xgE8zYD!BsmQfw=65jLPY97Hy0N4)!| zQ8B%U%7I>FQ+5-TYz}JYPf&lyQB-I?p~m;KDuptZPJ_)^4r-z@)Pkx|xzUPxa3gBq zt*8k*Q2h>LHJ(8|H-MyuI|;aBXkj{)<@$l5lhvsaLgl~N3aVD8BUI55>*b-MQ<>|w z5=Tx>xqmw)++y$d)t*9&ET<}LinWRssIro(Q>>*XQ3Kxm?u&$Lcjt\n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n" "MIME-Version: 1.0\n" @@ -292,20 +292,20 @@ msgstr "nivel" #: views.py:188 msgid "Index template node created successfully." -msgstr "" +msgstr "Nodo de plantilla de índice creado exitosamente." #: views.py:194 msgid "create child node" -msgstr "" +msgstr "crear nodo hijo" #: views.py:215 msgid "Index template node edited successfully" -msgstr "" +msgstr "Nodo de la plantilla de índice editado exitosamente" #: views.py:221 #, python-format msgid "edit index template node: %s" -msgstr "" +msgstr "editar nodo de la plantilla de índice: %s" #: views.py:228 views.py:268 views.py:336 msgid "node" @@ -314,17 +314,17 @@ msgstr "nodo" #: views.py:250 #, python-format msgid "Node: %s deleted successfully." -msgstr "" +msgstr "Nodo: %s eliminado exitosamente." #: views.py:252 #, python-format msgid "Node: %(node)s delete error: %(error)s" -msgstr "" +msgstr "Error de eliminación para nodo: %(node)s, %(error)s " #: views.py:261 #, python-format msgid "Are you sure you with to delete the index template node: %s?" -msgstr "" +msgstr "¿Seguro que desea eliminar el nodo de plantilla de indice: %s?" #: views.py:285 msgid "nodes" @@ -368,6 +368,8 @@ msgid "" "A dictionary that maps the index name and where on the filesystem that index" " will be mirrored." msgstr "" +"Un diccionario que asigna el nombre del índice y en qué parte del sistema de" +" archivos dicho índice se va a reflejar." #: templates/indexing_help.html:3 msgid "What are indexes?" diff --git a/apps/documents/locale/es/LC_MESSAGES/django.mo b/apps/documents/locale/es/LC_MESSAGES/django.mo index fd334df0ed97dfea8e7d15ff444359d080da6a8c..1b4bd1f00bc36a08eb6ff9f6545fe8f6c52ca7d0 100644 GIT binary patch delta 7809 zcma)=34B%6oySku0?LvQwg8gL5(ojpB4HI-3D-n&VjzPuOS0t8wg9jjDF zLA)xpc4QdE3e{ooS?bb`+BhIsWd@47)Tv@SwWV66{Ww(Z_jm7o5ay$w&zz6He9yV} zo^$@&IZyrK{=CCa`C-aS|&NF6S7dc_rdA#OE?Qo z>u$_^xCQF{2{-``>S4?{cpV%K?}20BK^TIc!`@>^!82k*DLyJjsVKvMs zpN0g@G()ms-i31HFHosy$L^Zn1-=0X zKz(->%7JbJh<|4~Wtck^j)&BhSr28%9Z&{78H`Us6J*GP7VUtO-6i3{_;u;S%^aI1w%?Meq(N2YwBQ z!_#mn>_fQpT>>hlk3noOuR#^z|3Vp1kipGqbb7-!a21>Y*T5U#{ZK{O1}nraur2Hj zwU7nn**GZAs$e^~0M>(prz4NfKzVXD7;#x>H%vz`--2oMu{qSP=6wKH8f02%=_Loo_ zyaQ#(seqqCd6qZAzahIrEH`7I3|I(NJJ&<*F0%=Cf-dBeGrORQ@F}Poco}NmpI|Bb zn=k3;LKsxxdt3=MacaP&P$6u9GW2^;hJGK)(_K*2egG;`FG0rCRc_0tYLK)JDL$3w8LcQ+`wb6ipBcO6P0qVOds7Ne;G9&~$!5g9G zH$i=;+fM7;2D`v}MiKu4IuG+e2K)qS;vuLHPe6I}9@K`vg&pCi!E@cmN=-ggqy|7P zQ8NQ-LmPUA1mh;CRNM?zD|ct;s3`VAdGIP!1m1`8M?weTyb1=f!D zFQ(&=y-Y`LDQz?r^2qFfI+jNvC)k{V_rOA~K^gW4R75|7isUDd2xZI{e#hib@n^B}w#z5&PT z{9k*SABycz8@&d#!C9zCNLqeEaJ<2g_fS_Kt}?Qj}=5z5oHm;3*QG!yn=yajRs z%|pTX7}Pqa;b8XnX6ddT!fcE(3!oOdoj*6gBT%`joaW!<8zEPQIS5na{xc|pBQyNx z-+=_f?1KvV@8JM=23oKemqK4S5oT1SOX+ljYv3PY8d@;KuD#)Rp)B4B`N!<%j~4g~ z91n|TQt_}FDl%K)b?`+v9S)e~*F+d{!p&V!wf6ih;;#^W#)E#a;7Y%UM#56YGocK- z5q5=};b7>(TKEi<1N~?F3lD=)#;c$r_!3+V+fx9VUk7EtM%V!N&dK;6_L}Sesx5~D zd2uJ~1@}Xp*CTKhd=uuw%4)y3rog)yuY)qQ!#qDy{a|~>qoCHA2=#sul%sX99lSL| zr;N^>FbWUA5F9w)_iPJX!+1NC=YNJaEMDMyvAyWv5&7b+!dukvf=NvLAh z5mLmv!Ok!ZLlxyT zSOAwpeHVdBS;~K(F*niCF}e@RvcpgtpMo9X>0o>o7BX(L$X}oblt&hnL1UppI|mMd z^{^b?1r?!Z;U(}GRPlZc3w8cGUE`;q1j>Nfa25>1BKTuSy_n~qJnOL7_oM{M!}5SL zUjHeh=kHhh@ZH#ZkD--)I0-&WAz$NKAlQpbBc? zWl+Z{3cJHwpbU5b%FxH5zB>Rl?`0^*PC{+`0UQKdFZYYRY&r2)DCY4%8!rtQf{IKd z)Q{0-cscw5>X>Nu~GeHU%mIA@nPxXq6zfZ~O56HU<6neP+C0IQ5lp9lPP^TS)m* z)2;R?qKMBmo$Il|NQJ1jAI(Ht(DUe8bSwG~v>3HQH=;5$4^2ZqQ~Y0}GY(awKcE_P z9omhuXe(NYHX}9tqCJiFXh8cTQV~x@A0ic|+IVytozfs^cf*%Z52SkY@~=zhb@U?o z7_CKW&mrCQ|Ai{i@6ZfXi&UKdhH~vYbVi}8&@a&#^fLM}QhN*i8TCR5G#SlDng8a` zAf(^_p&{ru=!fY0NbOnlk=Ntg!#mLr(7XP# zjQ9U?)c-E(iylWK(Q&i^sojNi%-+_ZMZ1W;j^mHeNwf;74MhFDp8w}xz=LRS@T?gY zdVTUgo6c|1YVQI66$76{i-Pf+@IcTPcB1Vq#*Os9hps^pbQt{vU60fbqPFN5N}(fY z0=flx`4>B*qo@?sBNx4j9z_;X+k_^fIcP9?4CUGjbXo_4OW_0Pe}b{l4PAlm)qwU> z^q(m6j7GE_=zg!q|A-2h4){jEp>R^r&ml@@H0p|0pkE`kDs&tA6Iy_Z&@QBQlMns7 z$TIWK4DJaY2#=s)Xqg6T)1y%=ec(t#s0}$x1dlbkdC% zES4N%g(JzvsNH1Qv9J}1;h7yuMbsohi6_&NwOG~4Cw@6Tuq=Zs-P1GS* z(I#tsy%QrJ{$`O_otMFIe1)H&;o8A!z|BY_GjdKQhkIt!q+?;8dil1a>+Pnbm-b+> zq-FC@OPgvVQK!QFyzl)b3V}AuE!eUUCR?TMGne#p7xe4sW-mEXl1N~JUlSKh$pw0S zzkS& zu8nMPl0)5fmRqI;zwUdsNX8o+3MtH?NDj^B_g|Yg)!WaCQpr(5o`~2{v&c!M6EWab zch2*q>fE+S+qy_RoeZiWyJ^72R?C+psXEdx7XoiB#V}^GAHlt#G;%M@(%@A32AQQ1 zX6JUZQcaCcGTXZJM633>CEcS#s=CBmX3hz_`DHJ(cVeMh6vn_C)*9W2{l5 zCXE@J{b< z)0~aD5082@GeaAF!!k*&nG0?_X@YN~Bvn3ilIZ|E7y`)dg1{rpByv z%=X{-*9^{u?FwtAau{#)L&zCwOgjY9yZIC>0-bEmM&ni}O|iy#L3om(413$Gcz)~Q zetL4(A5qMOi3<>$8f}U#SCLjS;^_93C2?;-Z#_0JUSVb`(g{v} zyfNa0?XbIf(j%k2s+Lh-TebhE+_))|*^Mn=eZ{T1VD6 z(xFt^)-mwwcWCy9Q{T>8a1ED<(qYB;$)yUEyz?fRrST|kafjA%A_(63g!t}y2hG-x zb|lUh*>6w(s#Wz8eaT|6ctZ{OVa;4R=n^R3^>g9!^4Ie77RBgpsw&Qly8R~f$Zo58 zt9AEtlUV7TEpGkn%g&F2GtRAbt|&Oh#_d0$$o=W;cRJ~g)wSTo+`W6wd->d(x@)tI zbIbC&EVwWZ?)K`rZS{lVxNlV_d)7LkdfRHU>f;I9oFBMz=WQQO>b<+xyM500{F+v5 ObHzM~AKa7kO8yRWLC@d- delta 4953 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\n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\n" "MIME-Version: 1.0\n" @@ -106,13 +106,16 @@ msgstr "Buscar archivos de documentos perdidos" #: __init__.py:86 msgid "Clear the document image cache" -msgstr "" +msgstr "Borrar el caché de imágenes de documentos" #: __init__.py:86 msgid "" "Clear the graphics representations used to speed up the documents' display " "and interactive transformations results." msgstr "" +"Borrar las representaciones gráficas utilizadas para acelerar la " +"presentación de los documentos y resultados de las transformaciones " +"interactivas." #: __init__.py:89 msgid "page transformations" @@ -246,6 +249,7 @@ msgstr "Páginas del documento (%s)" #: forms.py:162 msgid "Use the new version filename as the document filename" msgstr "" +"Usar el nombre de archivo de la nueva versión como el nombre del documento" #: forms.py:178 msgid "Quick document rename" @@ -261,7 +265,7 @@ msgstr "Nivel de liberación" #: forms.py:196 msgid "Release level serial" -msgstr "" +msgstr "Serie de nivel de publicación" #: forms.py:204 msgid "Comment" @@ -285,6 +289,10 @@ msgid "" "This option is selectable only when downloading one document, for multiple " "documents, the bundle will always be downloads as a compressed file." msgstr "" +"Descargue el documento en el formato original o en una forma comprimida. " +"Esta opción se puede seleccionar sólo cuando se descarga un documento, para " +"multiples documentos, el paquete será siempre como descarga de un archivo " +"comprimido." #: literals.py:10 msgid "Document creation" @@ -382,17 +390,17 @@ msgstr "documento" #: models.py:287 #, python-format msgid "Major %(major)i.%(minor)i, (new release)" -msgstr "" +msgstr "Mayor %(major)i.%(minor)i, (nueva publicación)" #: models.py:288 #, python-format msgid "Minor %(major)i.%(minor)i, (some updates)" -msgstr "" +msgstr "Menor %(major)i.%(minor)i, (algunas actualizaciones)" #: models.py:289 #, python-format msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" -msgstr "" +msgstr "Micro %(major)i.%(minor)i.%(micro)i, (arreglos)" #: models.py:301 msgid "mayor" @@ -408,15 +416,15 @@ msgstr "micro" #: models.py:304 msgid "release level" -msgstr "" +msgstr "Nivel de publicación" #: models.py:305 msgid "serial" -msgstr "" +msgstr "serie" #: models.py:306 msgid "timestamp" -msgstr "" +msgstr "fecha y hora" #: models.py:307 views.py:1357 msgid "comment" @@ -432,7 +440,7 @@ msgstr "suma de comprobación" #: models.py:318 models.py:319 models.py:542 msgid "document version" -msgstr "" +msgstr "versión de documento" #: models.py:411 msgid "" @@ -591,11 +599,11 @@ msgstr "Ejecutar herramientas de modificación de documento" #: permissions.py:17 msgid "Revert documents to a previous version" -msgstr "" +msgstr "Regresar documentos versiones anteriores" #: permissions.py:18 msgid "Create new document versions" -msgstr "" +msgstr "Crear nuevas versiones de documentos" #: permissions.py:20 msgid "Documents setup" @@ -603,7 +611,7 @@ msgstr "Configuración de documentos" #: permissions.py:22 msgid "View document types" -msgstr "" +msgstr "Ver los tipos de documentos" #: permissions.py:23 msgid "Edit document types" @@ -720,7 +728,7 @@ msgstr "Debe proveer al menos un documento." #: views.py:218 msgid "Document deleted successfully." -msgstr "" +msgstr "Documento eliminado exitosamente." #: views.py:220 #, python-format @@ -744,11 +752,11 @@ msgstr "Documento \"%s\" editado exitosamente." #: views.py:342 msgid "documents to be downloaded" -msgstr "" +msgstr "documentos para ser descargados" #: views.py:352 views.py:1337 msgid "version" -msgstr "" +msgstr "versión" #: views.py:409 msgid "Download" @@ -1019,50 +1027,50 @@ msgstr "crear nombre de archivo para tipo de documento: %s" #: views.py:1306 msgid "Document image cache cleared successfully" -msgstr "" +msgstr "Caché de imagenes de documentos borrada exitosamente" #: views.py:1308 #, python-format msgid "Error clearing document image cache; %s" -msgstr "" +msgstr "Error borrando el caché de imágenes de documentos; %s" #: views.py:1314 msgid "Are you sure you wish to clear the document image cache?" -msgstr "" +msgstr "¿Esta seguro que desea borrar el caché de imágenes de documentos?" #: views.py:1331 #, python-format msgid "versions for document: %s" -msgstr "" +msgstr "versiones para el documento: %s" #: views.py:1341 msgid "time and date" -msgstr "" +msgstr "fecha y hora" #: views.py:1345 msgid "mimetype" -msgstr "" +msgstr "mimetype" #: views.py:1349 msgid "encoding" -msgstr "" +msgstr "codificación" #: views.py:1380 msgid "Document version reverted successfully" -msgstr "" +msgstr "Versión de documento revertida exitosamente." #: views.py:1382 #, python-format msgid "Error reverting document version; %s" -msgstr "" +msgstr "Error revirtiendo la versión del documento; %s" #: views.py:1389 msgid "Are you sure you wish to revert to this version?" -msgstr "" +msgstr "¿Está seguro que desea revertir a esta versión?" #: views.py:1390 msgid "All later version after this one will be deleted too." -msgstr "" +msgstr "Todas las versiones más recientes a que éste serán borradas." #: widgets.py:25 msgid "document page image" diff --git a/apps/documents/locale/it/LC_MESSAGES/django.mo b/apps/documents/locale/it/LC_MESSAGES/django.mo index 33d61db5c8d9a6b9661b27793b209810b67c2638..609e68a54c843ca90c7fdbaa3160f49c8a3b5cfa 100644 GIT binary patch delta 23 fcmey=!}zI(al;l(4nso)0}Cq?)6IJ{x5)qia0Cd8 delta 23 fcmey=!}zI(al;l(4g(_vLklZI%guW\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n" "MIME-Version: 1.0\n" diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.mo b/apps/documents/locale/pt/LC_MESSAGES/django.mo index 25d04b452092d5e45ff9b9def3f5271414b78284..1ba95a785b7826b7c51bb8455442ad7af50d508c 100644 GIT binary patch delta 23 ecmdnj$+)kRal=M+4nso)0}Cq?)6F~8S!Drb3\n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" "MIME-Version: 1.0\n" diff --git a/apps/documents/locale/ru/LC_MESSAGES/django.mo b/apps/documents/locale/ru/LC_MESSAGES/django.mo index 91ed59aa69fa1dc179d0519aca3fceabec98b6c9..19b6037a4f06d0cdbb80fb68ced3d15cfb225be6 100644 GIT binary patch delta 8698 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 delta 4802 zcmZYC32;>P0mt$Gl0YCFh7ceifek`9b8NT*1W8no5Uy}4axKXw#3n?OB^&}v11g6K z_yyX)X0_5$W0oWsGXa-kKAy$V7~j^I@mPd9zY_=JHyFU4 ziN<8(3@pa=I8)~_9Shn;?~j!`(iDQ#a*b1 zeT6xg(#e=!I9)PiE0NwcdpaAFfyb}~eu11aSCLyytDD`5_r!>97(_uQ#-M5%#5TAH zN8%c!w@d@70w17W9M6Q&*k_}L?3dULUqC%){-d9{jLd z#F%?2B>COR6Y*S+O*y_5^?;|b5D%eV{3FKVB*tqJPDAy;9#lpCh?w?p_O`>}lc%*JPs6=wd2^D!mhj`b>3MYnnGM=mj^km+Nt;!;dz zX=$=Po=yK#DRYnmy5J*Bz?cDUmnGqC?5E-aEWz>k4sODm2hyFmAIIQ7QP0U5|9%Qo*8CUyVrITuvze&% zy8<;tTd)0dIBB+@#^pMXWmw4K{|7p#$-JHZUxTk>NbCRhQSNv4 zK4hLnyF<$=Ycwy#;h2Yw_zJeY)BW{3huzr!4{FY|Wdf)n-SJVp2Q?&LqMmmv&8@`( z%)>Wu74J8`vF?NFkO^vbV=P|82K)ePa7Up#1c^+TEcSCyFDys?%x*r~;J=Z!m}{sZ zy<@yPcV?jW@5fYJgOPL!dnm9}%|%Q?&BWf&9yw%gMdqb>1l!=7s1{$qR`?lq#w*_O zmJ{6ubwPD`F80ECn1^eT(J|*H(*L@k6;n6^voI6qqGtO>9Ekg{KYolWv1O6Ftk&ad z_V=P%)_*c90Y{=AOECo>#y0posv`B6jDML-|EuQTaX?*}Fvb1%Kmn@7_1G0JVVitt4VzIl zeirp}de-xEPyK5{J=X=*bA_m7`T%NZc3}d(`R{&VZ1RqrMBS+I z*7hKwvE~u-FexQl$m?V_X-#s-9I}^a(-5qSmfXf=Q-0CgKaTUs`shCIf1HB4PBT*5 zqb_C}szpc1v*Z8?kPbv$uI(YBUSfJgyBSOqGFOEgHVx(7L_Iv%JFb-#{r%rhVS;yX zB0f#jWtD{9j&7qp@AVvl`e&EsjFxI0`7Ievv>hTH$xWo1l#tD2H@R_h`=2An$Qtj= z2^>a(q#Myh@sr6!%knw0lU(2CQOGB6lKaUBqU{J7Lw=(jwpoM)5dCt?!;Sj>*H%ST z+NB+~WiHXr7JTyC^t0_AjtnJQEx)+o>~_kBNjcFH(-&JAX-oEzT5^iqN1|^X2;+#B zm$rJcN(HuGkzbPEP6jkF`hd6 zN~fSL%O(0*$fxsC(ng>Cq(eJrU58qq%}QQoM|8@t%R7y7KJIjXlV+ik@^Glc+0o^l z82h+?dAz@*s(4XlXkoa<{*d~VeYN{#=dD}fefC<9tGQ{0KW(io>2<+* zxc8DK_O5=1n^%{4H>LCsIMe&T=d&X+hFhC)#1>@^w--Am*xi{u5-Wl=VgG%>vXH3^ zg@Yx*aM1pcc_OtY6!zDahZdXas&FtI@>hgP!`I8zW)Q>%juYbt`_s_J3>$yM`1)!{0v309X^`E#q?0~yusfsC@Mh0B5! zp=EhxmBI3gjN+$JjuASLf0E*f=|*;3oUwm=Elm1!;CmVS77oLaZ~Ou)ohaH12($ z^VWnv`<%Z{y22Z#Tz1A!9qenM|M;cF@uRFiN z?wY;A88jz7*4E9RX-@{bIz5Y*`0T-w8oO)gEjAb`vgblQlDPhSUE{&VdUAq0H#8nG y_TY5xZzxSI?B diff --git a/apps/documents/locale/ru/LC_MESSAGES/django.po b/apps/documents/locale/ru/LC_MESSAGES/django.po index 1d01185b53..85a5b50c3e 100644 --- a/apps/documents/locale/ru/LC_MESSAGES/django.po +++ b/apps/documents/locale/ru/LC_MESSAGES/django.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:19+0000\n" -"Last-Translator: Roberto Rosario \n" +"PO-Revision-Date: 2012-02-11 08:45+0000\n" +"Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -105,13 +105,15 @@ msgstr "Найти недостающие файлы документов" #: __init__.py:86 msgid "Clear the document image cache" -msgstr "" +msgstr "Очистить кэш изображения документа" #: __init__.py:86 msgid "" "Clear the graphics representations used to speed up the documents' display " "and interactive transformations results." msgstr "" +"Очистить графику для ускорения отображения документов и интерактивных " +"преобразований." #: __init__.py:89 msgid "page transformations" @@ -171,11 +173,11 @@ msgstr "вернуть вид" #: __init__.py:108 msgid "versions" -msgstr "" +msgstr "версии" #: __init__.py:109 msgid "revert" -msgstr "" +msgstr "возвращаться" #: __init__.py:112 msgid "document type list" @@ -227,7 +229,7 @@ msgstr "Содержание" #: forms.py:109 msgid "Page" -msgstr "" +msgstr "Страница" #: forms.py:121 msgid "Details" @@ -244,7 +246,7 @@ msgstr "Страницы документа (%s)" #: forms.py:162 msgid "Use the new version filename as the document filename" -msgstr "" +msgstr "Использовать имя новой версии файла как имя документа" #: forms.py:178 msgid "Quick document rename" @@ -252,19 +254,19 @@ msgstr "Быстро переименовать документ" #: forms.py:185 msgid "Version update" -msgstr "" +msgstr "Обновление версии" #: forms.py:190 msgid "Release level" -msgstr "" +msgstr "Уровень релиза" #: forms.py:196 msgid "Release level serial" -msgstr "" +msgstr "Номер уровня релиза" #: forms.py:204 msgid "Comment" -msgstr "" +msgstr "Комментарий" #: forms.py:210 msgid "New document filename" @@ -276,7 +278,7 @@ msgstr "Диапазон страниц" #: forms.py:318 msgid "Compress" -msgstr "" +msgstr "Сжать" #: forms.py:318 msgid "" @@ -284,6 +286,9 @@ msgid "" "This option is selectable only when downloading one document, for multiple " "documents, the bundle will always be downloads as a compressed file." msgstr "" +"Скачать документ в исходном формате или сжатым. Этот вариант доступен только" +" при загрузке одного документа, для нескольких документов будет использован " +"сжатый файл." #: literals.py:10 msgid "Document creation" @@ -335,23 +340,23 @@ msgstr "Документ\"%(document)s\" удалил %(datetime)s %(fullname) #: literals.py:42 msgid "final" -msgstr "" +msgstr "окончательный" #: literals.py:43 msgid "alpha" -msgstr "" +msgstr "альфа" #: literals.py:44 msgid "beta" -msgstr "" +msgstr "бета" #: literals.py:45 msgid "release candidate" -msgstr "" +msgstr "релиз-кандидат" #: literals.py:46 msgid "hotfix" -msgstr "" +msgstr "исправление" #: models.py:61 msgid "name" @@ -382,45 +387,45 @@ msgstr "документ" #: models.py:287 #, python-format msgid "Major %(major)i.%(minor)i, (new release)" -msgstr "" +msgstr "Основной %(major)i.%(minor)i, (новый релиз)" #: models.py:288 #, python-format msgid "Minor %(major)i.%(minor)i, (some updates)" -msgstr "" +msgstr "Младший %(major)i.%(minor)i, (некоторые обновления)" #: models.py:289 #, python-format msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" -msgstr "" +msgstr "Микро %(major)i.%(minor)i.%(micro)i, (исправления)" #: models.py:301 msgid "mayor" -msgstr "" +msgstr "основной" #: models.py:302 msgid "minor" -msgstr "" +msgstr "младший" #: models.py:303 msgid "micro" -msgstr "" +msgstr "микро" #: models.py:304 msgid "release level" -msgstr "" +msgstr "уровень релиза" #: models.py:305 msgid "serial" -msgstr "" +msgstr "номер" #: models.py:306 msgid "timestamp" -msgstr "" +msgstr "отметка времени" #: models.py:307 views.py:1357 msgid "comment" -msgstr "" +msgstr "комментарий" #: models.py:310 msgid "file" @@ -432,7 +437,7 @@ msgstr "Контрольная сумма" #: models.py:318 models.py:319 models.py:542 msgid "document version" -msgstr "" +msgstr "версия документа" #: models.py:411 msgid "" @@ -589,11 +594,11 @@ msgstr "Выполнить изменения документа" #: permissions.py:17 msgid "Revert documents to a previous version" -msgstr "" +msgstr "Восстановить документы до предыдущей версии" #: permissions.py:18 msgid "Create new document versions" -msgstr "" +msgstr "Создать новые версии документа" #: permissions.py:20 msgid "Documents setup" @@ -601,7 +606,7 @@ msgstr "Настройки для документов" #: permissions.py:22 msgid "View document types" -msgstr "" +msgstr "Просмотр типов документов" #: permissions.py:23 msgid "Edit document types" @@ -717,7 +722,7 @@ msgstr "Необходимо предоставить хотя бы один д #: views.py:218 msgid "Document deleted successfully." -msgstr "" +msgstr "Документ успешно удален." #: views.py:220 #, python-format @@ -741,19 +746,19 @@ msgstr "Документ \"%s\" изменен." #: views.py:342 msgid "documents to be downloaded" -msgstr "" +msgstr "Документы для загрузки" #: views.py:352 views.py:1337 msgid "version" -msgstr "" +msgstr "версия" #: views.py:409 msgid "Download" -msgstr "" +msgstr "Скачать" #: views.py:411 msgid "Return" -msgstr "" +msgstr "Назад" #: views.py:445 #, python-format @@ -1007,50 +1012,50 @@ msgstr "создание имени файла для типа документ #: views.py:1306 msgid "Document image cache cleared successfully" -msgstr "" +msgstr "Кэш изображений документа очищен" #: views.py:1308 #, python-format msgid "Error clearing document image cache; %s" -msgstr "" +msgstr "Ошибка очистки кэш изображений документов %s" #: views.py:1314 msgid "Are you sure you wish to clear the document image cache?" -msgstr "" +msgstr "Вы уверены, что хотите очистить кэш изображений документа?" #: views.py:1331 #, python-format msgid "versions for document: %s" -msgstr "" +msgstr "версии для документа %s" #: views.py:1341 msgid "time and date" -msgstr "" +msgstr "время и дата" #: views.py:1345 msgid "mimetype" -msgstr "" +msgstr "MimeType" #: views.py:1349 msgid "encoding" -msgstr "" +msgstr "кодировка" #: views.py:1380 msgid "Document version reverted successfully" -msgstr "" +msgstr "Версия документа восстановлена" #: views.py:1382 #, python-format msgid "Error reverting document version; %s" -msgstr "" +msgstr "Ошибка получения версии документа %s" #: views.py:1389 msgid "Are you sure you wish to revert to this version?" -msgstr "" +msgstr "Вы уверены, что хотите вернуться к этой версии?" #: views.py:1390 msgid "All later version after this one will be deleted too." -msgstr "" +msgstr "Все более поздние версии после этого будут удалены" #: widgets.py:25 msgid "document page image" diff --git a/apps/permissions/locale/es/LC_MESSAGES/django.mo b/apps/permissions/locale/es/LC_MESSAGES/django.mo index bc2b168886f1309eb101f83a59977dc2b0f1b0c5..a8cf185da1ff49bcdd25deebeb0cf5dfef8d8b76 100644 GIT binary patch delta 1042 zcmX}rOGuPa7{>8;ni;imOf&PEHa1O{Ny=Lhj%1}`7SW<4f}kc7l9FV^MHl%tNl1$p z(I!wKhE}bdr68dcxpGqr!CFjLT16qa?Ej2sI?Vh1&N*`~?|0_R&zg6&-skebbE7m7 zyNHKAvjnbf;X!%tHw)r2MsNkY@i+Ehd%)}h-ovxFjOVa|NnyP19KjIn`^d*8d2BcH z>BSXtOTo&E{me($6fys)JY_;49}nv zxq?}b@>UW#vbg#n|K1#cp1N-jy6FS=kYP>O+TU%`G!h#16k6_$V!P;qY{gw zzHh-c>_@Mi$^?}noI_2VM`gO?`ad{7p%(m(6}aL0OL#qPP>Gsfk0lsGt=s18#5&r& zsPV}#zrQlSMMncZKrQgX4Sb2Uv=>kdt-9~CuKf!u>Hmuw7h+enW5{7yC+cMNvmPM! z6O9CSH#e?<{c{sFI7X=G;ww8PrlKQL*7?F-wwKUl%@>`9icT$G;#726`ib;XhX`Ff zy@<*|B6O0+K0+5FN^qi9Pece6{UvwiYMXbX$<=ki_7K&XDgRerurGCYeDvAv;9U6P z=+NMB@{SFR4W%-51+%`Qmexpfb4TmZ%wl2GALvUlFdKSR+B^1t^9!ODmL*ZwlRrCCd;cB$13W53slF<>UNKZ zG#!udGCs!=e#8X+#bNZQQW!_QD2qq1fPAb(MNTUtQ>=oAvFh4)afEgakK;p(lHZnj zI7r7+9LJZa1RKZ-?L8`S3$>uH$j3q|CG5EVKd7B{@hEy^(?Uk^2dA1ruwKk8hySol ze#?>l8rJX*uA+{xi?{GPtI4b6`r8oa09npdmlLr3sFa?B#N^XCE_mH8H$qVWHfdVy2o0aHmcA@PxhZw zasIs1CMilh2wf0`j(rdpc+j!wQfbiz$~lU5qBu|C#BGYA-#t&^VEQ}GqCyva5c;=G u>xBwkBwdQJ;DgtWtZWVK21~>5BC+DdykDC2OTkEN%3JXho59b-V&p$lpiII5 diff --git a/apps/permissions/locale/es/LC_MESSAGES/django.po b/apps/permissions/locale/es/LC_MESSAGES/django.po index 29f9e554c8..f37aab51e6 100644 --- a/apps/permissions/locale/es/LC_MESSAGES/django.po +++ b/apps/permissions/locale/es/LC_MESSAGES/django.po @@ -3,13 +3,13 @@ # 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: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:18+0000\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" "MIME-Version: 1.0\n" @@ -172,15 +172,15 @@ msgstr "" #: views.py:273 views.py:297 msgid "Users" -msgstr "" +msgstr "Usuarios" #: views.py:276 views.py:300 msgid "Groups" -msgstr "" +msgstr "Grupos" #: views.py:279 views.py:303 msgid "Special" -msgstr "" +msgstr "Especial" #: views.py:332 #, python-format diff --git a/apps/sources/locale/es/LC_MESSAGES/django.mo b/apps/sources/locale/es/LC_MESSAGES/django.mo index 7a4495f7d4963160d717ea9fd7bef90258726460..4873b27b15abd3a76591fabed0a59917b03defcd 100644 GIT binary patch delta 3540 zcmbW%Yitzd9>?*gg(^@fbz5pn3p^^7VoPlcBJ=>KQjv>X6cm)IW!RmT#qCbd&TcuJ z7}vuK174zLG-|vhMohfCP&Z1vB$BAS@oqGMMva#E;&@bIV$^tx-{0&MTJ)7q_P?Lm z*_r3^fBrLvSNy&{|5N|=Ybz7x+fCU3eqSj>qYoQU_JE_?u&<5O6M|HJ8c9J$ey zong#WoQc)gjOw@xHQ*Yo!wk;H+ffsK8Rz0xSj+e(Mlb5H88v}!?84QkmF&j_cmS1& zqtWlraXr7QD~c1@ftu(bHscVk!^cp`JdVonk9am#PosavH;Xu!ft&Dr96)t&KhDE9 zkg?3S$fV7$I149}CUw+=Ew~o7vfZeOJ&MZ2H`s+WXBsmHx1#R55%W5Dgac*Z5U#)@ z$RtgD%$S9EKC+Fb7d7xMoR9ml5f5Sqeu~OKWmWP18swB|M9Ri2j$DDt@D)@IypEKCIf}aO%gC=#HE7Er=v1D zr<(k$!wyc=;A-Sr(~EqJ&zEMp57oh)s1EK!P3#HO%3eebcqsb+aPD#E44WkA;7Woa1lu%Tt2@W$_JC5KMtgbbt z4R1ikHV@%ud=AgSd>PM(Qs0Ey!&RsW{0BAg9nt>};>G-a8MV@1kugmvmAeXSQ4`*d zs`3HkV{YY3nK}@ie*ty>hsbz&bA$sXW6F8fR8(_t32wp#csnwdIfQzl45L>16KY_M zrt_Mg&^*-Rw+!`I_hBdAjji}LUY+OQ7Y?-YE3Gk?;a=>*cTqJl zjajIJrKpMY<7(WCD#o`^kL@sOk7u&6=VAvg#4V@^--Z|AtEdcok9pnjGY6{DY22kM zor`+BI#AWW95wJt)C#wws(4@Y|MSQz!@Ptl(zj5V`3O}@r&Hk?a7Ls>W%|51>=Dt-!=<3ZF)e?V=8J+GMR^{C9xnA~HPymZ#OT7q;?f^$2(5xA07>@l;c))piiwgfe#>v5U}Kb!_X2 zeoVmadj8dx5PifyiM52PRIQoNqm&|4@oGM?F+4IRj{k^`S7Cy4ePXGQITu&3QzllHRKv15AF zl`Z4D$y%;#4UUyRTIKGxiBo2({tEv+qq20#-=0`-V?}dtQ$=k4=!{OzXZ%zg>nGFw zBtf$b4pgLK>7A@P#d_U;$KAm!nJbh}Yc8$ua#`#3*};sb{1h%cb3;kc6PsL_W(8wY z9BhnDUv%n8>t~&Q2C}}F%f#JI+vuBOV(pkqgT1k%liE9MTU%#GTOnSxXF}Z;ZQkpJ zv`x4t^5pR&6*M%|2G7=?RrsXl{*wH~nfT7+kY^&fzzbk}*Mvreq=FV`3BYp@eo zMlh?PMp+6TsIP0+T$w_#Hp9%cjLQXU@Vyk-jq1@0-mHJHW~Is?9_|69Vh5bGyUWQG zdKz9Tt?bLOcx_FwD!f9~?BSB@H2(}4acuh3W%^v3axC|;6=4;eyf`c(Wuti4*ef+e Rv{S*ewyt7)zrojb+aE6QLwo=L delta 2339 zcmYk+TWnNS6vpv2(-u0EmJaO{sjZ!%H;OIo)Pkjy0#yOAQ$=bKO6h#?L13K|7vlrtS%>#vxpeH?bD$0%mkAj?K6kAICu~ z#-DH|{*JjAnB?AHh||mxR!XOlf6T{p+=jZb4>NENhOi%bzy>iJPhma|qbBeNYM{F~ z9rLoxYOn@1(JrjSz4#b9IF0dbn2uI>1E0cs7{iju?m)e$iM)?(_z_OT5md&0!3aJ? ztvtl+3NebaunnKY?O26}kv}`n$7II0%XFT=+o%^!%yCm)g_?0EYGpgH43DDj8}|GY zTltbQz!E%#+QKWyyX`tEQx8#F_y|d^1%vK=#X<6~2WD_VdsvB@NFD0Ixu^-XAjz>9 z>P1~xfbXCtvI|uUUty|PQO^&dosZMIKP6Y57z{1EEJM?FvAHJ{n{sEHh6c2OL}P8`KLtWB^S%{-1P@m-vO=TND= zkM)?va(S1vpax!n`hO2D#vP~?okkw9GpLFFhAPrKsG^*}>XeBH>UttdM-R562I@c^ zk55s>@-@!G5!C6(mT@7Ds)b{y<1~cYnnzfQxh%H<8&DJ5j8EeM)Cw=6?jJ>xWn-us%3z;V^|`3x zEJEgLrC7=M)|U?-Y(Ndrj2fT~*){7%72kGj z!JViD{)}4K7%BsQhsnQEUdSkVQ5EXJdFVs!w|*buM2yhB`3e1;s+f1#)9FSUnc(4HY`hzjqYN)e~VJ@?)errW)?Zk2- zOsLXTBWgO1n^HY@akXAw3tzzaspGX6RW#bimx&%i8JSO%6DmA46_gr9Y%dVq`r@@U zo^Rlb#1cYv(?K*7jl{FWdLoT@o=E7ZY$Vi5iFJgEO#8KzP+LoIoKvlpPyG&TaKEO0 z&9ukb_Z7rUVl`1l{J-h9L3^$``L|KrO}2_}Dmpb4qgsS0A?6UT6FNQ_go^UN=9~*$ z^Er33*7%aYW*>A8=S=Z`9xO<%3T|;O1YBG$&s8 vr7!ty(aDUh;WyX!C435cvUGgQ5RIL67JU`VO diff --git a/apps/sources/locale/es/LC_MESSAGES/django.po b/apps/sources/locale/es/LC_MESSAGES/django.po index 45c0ca1900..276debfca4 100644 --- a/apps/sources/locale/es/LC_MESSAGES/django.po +++ b/apps/sources/locale/es/LC_MESSAGES/django.po @@ -3,13 +3,13 @@ # 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: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:18+0000\n" +"PO-Revision-Date: 2012-02-12 00:20+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" @@ -64,7 +64,7 @@ msgstr "Fuentes de documentos" #: __init__.py:38 msgid "upload new version" -msgstr "" +msgstr "subir nueva versión" #: __init__.py:68 widgets.py:39 msgid "thumbnail" @@ -85,7 +85,7 @@ msgstr "Archivo provisional" #: forms.py:50 msgid "File" -msgstr "" +msgstr "Archivo" #: literals.py:8 literals.py:13 msgid "Always" @@ -274,7 +274,7 @@ msgstr "transformaciones de fuentes de documentos" #: models.py:288 models.py:289 msgid "out of process" -msgstr "" +msgstr "fuera de proceso" #: permissions.py:7 msgid "Sources setup" @@ -339,29 +339,30 @@ msgstr "" #: views.py:163 msgid "New document version uploaded successfully." -msgstr "" +msgstr "Nueva versión del documento subida exitosamente." #: views.py:167 msgid "File uploaded successfully." -msgstr "" +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 "" +msgstr "El archivo no era un archivo comprimido, cargado como estaba." #: views.py:179 views.py:258 #, python-format msgid "Unhandled exception: %s" -msgstr "" +msgstr "Excepción sin manejar: %s" #: views.py:188 #, python-format msgid "upload a new version from source: %s" -msgstr "" +msgstr "subir una nueva versión desde la fuente: %s" #: views.py:190 #, python-format @@ -372,6 +373,7 @@ msgstr "subir un documento local de la fuente: %s" #, 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 @@ -384,11 +386,14 @@ 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 @@ -398,7 +403,7 @@ msgstr "Archivo provisional: %s, borrado exitosamente." #: views.py:273 #, python-format msgid "upload a new version from staging source: %s" -msgstr "" +msgstr "subir una versión nueva de la fuente de archivo provisionales: %s" #: views.py:275 #, python-format From f94f9978837fa0c0adb4ab300eb80ac7fa91dd77 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 11 Feb 2012 21:13:05 -0400 Subject: [PATCH 408/484] Documentation updates, indexed documentation --- apps/common/forms.py | 4 +-- docs/conf.py | 3 +- docs/contents.rst | 22 +++++++++++++++ docs/{ => credits}/LICENSE | 0 docs/{topics => credits}/contributors.rst | 0 docs/credits/index.rst | 11 ++++++++ docs/{ => credits}/license.rst | 0 docs/{topics => credits}/software_used.rst | 0 docs/faq/index.rst | 6 ++-- docs/index.rst | 7 +++-- docs/intro/index.rst | 33 ++++++++++++++++++++++ docs/releases/0.11.rst | 4 ++- docs/releases/index.rst | 2 +- docs/topics/index.rst | 15 ++++++++++ 14 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 docs/contents.rst rename docs/{ => credits}/LICENSE (100%) rename docs/{topics => credits}/contributors.rst (100%) create mode 100644 docs/credits/index.rst rename docs/{ => credits}/license.rst (100%) rename docs/{topics => credits}/software_used.rst (100%) create mode 100644 docs/intro/index.rst create mode 100644 docs/topics/index.rst diff --git a/apps/common/forms.py b/apps/common/forms.py index ac5527fc9f..95f8a572dd 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -161,7 +161,7 @@ class FileDisplayForm(forms.Form): def __init__(self, *args, **kwargs): super(FileDisplayForm, self).__init__(*args, **kwargs) - changelog_path = os.path.join(settings.PROJECT_ROOT, self.DIRECTORY, self.FILENAME) + changelog_path = os.path.join(settings.PROJECT_ROOT, os.sep.join(self.DIRECTORY), self.FILENAME) fd = open(changelog_path) self.fields['text'].initial = fd.read() fd.close() @@ -169,4 +169,4 @@ class FileDisplayForm(forms.Form): class LicenseForm(FileDisplayForm): FILENAME = u'LICENSE' - DIRECTORY = u'docs' + DIRECTORY = [u'docs', u'credits'] diff --git a/docs/conf.py b/docs/conf.py index d881a7cad6..2d7df78659 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -40,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' diff --git a/docs/contents.rst b/docs/contents.rst new file mode 100644 index 0000000000..a1d15892f2 --- /dev/null +++ b/docs/contents.rst @@ -0,0 +1,22 @@ +.. _contents: + +================================= +Mayan EDMS documentation contents +================================= + +.. toctree:: + :hidden: + + index + +.. toctree:: + :maxdepth: 3 + + intro/index + topics/index + releases/index + topics/settings + topics/development + credits/index + faq/index + 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/topics/contributors.rst b/docs/credits/contributors.rst similarity index 100% rename from docs/topics/contributors.rst rename to docs/credits/contributors.rst diff --git a/docs/credits/index.rst b/docs/credits/index.rst new file mode 100644 index 0000000000..2613360ea1 --- /dev/null +++ b/docs/credits/index.rst @@ -0,0 +1,11 @@ +Credits +======= + +Introductions to all the key parts of Mayan EDMS you'll need to know: + +.. 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/topics/software_used.rst b/docs/credits/software_used.rst similarity index 100% rename from docs/topics/software_used.rst rename to docs/credits/software_used.rst diff --git a/docs/faq/index.rst b/docs/faq/index.rst index c92c72cc02..b695062027 100644 --- a/docs/faq/index.rst +++ b/docs/faq/index.rst @@ -20,7 +20,7 @@ before trying again. Q: _mysql_exceptions. OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci, IMPLICIT) and (utf8_general_ci, COERCIBLE) for operation '='") -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Solution:: @@ -126,7 +126,7 @@ Q: How do you upload a new version of an existing file? version number and comments for the new version being uploaded. Q: Site search is slow -~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~ * Add indexes to the following fields: @@ -250,7 +250,7 @@ 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/index.rst b/docs/index.rst index 63e5f32cd8..aa13b55563 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -24,6 +24,7 @@ On the Web * 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 =========== @@ -69,9 +70,9 @@ For developers Credits ======= - :doc:`Contributors ` | - :doc:`Software used ` | - :doc:`Licensing ` + :doc:`Contributors ` | + :doc:`Software used ` | + :doc:`Licensing ` Getting help 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/releases/0.11.rst b/docs/releases/0.11.rst index fc6c4accb6..df691977e4 100644 --- a/docs/releases/0.11.rst +++ b/docs/releases/0.11.rst @@ -21,12 +21,14 @@ Version 0.11 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 + * 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/index.rst b/docs/releases/index.rst index 508bb73812..bd3fc2ddd6 100644 --- a/docs/releases/index.rst +++ b/docs/releases/index.rst @@ -15,7 +15,7 @@ Final releases ============== 0.12 release ------------ +------------ .. toctree:: :maxdepth: 1 diff --git a/docs/topics/index.rst b/docs/topics/index.rst new file mode 100644 index 0000000000..2d297d1745 --- /dev/null +++ b/docs/topics/index.rst @@ -0,0 +1,15 @@ +Using Mayan EDMS +================ + +Introductions to all the key parts of Mayan EDMS you'll need to know: + +.. toctree:: + :maxdepth: 1 + + indexes + smart_links + permissions + document_visualization + ocr + file_storage + transformations From d1621c6120d7adac2ddfdc2040568f9d8e754b9c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 11 Feb 2012 21:21:16 -0400 Subject: [PATCH 409/484] Documentation updates, split indexes and permissions into sections --- docs/topics/indexes.rst | 12 ++++++++++- docs/topics/permissions.rst | 41 ++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/docs/topics/indexes.rst b/docs/topics/indexes.rst index 093ddb1a5c..9f818e5876 100644 --- a/docs/topics/indexes.rst +++ b/docs/topics/indexes.rst @@ -3,6 +3,10 @@ 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 @@ -12,13 +16,19 @@ matched the path to reach the document container. .. image:: index_template.png :alt: index template -This template is the skeleton from which an instance of the index is then +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`. diff --git a/docs/topics/permissions.rst b/docs/topics/permissions.rst index 41980bb04c..4948654e85 100644 --- a/docs/topics/permissions.rst +++ b/docs/topics/permissions.rst @@ -5,26 +5,33 @@ Permissions **Mayan EDMS** provides very exact control over what activies users can perform. This control is divided into two levels of operation: -* 2-tier permission assignment - 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. +2 tier permissions assignement +============================== - .. image:: permissions.png - :alt: 2-tier permission diagram +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. + +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 +.. 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 From 31813f34128b86596b8dd647f034af9f9784c7ac Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 02:06:06 -0400 Subject: [PATCH 410/484] Add signaler app to intercept management commands and emit signals --- apps/signaler/__init__.py | 1 + apps/signaler/management/__init__.py | 0 apps/signaler/management/commands/__init__.py | 0 apps/signaler/management/commands/collectstatic.py | 13 +++++++++++++ apps/signaler/models.py | 3 +++ apps/signaler/signals.py | 3 +++ settings.py | 11 ++++++++--- 7 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 apps/signaler/__init__.py create mode 100644 apps/signaler/management/__init__.py create mode 100644 apps/signaler/management/commands/__init__.py create mode 100644 apps/signaler/management/commands/collectstatic.py create mode 100644 apps/signaler/models.py create mode 100644 apps/signaler/signals.py diff --git a/apps/signaler/__init__.py b/apps/signaler/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/apps/signaler/__init__.py @@ -0,0 +1 @@ + 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..e33b4d0ec1 --- /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/settings.py b/settings.py index ef68252deb..7fed78bde0 100644 --- a/settings.py +++ b/settings.py @@ -174,6 +174,8 @@ INSTALLED_APPS = ( 'rest_api', 'document_signatures', +# Has to be last so the other apps can register it's signals + 'signaler', ) TEMPLATE_CONTEXT_PROCESSORS = ( @@ -328,19 +330,22 @@ if DEVELOPMENT: import rosetta INSTALLED_APPS += ('rosetta',) except ImportError: - sys.stderr.write('DEBUG: rosetta is not installed\n') + pass + #sys.stderr.write('DEBUG: rosetta is not installed\n') try: import django_extensions INSTALLED_APPS += ('django_extensions',) except ImportError: - sys.stderr.write('DEBUG: django_extensions is not installed\n') + pass + #sys.stderr.write('DEBUG: django_extensions is not installed\n') try: import debug_toolbar #INSTALLED_APPS +=('debug_toolbar',) except ImportError: - sys.stderr.write('DEBUG: debug_toolbar is not installed\n') + pass + #sys.stderr.write('DEBUG: debug_toolbar is not installed\n') TEMPLATE_CONTEXT_PROCESSORS += ('django.core.context_processors.debug',) From f253ecf8c146e56a929e645958d180b93ceb7d77 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 02:06:45 -0400 Subject: [PATCH 411/484] Gracefully shutdown the scheduler on pre_collectstatic and post_syncdb --- apps/scheduler/__init__.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/scheduler/__init__.py b/apps/scheduler/__init__.py index 8b13789179..fd2f06bd8b 100644 --- a/apps/scheduler/__init__.py +++ b/apps/scheduler/__init__.py @@ -1 +1,24 @@ +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 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() From 234e5b8c5b04fa5d9ba3d32c1e80530ea202e6b8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 02:21:57 -0400 Subject: [PATCH 412/484] Add Latex configuration --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2d7df78659..06e2d962ad 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -183,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'), ] @@ -216,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) ] From 4d8a61b25bb7d93f15063885bffaf18251a9c37a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 15:01:07 -0400 Subject: [PATCH 413/484] Fix document container index nodes --- apps/document_indexing/api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 0e68bb623b..7112f1d3a2 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -86,8 +86,7 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) 'expression': template_node.expression, 'exception': exc}) else: if result: - index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node) - index_instance.value = result + index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node, value=result) index_instance.parent = parent_index_instance index_instance.save() #if created: From 1892225d6f41c514b690e6347118f7888a65c6d6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 15:18:21 -0400 Subject: [PATCH 414/484] Show currently selected document type in upload views --- apps/sources/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/sources/views.py b/apps/sources/views.py index 900c3aba50..0c107d7365 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -314,6 +314,14 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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': { From cc0040a88bf561b8825fea1254db98ac2452894f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 15:33:26 -0400 Subject: [PATCH 415/484] Language source files updates, Spanish translation updates --- apps/acls/locale/en/LC_MESSAGES/django.po | 48 +++--- apps/acls/locale/es/LC_MESSAGES/django.mo | Bin 4107 -> 4068 bytes apps/acls/locale/es/LC_MESSAGES/django.po | 59 ++++--- apps/acls/locale/it/LC_MESSAGES/django.mo | Bin 528 -> 489 bytes apps/acls/locale/it/LC_MESSAGES/django.po | 59 ++++--- apps/acls/locale/pt/LC_MESSAGES/django.mo | Bin 531 -> 492 bytes apps/acls/locale/pt/LC_MESSAGES/django.po | 59 ++++--- apps/acls/locale/ru/LC_MESSAGES/django.mo | Bin 4126 -> 4087 bytes apps/acls/locale/ru/LC_MESSAGES/django.po | 62 +++---- apps/common/locale/en/LC_MESSAGES/django.po | 30 ++-- apps/common/locale/es/LC_MESSAGES/django.mo | Bin 5935 -> 5896 bytes apps/common/locale/es/LC_MESSAGES/django.po | 45 +++--- apps/common/locale/it/LC_MESSAGES/django.mo | Bin 5136 -> 5097 bytes apps/common/locale/it/LC_MESSAGES/django.po | 52 +++--- apps/common/locale/pt/LC_MESSAGES/django.mo | Bin 5190 -> 5151 bytes apps/common/locale/pt/LC_MESSAGES/django.po | 52 +++--- apps/common/locale/ru/LC_MESSAGES/django.mo | Bin 6208 -> 6169 bytes apps/common/locale/ru/LC_MESSAGES/django.po | 52 +++--- .../converter/locale/en/LC_MESSAGES/django.po | 2 +- .../converter/locale/es/LC_MESSAGES/django.mo | Bin 19258 -> 19258 bytes .../converter/locale/es/LC_MESSAGES/django.po | 2 +- .../converter/locale/it/LC_MESSAGES/django.mo | Bin 18971 -> 18971 bytes .../converter/locale/it/LC_MESSAGES/django.po | 2 +- .../converter/locale/pt/LC_MESSAGES/django.mo | Bin 18843 -> 18843 bytes .../converter/locale/pt/LC_MESSAGES/django.po | 2 +- .../converter/locale/ru/LC_MESSAGES/django.mo | Bin 19627 -> 19627 bytes .../converter/locale/ru/LC_MESSAGES/django.po | 2 +- .../locale/en/LC_MESSAGES/django.po | 6 +- .../locale/es/LC_MESSAGES/django.mo | Bin 3954 -> 3915 bytes .../locale/es/LC_MESSAGES/django.po | 21 ++- .../locale/it/LC_MESSAGES/django.mo | Bin 3383 -> 3344 bytes .../locale/it/LC_MESSAGES/django.po | 21 ++- .../locale/pt/LC_MESSAGES/django.mo | Bin 2026 -> 1987 bytes .../locale/pt/LC_MESSAGES/django.po | 17 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 3930 -> 3891 bytes .../locale/ru/LC_MESSAGES/django.po | 20 +-- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 1792 -> 1753 bytes .../locale/es/LC_MESSAGES/django.po | 13 +- .../locale/it/LC_MESSAGES/django.mo | Bin 1750 -> 1711 bytes .../locale/it/LC_MESSAGES/django.po | 13 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 1792 -> 1753 bytes .../locale/pt/LC_MESSAGES/django.po | 13 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 2179 -> 2140 bytes .../locale/ru/LC_MESSAGES/django.po | 16 +- .../locale/en/LC_MESSAGES/django.po | 68 ++++---- .../locale/es/LC_MESSAGES/django.mo | Bin 7289 -> 7581 bytes .../locale/es/LC_MESSAGES/django.po | 78 ++++----- .../locale/it/LC_MESSAGES/django.mo | Bin 4094 -> 4055 bytes .../locale/it/LC_MESSAGES/django.po | 94 ++++++----- .../locale/pt/LC_MESSAGES/django.mo | Bin 4126 -> 4087 bytes .../locale/pt/LC_MESSAGES/django.po | 93 ++++++----- .../locale/ru/LC_MESSAGES/django.mo | Bin 5125 -> 5086 bytes .../locale/ru/LC_MESSAGES/django.po | 93 ++++++----- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 2092 -> 2053 bytes .../locale/es/LC_MESSAGES/django.po | 13 +- .../locale/it/LC_MESSAGES/django.mo | Bin 1718 -> 1679 bytes .../locale/it/LC_MESSAGES/django.po | 13 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 2102 -> 2063 bytes .../locale/pt/LC_MESSAGES/django.po | 13 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 2402 -> 2363 bytes .../locale/ru/LC_MESSAGES/django.po | 16 +- .../documents/locale/en/LC_MESSAGES/django.po | 28 ++-- .../documents/locale/es/LC_MESSAGES/django.mo | Bin 22857 -> 22818 bytes .../documents/locale/es/LC_MESSAGES/django.po | 74 +++++---- .../documents/locale/it/LC_MESSAGES/django.mo | Bin 18034 -> 17995 bytes .../documents/locale/it/LC_MESSAGES/django.po | 82 +++++----- .../documents/locale/pt/LC_MESSAGES/django.mo | Bin 17598 -> 17559 bytes .../documents/locale/pt/LC_MESSAGES/django.po | 78 +++++---- .../documents/locale/ru/LC_MESSAGES/django.mo | Bin 27359 -> 27320 bytes .../documents/locale/ru/LC_MESSAGES/django.po | 86 +++++----- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 2189 -> 2189 bytes .../locale/es/LC_MESSAGES/django.po | 2 +- .../locale/it/LC_MESSAGES/django.mo | Bin 2079 -> 2079 bytes .../locale/it/LC_MESSAGES/django.po | 2 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 2134 -> 2134 bytes .../locale/pt/LC_MESSAGES/django.po | 2 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 2605 -> 2605 bytes .../locale/ru/LC_MESSAGES/django.po | 2 +- apps/feedback/locale/en/LC_MESSAGES/django.po | 2 +- apps/feedback/locale/es/LC_MESSAGES/django.mo | Bin 3198 -> 3159 bytes apps/feedback/locale/es/LC_MESSAGES/django.po | 21 ++- apps/feedback/locale/it/LC_MESSAGES/django.mo | Bin 528 -> 489 bytes apps/feedback/locale/it/LC_MESSAGES/django.po | 13 +- apps/feedback/locale/pt/LC_MESSAGES/django.mo | Bin 531 -> 492 bytes apps/feedback/locale/pt/LC_MESSAGES/django.po | 13 +- apps/feedback/locale/ru/LC_MESSAGES/django.mo | Bin 602 -> 563 bytes apps/feedback/locale/ru/LC_MESSAGES/django.po | 16 +- apps/folders/locale/en/LC_MESSAGES/django.po | 2 +- apps/folders/locale/es/LC_MESSAGES/django.mo | Bin 4046 -> 4007 bytes apps/folders/locale/es/LC_MESSAGES/django.po | 17 +- apps/folders/locale/it/LC_MESSAGES/django.mo | Bin 4023 -> 3984 bytes apps/folders/locale/it/LC_MESSAGES/django.po | 17 +- apps/folders/locale/pt/LC_MESSAGES/django.mo | Bin 3962 -> 3923 bytes apps/folders/locale/pt/LC_MESSAGES/django.po | 21 ++- apps/folders/locale/ru/LC_MESSAGES/django.mo | Bin 4693 -> 4654 bytes apps/folders/locale/ru/LC_MESSAGES/django.po | 24 +-- apps/history/locale/en/LC_MESSAGES/django.po | 2 +- apps/history/locale/es/LC_MESSAGES/django.mo | Bin 1455 -> 1416 bytes apps/history/locale/es/LC_MESSAGES/django.po | 13 +- apps/history/locale/it/LC_MESSAGES/django.mo | Bin 1406 -> 1367 bytes apps/history/locale/it/LC_MESSAGES/django.po | 13 +- apps/history/locale/pt/LC_MESSAGES/django.mo | Bin 1424 -> 1385 bytes apps/history/locale/pt/LC_MESSAGES/django.po | 13 +- apps/history/locale/ru/LC_MESSAGES/django.mo | Bin 1618 -> 1579 bytes apps/history/locale/ru/LC_MESSAGES/django.po | 16 +- apps/linking/locale/en/LC_MESSAGES/django.po | 2 +- apps/linking/locale/es/LC_MESSAGES/django.mo | Bin 7337 -> 7298 bytes apps/linking/locale/es/LC_MESSAGES/django.po | 22 ++- apps/linking/locale/it/LC_MESSAGES/django.mo | Bin 7147 -> 7108 bytes apps/linking/locale/it/LC_MESSAGES/django.po | 17 +- apps/linking/locale/pt/LC_MESSAGES/django.mo | Bin 4333 -> 4294 bytes apps/linking/locale/pt/LC_MESSAGES/django.po | 13 +- apps/linking/locale/ru/LC_MESSAGES/django.mo | Bin 8286 -> 8247 bytes apps/linking/locale/ru/LC_MESSAGES/django.po | 20 +-- apps/main/locale/en/LC_MESSAGES/django.po | 2 +- apps/main/locale/es/LC_MESSAGES/django.mo | Bin 2720 -> 2720 bytes apps/main/locale/es/LC_MESSAGES/django.po | 2 +- apps/main/locale/it/LC_MESSAGES/django.mo | Bin 2499 -> 2499 bytes apps/main/locale/it/LC_MESSAGES/django.po | 2 +- apps/main/locale/pt/LC_MESSAGES/django.mo | Bin 2540 -> 2540 bytes apps/main/locale/pt/LC_MESSAGES/django.po | 2 +- apps/main/locale/ru/LC_MESSAGES/django.mo | Bin 3341 -> 3341 bytes apps/main/locale/ru/LC_MESSAGES/django.po | 2 +- apps/metadata/locale/en/LC_MESSAGES/django.po | 102 ++++++------ apps/metadata/locale/es/LC_MESSAGES/django.mo | Bin 9974 -> 10063 bytes apps/metadata/locale/es/LC_MESSAGES/django.po | 137 ++++++++-------- apps/metadata/locale/it/LC_MESSAGES/django.mo | Bin 9743 -> 9789 bytes apps/metadata/locale/it/LC_MESSAGES/django.po | 140 ++++++++-------- apps/metadata/locale/pt/LC_MESSAGES/django.mo | Bin 9803 -> 9857 bytes apps/metadata/locale/pt/LC_MESSAGES/django.po | 151 ++++++++--------- apps/metadata/locale/ru/LC_MESSAGES/django.mo | Bin 12186 -> 12249 bytes apps/metadata/locale/ru/LC_MESSAGES/django.po | 149 ++++++++--------- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 685 -> 685 bytes .../locale/es/LC_MESSAGES/django.po | 2 +- .../locale/it/LC_MESSAGES/django.mo | Bin 643 -> 643 bytes .../locale/it/LC_MESSAGES/django.po | 2 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 640 -> 640 bytes .../locale/pt/LC_MESSAGES/django.po | 2 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 748 -> 748 bytes .../locale/ru/LC_MESSAGES/django.po | 2 +- apps/ocr/locale/en/LC_MESSAGES/django.po | 30 ++-- apps/ocr/locale/es/LC_MESSAGES/django.mo | Bin 8290 -> 8670 bytes apps/ocr/locale/es/LC_MESSAGES/django.po | 42 ++--- apps/ocr/locale/it/LC_MESSAGES/django.mo | Bin 8068 -> 8029 bytes apps/ocr/locale/it/LC_MESSAGES/django.po | 52 +++--- apps/ocr/locale/pt/LC_MESSAGES/django.mo | Bin 8119 -> 8080 bytes apps/ocr/locale/pt/LC_MESSAGES/django.po | 48 +++--- apps/ocr/locale/ru/LC_MESSAGES/django.mo | Bin 10558 -> 10519 bytes apps/ocr/locale/ru/LC_MESSAGES/django.po | 47 +++--- .../locale/en/LC_MESSAGES/django.po | 30 ++-- .../locale/es/LC_MESSAGES/django.mo | Bin 3398 -> 3359 bytes .../locale/es/LC_MESSAGES/django.po | 41 +++-- .../locale/it/LC_MESSAGES/django.mo | Bin 3271 -> 3232 bytes .../locale/it/LC_MESSAGES/django.po | 41 +++-- .../locale/pt/LC_MESSAGES/django.mo | Bin 2111 -> 2072 bytes .../locale/pt/LC_MESSAGES/django.po | 41 +++-- .../locale/ru/LC_MESSAGES/django.mo | Bin 3752 -> 3713 bytes .../locale/ru/LC_MESSAGES/django.po | 44 ++--- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 602 -> 602 bytes .../locale/es/LC_MESSAGES/django.po | 2 +- .../locale/it/LC_MESSAGES/django.mo | Bin 578 -> 578 bytes .../locale/it/LC_MESSAGES/django.po | 2 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 572 -> 572 bytes .../locale/pt/LC_MESSAGES/django.po | 2 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 633 -> 633 bytes .../locale/ru/LC_MESSAGES/django.po | 2 +- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 544 -> 544 bytes .../locale/es/LC_MESSAGES/django.po | 2 +- .../locale/it/LC_MESSAGES/django.mo | Bin 522 -> 522 bytes .../locale/it/LC_MESSAGES/django.po | 2 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 519 -> 519 bytes .../locale/pt/LC_MESSAGES/django.po | 2 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 592 -> 592 bytes .../locale/ru/LC_MESSAGES/django.po | 2 +- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 649 -> 649 bytes .../locale/es/LC_MESSAGES/django.po | 2 +- .../locale/it/LC_MESSAGES/django.mo | Bin 625 -> 625 bytes .../locale/it/LC_MESSAGES/django.po | 2 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 620 -> 620 bytes .../locale/pt/LC_MESSAGES/django.po | 2 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 714 -> 714 bytes .../locale/ru/LC_MESSAGES/django.po | 2 +- apps/sources/locale/en/LC_MESSAGES/django.po | 122 +++++++------- apps/sources/locale/es/LC_MESSAGES/django.mo | Bin 9982 -> 10074 bytes apps/sources/locale/es/LC_MESSAGES/django.po | 124 +++++++------- apps/sources/locale/it/LC_MESSAGES/django.mo | Bin 8517 -> 8517 bytes apps/sources/locale/it/LC_MESSAGES/django.po | 124 +++++++------- apps/sources/locale/pt/LC_MESSAGES/django.mo | Bin 8193 -> 8193 bytes apps/sources/locale/pt/LC_MESSAGES/django.po | 124 +++++++------- apps/sources/locale/ru/LC_MESSAGES/django.mo | Bin 10429 -> 12097 bytes apps/sources/locale/ru/LC_MESSAGES/django.po | 152 +++++++++--------- apps/tags/locale/en/LC_MESSAGES/django.po | 62 +++---- apps/tags/locale/es/LC_MESSAGES/django.mo | Bin 3540 -> 3777 bytes apps/tags/locale/es/LC_MESSAGES/django.po | 78 ++++----- apps/tags/locale/it/LC_MESSAGES/django.mo | Bin 3549 -> 3510 bytes apps/tags/locale/it/LC_MESSAGES/django.po | 66 ++++---- apps/tags/locale/pt/LC_MESSAGES/django.mo | Bin 3496 -> 3457 bytes apps/tags/locale/pt/LC_MESSAGES/django.po | 66 ++++---- apps/tags/locale/ru/LC_MESSAGES/django.mo | Bin 4046 -> 4314 bytes apps/tags/locale/ru/LC_MESSAGES/django.po | 77 ++++----- .../locale/en/LC_MESSAGES/django.po | 2 +- .../locale/es/LC_MESSAGES/django.mo | Bin 4918 -> 4879 bytes .../locale/es/LC_MESSAGES/django.po | 17 +- .../locale/it/LC_MESSAGES/django.mo | Bin 4753 -> 4714 bytes .../locale/it/LC_MESSAGES/django.po | 13 +- .../locale/pt/LC_MESSAGES/django.mo | Bin 4737 -> 4698 bytes .../locale/pt/LC_MESSAGES/django.po | 13 +- .../locale/ru/LC_MESSAGES/django.mo | Bin 6117 -> 6078 bytes .../locale/ru/LC_MESSAGES/django.po | 20 +-- .../web_theme/locale/en/LC_MESSAGES/django.po | 2 +- .../web_theme/locale/es/LC_MESSAGES/django.mo | Bin 1729 -> 1729 bytes .../web_theme/locale/es/LC_MESSAGES/django.po | 2 +- .../web_theme/locale/it/LC_MESSAGES/django.mo | Bin 1701 -> 1701 bytes .../web_theme/locale/it/LC_MESSAGES/django.po | 2 +- .../web_theme/locale/pt/LC_MESSAGES/django.mo | Bin 1688 -> 1688 bytes .../web_theme/locale/pt/LC_MESSAGES/django.po | 2 +- .../web_theme/locale/ru/LC_MESSAGES/django.mo | Bin 1937 -> 1937 bytes .../web_theme/locale/ru/LC_MESSAGES/django.po | 2 +- 225 files changed, 2007 insertions(+), 1996 deletions(-) diff --git a/apps/acls/locale/en/LC_MESSAGES/django.po b/apps/acls/locale/en/LC_MESSAGES/django.po index 983294f283..e7e9ea010d 100644 --- a/apps/acls/locale/en/LC_MESSAGES/django.po +++ b/apps/acls/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: 2012-02-02 14:18-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" @@ -122,11 +122,11 @@ msgstr "" msgid "access control lists for: %s" msgstr "" -#: views.py:49 views.py:412 +#: views.py:49 views.py:411 msgid "holder" msgstr "" -#: views.py:50 views.py:413 +#: views.py:50 views.py:412 msgid "permissions" msgstr "" @@ -135,75 +135,75 @@ msgstr "" msgid "permissions available to: %(actor)s for %(obj)s" msgstr "" -#: views.py:104 views.py:445 +#: views.py:104 views.py:444 msgid "namespace" msgstr "" -#: views.py:105 views.py:446 +#: views.py:105 views.py:445 msgid "label" msgstr "" -#: views.py:107 views.py:448 +#: views.py:107 views.py:447 msgid "has permission" msgstr "" -#: views.py:185 views.py:279 views.py:529 views.py:609 +#: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " msgstr "" -#: views.py:186 views.py:280 views.py:530 views.py:610 +#: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format msgid " for %s" msgstr "" -#: views.py:187 views.py:531 +#: views.py:187 views.py:530 #, python-format msgid " to %s" msgstr "" -#: views.py:190 views.py:534 +#: views.py:190 views.py:533 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "" -#: views.py:192 views.py:536 +#: views.py:192 views.py:535 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "" -#: views.py:199 views.py:543 +#: views.py:199 views.py:542 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:205 views.py:549 +#: views.py:205 views.py:548 #, python-format msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:281 views.py:611 +#: views.py:281 views.py:610 #, python-format msgid " from %s" msgstr "" -#: views.py:284 views.py:614 +#: views.py:284 views.py:613 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:286 views.py:616 +#: views.py:286 views.py:615 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:293 views.py:623 +#: views.py:293 views.py:622 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:299 views.py:629 +#: views.py:299 views.py:628 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" @@ -213,29 +213,29 @@ msgstr "" msgid "add new holder for: %s" msgstr "" -#: views.py:356 views.py:489 +#: views.py:356 views.py:488 msgid "Select" msgstr "" -#: views.py:389 +#: views.py:388 msgid "classes" msgstr "" -#: views.py:391 +#: views.py:390 msgid "class" msgstr "" -#: views.py:410 +#: views.py:409 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:438 +#: views.py:437 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:487 +#: views.py:486 #, python-format msgid "add new holder for class: %s" msgstr "" diff --git a/apps/acls/locale/es/LC_MESSAGES/django.mo b/apps/acls/locale/es/LC_MESSAGES/django.mo index c49ee5e0ec78b46713395bc7fb6b6c04f1664ea2..9570cc62603b6b94f7fd3ee6106ad6ce46666461 100644 GIT binary patch delta 493 zcmXZY&nts*9Ki9T?WrBM{902A#leXjp2O2pJS!&UV1Iy;nsQJs zu2yQvft%bElG}FTA~$ZLygzyB>3Q}2d_H|XpYL}+_7=Uk@l~#UBE3P8b`g0tL|UCT@0)Md^dXGmK*CsDSTYNnj$K|Wx#qN8c5*Q*mA1^3Wu~oII+L?f)#Kn(Xx?^<+jfz( OvsEn`EAvp#zO delta 509 zcmXZYKS)AR6vy#nPfN|rBnbMamEhLPh$z8If}oOyhz4=!6`~IQ$)`h;OIvNP8iR&t z4I~DC$7qPAXsRKIhQ5~`Jl=Fp|@a3(e@#+xi^N6@b-5P#tuKv-p5&pOfi^a12#&64kyHBvaPy^_JbwqYB=&>-!^i;}CTk$Ecp{ z9@RlwpqbV_UD154R*CC+u29R@x5szNMZH=!jcTD>)r-cSQPK;hS, 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-02 14:18-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-12 00:16+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:14 @@ -123,11 +124,11 @@ msgstr "Ver LCA por defecto de la clase" msgid "access control lists for: %s" msgstr "listas de control de acceso para: %s" -#: views.py:49 views.py:412 +#: views.py:49 views.py:411 msgid "holder" msgstr "titular" -#: views.py:50 views.py:413 +#: views.py:50 views.py:412 msgid "permissions" msgstr "permisos" @@ -136,48 +137,48 @@ msgstr "permisos" msgid "permissions available to: %(actor)s for %(obj)s" msgstr "permisos disponibles a: %(actor)s para %(obj)s " -#: views.py:104 views.py:445 +#: views.py:104 views.py:444 msgid "namespace" msgstr "espacio de nombres" -#: views.py:105 views.py:446 +#: views.py:105 views.py:445 msgid "label" msgstr "etiqueta" -#: views.py:107 views.py:448 +#: views.py:107 views.py:447 msgid "has permission" msgstr "tiene permiso" -#: views.py:185 views.py:279 views.py:529 views.py:609 +#: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " msgstr ", " -#: views.py:186 views.py:280 views.py:530 views.py:610 +#: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format msgid " for %s" msgstr " para %s" -#: views.py:187 views.py:531 +#: views.py:187 views.py:530 #, python-format msgid " to %s" msgstr " a %s" -#: views.py:190 views.py:534 +#: views.py:190 views.py:533 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "¿Está seguro que desea conceder el permiso %(title_suffix)s?" -#: views.py:192 views.py:536 +#: views.py:192 views.py:535 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "¿Está seguro que desea conceder los permisos de %(title_suffix)s?" -#: views.py:199 views.py:543 +#: views.py:199 views.py:542 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "Permiso \"%(permission)s\" otorgado a %(actor)s para %(object)s." -#: views.py:205 views.py:549 +#: views.py:205 views.py:548 #, python-format msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " @@ -185,27 +186,27 @@ msgid "" msgstr "" "%(actor)s, ya tenía el permiso \"%(permission)s\", otorgado para %(object)s." -#: views.py:281 views.py:611 +#: views.py:281 views.py:610 #, python-format msgid " from %s" msgstr " de %s" -#: views.py:284 views.py:614 +#: views.py:284 views.py:613 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "¿Está seguro que desea revocar el permiso %(title_suffix)s?" -#: views.py:286 views.py:616 +#: views.py:286 views.py:615 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "¿Está seguro de querer revocar los permisos %(title_suffix)s?" -#: views.py:293 views.py:623 +#: views.py:293 views.py:622 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "Permiso \"%(permission)s\" revocado del %(actor)s para %(object)s." -#: views.py:299 views.py:629 +#: views.py:299 views.py:628 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "%(actor)s, no tenía el permiso \"%(permission)s\" para %(object)s." @@ -215,31 +216,29 @@ msgstr "%(actor)s, no tenía el permiso \"%(permission)s\" para %(object)s." msgid "add new holder for: %s" msgstr "añadir nuevo titular para: %s" -#: views.py:356 views.py:489 +#: views.py:356 views.py:488 msgid "Select" msgstr "Seleccionar" -#: views.py:389 +#: views.py:388 msgid "classes" msgstr "clases" -#: views.py:391 +#: views.py:390 msgid "class" msgstr "clase" -#: views.py:410 +#: views.py:409 #, python-format msgid "default access control lists for class: %s" msgstr "listas de control de acceso por defecto para la clase: %s" -#: views.py:438 +#: views.py:437 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "permisos disponibles para: %(actor)s para la clase %(class)s " -#: views.py:487 +#: views.py:486 #, python-format msgid "add new holder for class: %s" msgstr "añadir nuevo titular para la clase: %s" - - diff --git a/apps/acls/locale/it/LC_MESSAGES/django.mo b/apps/acls/locale/it/LC_MESSAGES/django.mo index f82535c3d4ab2d41a6bbcad433ccc44cb2fa62a2..889b3132c9e73fd5daa9cff1a3dd97941dcde83a 100644 GIT binary patch delta 72 zcmbQh@{)Oi3gh~Ts-7xb0sbMn&PAz-C7Jnox-N+&sa6U`28Kqu21dGuMhb?eRz?OB bcOK>ONz6+xO-u*MW|mB@WsIKulu;W1FkKe- delta 85 zcmaFKJb`6`3gfkjs-Ef@B_#z``ugdaB^jkjddc~@`bGK0iA9\n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:14 @@ -122,11 +123,11 @@ msgstr "" msgid "access control lists for: %s" msgstr "" -#: views.py:49 views.py:412 +#: views.py:49 views.py:411 msgid "holder" msgstr "" -#: views.py:50 views.py:413 +#: views.py:50 views.py:412 msgid "permissions" msgstr "" @@ -135,75 +136,75 @@ msgstr "" msgid "permissions available to: %(actor)s for %(obj)s" msgstr "" -#: views.py:104 views.py:445 +#: views.py:104 views.py:444 msgid "namespace" msgstr "" -#: views.py:105 views.py:446 +#: views.py:105 views.py:445 msgid "label" msgstr "" -#: views.py:107 views.py:448 +#: views.py:107 views.py:447 msgid "has permission" msgstr "" -#: views.py:185 views.py:279 views.py:529 views.py:609 +#: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " msgstr "" -#: views.py:186 views.py:280 views.py:530 views.py:610 +#: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format msgid " for %s" msgstr "" -#: views.py:187 views.py:531 +#: views.py:187 views.py:530 #, python-format msgid " to %s" msgstr "" -#: views.py:190 views.py:534 +#: views.py:190 views.py:533 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "" -#: views.py:192 views.py:536 +#: views.py:192 views.py:535 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "" -#: views.py:199 views.py:543 +#: views.py:199 views.py:542 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:205 views.py:549 +#: views.py:205 views.py:548 #, python-format msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:281 views.py:611 +#: views.py:281 views.py:610 #, python-format msgid " from %s" msgstr "" -#: views.py:284 views.py:614 +#: views.py:284 views.py:613 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:286 views.py:616 +#: views.py:286 views.py:615 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:293 views.py:623 +#: views.py:293 views.py:622 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:299 views.py:629 +#: views.py:299 views.py:628 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" @@ -213,31 +214,29 @@ msgstr "" msgid "add new holder for: %s" msgstr "" -#: views.py:356 views.py:489 +#: views.py:356 views.py:488 msgid "Select" msgstr "" -#: views.py:389 +#: views.py:388 msgid "classes" msgstr "" -#: views.py:391 +#: views.py:390 msgid "class" msgstr "" -#: views.py:410 +#: views.py:409 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:438 +#: views.py:437 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:487 +#: views.py:486 #, python-format msgid "add new holder for class: %s" msgstr "" - - diff --git a/apps/acls/locale/pt/LC_MESSAGES/django.mo b/apps/acls/locale/pt/LC_MESSAGES/django.mo index c80761c957eaaaf30ce0dcad0c90e81d4f554c66..e9bdbc03ba1c2b6a75e8622d5ffdb1d85e9e59fc 100644 GIT binary patch delta 72 zcmbQt@`ibW3gf1Us-7xb0sbMn&PAz-C7Jnox-N+&sa6U`28Kqu21dGuMhb?eRz?OB bcb?$!Nz6+xO-u*M7L-hGV2qypf>9d)GjJCX delta 86 zcmaFEJeg&J3ggX*s-Ef@B_#z``ugdaB^jkjddc~@`bGK0iA9\n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:14 @@ -122,11 +123,11 @@ msgstr "" msgid "access control lists for: %s" msgstr "" -#: views.py:49 views.py:412 +#: views.py:49 views.py:411 msgid "holder" msgstr "" -#: views.py:50 views.py:413 +#: views.py:50 views.py:412 msgid "permissions" msgstr "" @@ -135,75 +136,75 @@ msgstr "" msgid "permissions available to: %(actor)s for %(obj)s" msgstr "" -#: views.py:104 views.py:445 +#: views.py:104 views.py:444 msgid "namespace" msgstr "" -#: views.py:105 views.py:446 +#: views.py:105 views.py:445 msgid "label" msgstr "" -#: views.py:107 views.py:448 +#: views.py:107 views.py:447 msgid "has permission" msgstr "" -#: views.py:185 views.py:279 views.py:529 views.py:609 +#: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " msgstr "" -#: views.py:186 views.py:280 views.py:530 views.py:610 +#: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format msgid " for %s" msgstr "" -#: views.py:187 views.py:531 +#: views.py:187 views.py:530 #, python-format msgid " to %s" msgstr "" -#: views.py:190 views.py:534 +#: views.py:190 views.py:533 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "" -#: views.py:192 views.py:536 +#: views.py:192 views.py:535 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "" -#: views.py:199 views.py:543 +#: views.py:199 views.py:542 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:205 views.py:549 +#: views.py:205 views.py:548 #, python-format msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:281 views.py:611 +#: views.py:281 views.py:610 #, python-format msgid " from %s" msgstr "" -#: views.py:284 views.py:614 +#: views.py:284 views.py:613 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "" -#: views.py:286 views.py:616 +#: views.py:286 views.py:615 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "" -#: views.py:293 views.py:623 +#: views.py:293 views.py:622 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:299 views.py:629 +#: views.py:299 views.py:628 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" @@ -213,31 +214,29 @@ msgstr "" msgid "add new holder for: %s" msgstr "" -#: views.py:356 views.py:489 +#: views.py:356 views.py:488 msgid "Select" msgstr "" -#: views.py:389 +#: views.py:388 msgid "classes" msgstr "" -#: views.py:391 +#: views.py:390 msgid "class" msgstr "" -#: views.py:410 +#: views.py:409 #, python-format msgid "default access control lists for class: %s" msgstr "" -#: views.py:438 +#: views.py:437 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "" -#: views.py:487 +#: views.py:486 #, python-format msgid "add new holder for class: %s" msgstr "" - - diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.mo b/apps/acls/locale/ru/LC_MESSAGES/django.mo index 2521c4c589b9de3d5082daa93541951b0f41beda..424eb9acbf82dc34649690c9af52155f052185fa 100644 GIT binary patch delta 404 zcmXZY&q@MO6vy#nRC8-=Y!MU~IMOC8urU-HkZNNtg#Hjgw9!QvA%c;MAo2|&8E7fJ zKp=>ZkkG14B19WEy@I&wd!5+S5q2?qck~TyZL?p>Ek9$Z-4saO@ zxQds!jdiSI8*k8D6e;0--~glKj485(XLy277{)K$#9vdI)5bZfdLWJpbI1OG%Gt9;`Hj&K*VR>{9qEx+Ln^@Hyi!#?UC_zN6k zoU9@uE0_q}$3yZt9^)%c=OW#onU`6wWvnYFWjkp%wd3`Sk8rVEt2D}$YuCPOcn|8T IJ5o90AJiZ)jsO4v delta 444 zcmXZYu}Z^G6vpvm6%)0s9Rvl%MjR9@##SqmL2$Bzpj|o$Vx!iy#Wa#MU{R<~AW9ZN zaB~-mgM(x71)O{b!AS>2{HN`5fA>3_b1vNPB3VUbNJI)8gIGjLVqpRu z9LGyc;VqtE8_Sp(W(Mzi{^BHgZ$xAP8@PiH7{xD~$Ns1^JB=x-;Xn>mJVJJejT3l= zvv`9!e8N@y!*DJe>zc<+vW-UAhvA-2q*Z>ffNET18TaGG?j@iQHoRi^;2S3K1H&JP zjdq>J8M2OJnD2Rv8{~7`#ux0&C0g&1>w&p)y?$!wx>c!{{e#6r$JSlPGu?{g>bBW1 sYkI}={E`<`l__;8qor4j^jdJGw1c9$8{IN%mTy`mLv#Jsv%0SQ1DE_i-2eap diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.po b/apps/acls/locale/ru/LC_MESSAGES/django.po index 9da4d973c0..46ce25ad4c 100644 --- a/apps/acls/locale/ru/LC_MESSAGES/django.po +++ b/apps/acls/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # Sergey Glita , 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-02 14:18-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:14 msgid "ACLs" @@ -123,11 +125,11 @@ msgstr "Просмотр списков ACL класса по умолчанию msgid "access control lists for: %s" msgstr "списки контроля доступа для %s" -#: views.py:49 views.py:412 +#: views.py:49 views.py:411 msgid "holder" msgstr "владелец" -#: views.py:50 views.py:413 +#: views.py:50 views.py:412 msgid "permissions" msgstr "разрешения" @@ -136,75 +138,75 @@ msgstr "разрешения" msgid "permissions available to: %(actor)s for %(obj)s" msgstr "разрешения, доступные %(actor)s для %(obj)s" -#: views.py:104 views.py:445 +#: views.py:104 views.py:444 msgid "namespace" msgstr "пространство имен" -#: views.py:105 views.py:446 +#: views.py:105 views.py:445 msgid "label" msgstr "этикетка" -#: views.py:107 views.py:448 +#: views.py:107 views.py:447 msgid "has permission" msgstr "имеет разрешение" -#: views.py:185 views.py:279 views.py:529 views.py:609 +#: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " msgstr "" -#: views.py:186 views.py:280 views.py:530 views.py:610 +#: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format msgid " for %s" msgstr "для %s" -#: views.py:187 views.py:531 +#: views.py:187 views.py:530 #, python-format msgid " to %s" msgstr "до %s" -#: views.py:190 views.py:534 +#: views.py:190 views.py:533 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" msgstr "Вы действительно хотите предоставить разрешение %(title_suffix)s?" -#: views.py:192 views.py:536 +#: views.py:192 views.py:535 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" msgstr "Вы уверены, что хотите предоставить разрешения %(title_suffix)s?" -#: views.py:199 views.py:543 +#: views.py:199 views.py:542 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgstr "" -#: views.py:205 views.py:549 +#: views.py:205 views.py:548 #, python-format msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." msgstr "" -#: views.py:281 views.py:611 +#: views.py:281 views.py:610 #, python-format msgid " from %s" msgstr "от%s" -#: views.py:284 views.py:614 +#: views.py:284 views.py:613 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" msgstr "Вы уверены, что хотите отменить разрешение %(title_suffix)s?" -#: views.py:286 views.py:616 +#: views.py:286 views.py:615 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" msgstr "Вы уверены, что хотите отменить разрешение %(title_suffix)s?" -#: views.py:293 views.py:623 +#: views.py:293 views.py:622 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgstr "" -#: views.py:299 views.py:629 +#: views.py:299 views.py:628 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." msgstr "" @@ -214,31 +216,29 @@ msgstr "" msgid "add new holder for: %s" msgstr "добавить нового владельца для %s" -#: views.py:356 views.py:489 +#: views.py:356 views.py:488 msgid "Select" msgstr "Выбор" -#: views.py:389 +#: views.py:388 msgid "classes" msgstr "классы" -#: views.py:391 +#: views.py:390 msgid "class" msgstr "класс" -#: views.py:410 +#: views.py:409 #, python-format msgid "default access control lists for class: %s" msgstr "списки контроля доступа умолчанию для класса %s" -#: views.py:438 +#: views.py:437 #, python-format msgid "permissions available to: %(actor)s for class %(class)s" msgstr "разрешения доступные %(actor)s для класса %(class)s" -#: views.py:487 +#: views.py:486 #, python-format msgid "add new holder for class: %s" msgstr "добавить нового владельца для класса %s" - - diff --git a/apps/common/locale/en/LC_MESSAGES/django.po b/apps/common/locale/en/LC_MESSAGES/django.po index e0d5d55e53..204dff27f1 100644 --- a/apps/common/locale/en/LC_MESSAGES/django.po +++ b/apps/common/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: 2012-02-02 14:17-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" @@ -111,62 +111,62 @@ msgstr "" msgid "function found" msgstr "" -#: views.py:35 +#: views.py:36 msgid "No action selected." msgstr "" -#: views.py:39 +#: views.py:40 msgid "Must select at least one item." msgstr "" -#: views.py:87 +#: views.py:88 #, python-format msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "" -#: views.py:90 views.py:114 +#: views.py:94 views.py:121 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "" -#: views.py:111 +#: views.py:115 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." msgstr "" -#: views.py:129 +#: views.py:136 msgid "Add" msgstr "" -#: views.py:140 +#: views.py:147 msgid "Remove" msgstr "" -#: views.py:163 +#: views.py:170 msgid "current user details" msgstr "" -#: views.py:180 +#: views.py:187 msgid "E-mail conflict, another user has that same email." msgstr "" -#: views.py:183 +#: views.py:190 msgid "Current user's details updated." msgstr "" -#: views.py:192 +#: views.py:199 msgid "edit current user details" msgstr "" -#: views.py:223 +#: views.py:230 msgid "License" msgstr "" -#: views.py:232 +#: views.py:239 msgid "Current user password change" msgstr "" -#: views.py:247 templates/password_change_done.html:5 +#: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." msgstr "" diff --git a/apps/common/locale/es/LC_MESSAGES/django.mo b/apps/common/locale/es/LC_MESSAGES/django.mo index af532bd9417dbba8eb6739b29f922aba600978ec..8eccd1e08b06a59bd86823c9871f97784c9f798b 100644 GIT binary patch delta 622 zcmXZZzb}J99LMofKl-3gJz7e%p0tC~<)IZq(Z7M_P5c95 zA?e7{fi4DO!D16JiHM||_czZoz3zK=x$k}MuB?i6z2UKMI+S|%DYdMWI`=D;#TWG8 z=zwF`)kH7zG0b5C4LraMo}h(IjNmuQIXas}12qg{FGdVys}O@Y6BS&+ZoJ1ZKHwyN zVgijp$25*n7ch@D_TV#);G0|jpibRJ>EjJJ0ZiUGUQ(Ccb#uts7q{Jkg?((8NBM$Pltjna!U{^_ zbxxI+*~3LV#ZGMEEZ(7fK^rB|6tQ_cWg)#)79~g?Cop};KoZs64HvGrC@=Ada=jn!q=##fetmZ-E(XWPS#xaUNs1kK=fP8dk9vRnvGBm97`7{{7+zwW{abpoZ2h7uryEtqYu_zizB zA&q~doX|o^VB<3G;%9t9!l_7yf3QB3gcO1, 2011, 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-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:39+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:20 @@ -115,64 +116,64 @@ msgstr "usuario anónimo" msgid "function found" msgstr "función encontrada" -#: views.py:35 +#: views.py:36 msgid "No action selected." msgstr "Ninguna acción seleccionada." -#: views.py:39 +#: views.py:40 msgid "Must select at least one item." msgstr "Debe seleccionar al menos un artículo." -#: views.py:87 +#: views.py:88 #, python-format msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "Se agrego exitosamente %(selection)s a %(right_list_title)s." -#: views.py:90 views.py:114 +#: views.py:94 views.py:121 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "No se puede agregar %(selection)s a %(right_list_title)s." -#: views.py:111 +#: views.py:115 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." msgstr "Se removió exitosamente %(selection)s de %(right_list_title)s." -#: views.py:129 +#: views.py:136 msgid "Add" msgstr "Agregar" -#: views.py:140 +#: views.py:147 msgid "Remove" msgstr "Remover" -#: views.py:163 +#: views.py:170 msgid "current user details" msgstr "detalles del usuario corriente" -#: views.py:180 +#: views.py:187 msgid "E-mail conflict, another user has that same email." msgstr "" "Conflicto de correo electrónica, otro usuario tiene ese mismo correo " "electrónico." -#: views.py:183 +#: views.py:190 msgid "Current user's details updated." msgstr "Datos del usuario corriente actualizados." -#: views.py:192 +#: views.py:199 msgid "edit current user details" msgstr "editar detalles del usuario corriente" -#: views.py:223 +#: views.py:230 msgid "License" msgstr "Licencia" -#: views.py:232 +#: views.py:239 msgid "Current user password change" msgstr "Cambio de contraseña de usuario actual" -#: views.py:247 templates/password_change_done.html:5 +#: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." msgstr "Su contraseña se ha modificado correctamente." @@ -183,8 +184,8 @@ msgstr "Ninguno" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using " -"tempfile.mkdtemp()" +"temporary files. If none is specified, one will be created using tempfile." +"mkdtemp()" msgstr "" "Directorio temporal utilizado por todo el sitio para almacenar imágenes en " "miniatura, vistas previas y los archivos temporales. Si no se especifica " @@ -347,5 +348,3 @@ msgstr "Iniciar sesión" #: templates/password_change_form.html:5 msgid "Password change" msgstr "Cambio de contraseña" - - diff --git a/apps/common/locale/it/LC_MESSAGES/django.mo b/apps/common/locale/it/LC_MESSAGES/django.mo index ac9bbfed478c7f5b070bb3d867ab819c1b727b00..95680511703bc58b937191c73453b90c1eab4030 100644 GIT binary patch delta 565 zcmXZY&nv@m9LMqZX11{(hLZ7}cC#dGaoL=;GAHEVpwXJ8rZhQz%V`(F4lYV+NiNh< zE^@+Btki1BfjHnVaP)k)@9FXVy!(7!pV#NR7x@{yH0`eh~wcsOK`4tEl_eFo*@5!(DXXr(aCzL6ZOg delta 603 zcmXZYPbkB27{~EvjLl{?l>C|HHg?$0q|`Xd$&G{Dev@VgoA%odB)d6iWm%NSnG=QL z;^t2+2Nx$tDF>u%r4;WcztijcJU!pf_xb%^!=?U{U|r$SA+qlk85I%BCo+M@Scf&+ zZ`&Vq)Bi=CcejW{a2$h}LA_VB-9(+=!YwEsUegStQhdohdp2TMq#Tp~M4#r6qxu{YF3t9IY4-WOkhU2l3a@BiXzHOfMOq%Ir-b~KN K`%Xi?O5-0l*i#Mw diff --git a/apps/common/locale/it/LC_MESSAGES/django.po b/apps/common/locale/it/LC_MESSAGES/django.po index dea31d3245..b29dd785f0 100644 --- a/apps/common/locale/it/LC_MESSAGES/django.po +++ b/apps/common/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:20 @@ -114,63 +115,62 @@ msgstr "" msgid "function found" msgstr "trovata funzione" -#: views.py:35 +#: views.py:36 msgid "No action selected." msgstr "Nessuna azione selezionata" -#: views.py:39 +#: views.py:40 msgid "Must select at least one item." msgstr "Devi selezionare un item" -#: views.py:87 +#: views.py:88 #, python-format msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "%(selection)s aggiunto con successo a %(right_list_title)s." -#: views.py:90 views.py:114 +#: views.py:94 views.py:121 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "Impossibile aggiungere %(selection)s a %(right_list_title)s." -#: views.py:111 +#: views.py:115 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." -msgstr "" -"%(selection)s aggiunto correttamente rimosso dal %(right_list_title)s." +msgstr "%(selection)s aggiunto correttamente rimosso dal %(right_list_title)s." -#: views.py:129 +#: views.py:136 msgid "Add" msgstr "Aggiungi" -#: views.py:140 +#: views.py:147 msgid "Remove" msgstr "Rimuovi" -#: views.py:163 +#: views.py:170 msgid "current user details" msgstr "dettagli dell'utente corrente" -#: views.py:180 +#: views.py:187 msgid "E-mail conflict, another user has that same email." msgstr "" -#: views.py:183 +#: views.py:190 msgid "Current user's details updated." msgstr "Dettagli dell'utente corrente aggiornati" -#: views.py:192 +#: views.py:199 msgid "edit current user details" msgstr "modifica i dettagli dell'utente corrente" -#: views.py:223 +#: views.py:230 msgid "License" msgstr "Licenza" -#: views.py:232 +#: views.py:239 msgid "Current user password change" msgstr "" -#: views.py:247 templates/password_change_done.html:5 +#: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." msgstr "La tua password è stata cambiata con successo" @@ -181,8 +181,8 @@ msgstr "Nessuno" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using " -"tempfile.mkdtemp()" +"temporary files. If none is specified, one will be created using tempfile." +"mkdtemp()" msgstr "" "Directory temporanea utilizzata a livello di sito per thumbnails, anteprime " "e file temporanei. Se non viene specificato, ne verrà creata utilizzando " @@ -193,8 +193,8 @@ msgid "" "Controls the mechanism used to authenticated user. Options are: username, " "email" msgstr "" -"Controllo del meccanismo di autenticazione. Le opzioni possibili " -"sono:username,email" +"Controllo del meccanismo di autenticazione. Le opzioni possibili sono:" +"username,email" #: conf/settings.py:74 msgid "Allow non authenticated users, access to all views" @@ -344,5 +344,3 @@ msgstr "Login" #: templates/password_change_form.html:5 msgid "Password change" msgstr "Cambia password" - - diff --git a/apps/common/locale/pt/LC_MESSAGES/django.mo b/apps/common/locale/pt/LC_MESSAGES/django.mo index 070eb0b939834f0920dc84e90b0f71cc0d30155c..3d237ca5107cda5a565c2dbdbe6064190d8f923b 100644 GIT binary patch delta 565 zcmXZYPbhs9N5Zb`Ex>|Tot7qG^gcYrDV@(av?RPw5%MQ z6j{kZxkzqYR*H7f;;I~mlK0Pk_3L^4{(nEu?=GAVpIc7*!Xc9Lij0ZKoKIvDchQMO z?UVKyJk^RvdLCS2y)R%_lW#Gh4xC^Qo}z(|*nve< zK|W9gsUUYspiyKIL+HXyZ3fl;9aJx{kE3{mD(DO5v24>(FOX@f{>d>;F}}tcGluVlQJJw_zP7~XNw3;9QB2uaplTZyp}r>4Mm1y e(V?tm-kY=WWFi$$EXP8tYuQ(Gp)lk7srv)eN$`0+IT>bt87t5Ve;%=f4 zrIbV{7gEZFE9J&DZYJJO`_)sg=h*l2e0M^(p(CHgc&!uJwu?-P$huQx8c)%JRntFH zi%X=LeJf6(8#SCqKN_gs?U?SOy1$QYc!)Y)qZJ3;Vu+7P*ew#o84P0%dvF^Y@eDih z(pJf3E3snKHX)mhtAgX#JxP)^aqn7-@y!eRy96VzK{-77DsDgC0 z)Pnetni9oDjH36P2if>L>RY$9Js9Fnt?G4f}8n z)z3Cj1=vCra32To%H03J4%Xku5J!8hZ~#@%A!JBh, 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:20 @@ -114,63 +115,62 @@ msgstr "" msgid "function found" msgstr "função encontrada" -#: views.py:35 +#: views.py:36 msgid "No action selected." msgstr "Nenhuma ação selecionada." -#: views.py:39 +#: views.py:40 msgid "Must select at least one item." msgstr "Deve selecionar pelo menos um item." -#: views.py:87 +#: views.py:88 #, python-format msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "%(selection)s adicionadas com sucesso a %(right_list_title)s ." -#: views.py:90 views.py:114 +#: views.py:94 views.py:121 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "Não foi possível adicionar %(selection)s para %(right_list_title)s ." -#: views.py:111 +#: views.py:115 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." -msgstr "" -" %(selection)s adicionado com sucesso removidos %(right_list_title)s." +msgstr " %(selection)s adicionado com sucesso removidos %(right_list_title)s." -#: views.py:129 +#: views.py:136 msgid "Add" msgstr "Adicionar" -#: views.py:140 +#: views.py:147 msgid "Remove" msgstr "Remover" -#: views.py:163 +#: views.py:170 msgid "current user details" msgstr "detalhes atuais do usuário" -#: views.py:180 +#: views.py:187 msgid "E-mail conflict, another user has that same email." msgstr "" -#: views.py:183 +#: views.py:190 msgid "Current user's details updated." msgstr "Detalhes do usuário atual atualizados." -#: views.py:192 +#: views.py:199 msgid "edit current user details" msgstr "editar os detalhes do usuário atual" -#: views.py:223 +#: views.py:230 msgid "License" msgstr "Licença" -#: views.py:232 +#: views.py:239 msgid "Current user password change" msgstr "" -#: views.py:247 templates/password_change_done.html:5 +#: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." msgstr "Sua senha foi alterada com êxito." @@ -181,12 +181,12 @@ msgstr "Nenhum" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using " -"tempfile.mkdtemp()" +"temporary files. If none is specified, one will be created using tempfile." +"mkdtemp()" msgstr "" "Diretório temporário usado para armazenar miniaturas, previews e arquivos " -"temporários. Se nenhum for especificado, um será criado usando " -"tempfile.mkdtemp()" +"temporários. Se nenhum for especificado, um será criado usando tempfile." +"mkdtemp()" #: conf/settings.py:65 msgid "" @@ -344,5 +344,3 @@ msgstr "Login" #: templates/password_change_form.html:5 msgid "Password change" msgstr "Alterar a senha" - - diff --git a/apps/common/locale/ru/LC_MESSAGES/django.mo b/apps/common/locale/ru/LC_MESSAGES/django.mo index 3f4e402873275d720824a874acb4342ff8a6ecb9..e56ec42c1ac6fd31356cde0a427751557b888a97 100644 GIT binary patch delta 566 zcmXZYze_?<6u|M5S&F|>%Ph0f%8Y)YVnHr8M2Y7q#~odXXa%MpZY7+n8>}FVIKlYZ{Y&HtIfJhp)JSo?a0% z?%_J-aT0a3VguC$zA%CozsMra;3yW6A!mFBv4*MxPpB^Tf~upYZ@(Te-&rb6d(awB hgyM6lM642YJUG^J#X>n($frW3a^>Bzt7n`|+dtfbKn?%^ delta 606 zcmXZZyDvj=6u|MLQA!`)ucoMXBGOyp*+IlWLy-s}#Bd4Kh?YJiEFFayNF&k2f50Fy zh{0nKlcBNMOg0t<6W?EYlbiebopXP`bI(0D?S1rKxlBp7N#xurGAbf>c99V@J48rJ zz;McN8jH!#;ykXQA0Mz4Ek)ULnqe1KlkdScoWyV3L5|2qu_UFA#U51$FpcB*ij7!b zBI3kh?7$^7zOZ`}% YQqQ&pTR;y76MAsf=Z+?>-S*$Yf0$uSZ2$lO diff --git a/apps/common/locale/ru/LC_MESSAGES/django.po b/apps/common/locale/ru/LC_MESSAGES/django.po index 0701d9e19b..b2c8e773e7 100644 --- a/apps/common/locale/ru/LC_MESSAGES/django.po +++ b/apps/common/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # 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: 2012-02-02 14:17-0400\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-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:20 msgid "change password" @@ -114,62 +116,62 @@ msgstr "" msgid "function found" msgstr "функция найдена" -#: views.py:35 +#: views.py:36 msgid "No action selected." msgstr "Никаких действий не выбрано." -#: views.py:39 +#: views.py:40 msgid "Must select at least one item." msgstr "Необходимо выбрать хотя бы один элемент." -#: views.py:87 +#: views.py:88 #, python-format msgid "%(selection)s added successfully added to %(right_list_title)s." msgstr "%(selection)s успешно добавлен в %(right_list_title)s ." -#: views.py:90 views.py:114 +#: views.py:94 views.py:121 #, python-format msgid "Unable to add %(selection)s to %(right_list_title)s." msgstr "Не удалось добавить %(selection)s до %(right_list_title)s ." -#: views.py:111 +#: views.py:115 #, python-format msgid "%(selection)s added successfully removed from %(right_list_title)s." msgstr "%(selection)s успешно удален из %(right_list_title)s ." -#: views.py:129 +#: views.py:136 msgid "Add" msgstr "Добавить" -#: views.py:140 +#: views.py:147 msgid "Remove" msgstr "Удалить" -#: views.py:163 +#: views.py:170 msgid "current user details" msgstr "данные пользователя" -#: views.py:180 +#: views.py:187 msgid "E-mail conflict, another user has that same email." msgstr "" -#: views.py:183 +#: views.py:190 msgid "Current user's details updated." msgstr "Данные пользователя обновлены." -#: views.py:192 +#: views.py:199 msgid "edit current user details" msgstr "редактировать данные пользователя" -#: views.py:223 +#: views.py:230 msgid "License" msgstr "Лицензия" -#: views.py:232 +#: views.py:239 msgid "Current user password change" msgstr "" -#: views.py:247 templates/password_change_done.html:5 +#: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." msgstr "Ваш пароль был изменен." @@ -180,8 +182,8 @@ msgstr "Ни один" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using " -"tempfile.mkdtemp()" +"temporary files. If none is specified, one will be created using tempfile." +"mkdtemp()" msgstr "" "Временный каталог, используемый сайтом для хранения миниатюр, превью и " "временных файлов. Если он не указан, он будет создан с использованием " @@ -317,8 +319,8 @@ msgid "" "List of %(title)s (%(start)s - %(end)s out of %(total)s) (Page " "%(page_number)s of %(total_pages)s)" msgstr "" -"Список %(title)s (%(start)s - %(end)s из %(total)s) (Page %(page_number)s из" -" %(total_pages)s)" +"Список %(title)s (%(start)s - %(end)s из %(total)s) (Page %(page_number)s из " +"%(total_pages)s)" #: templates/generic_list_horizontal_subtemplate.html:25 #: templates/generic_list_subtemplate.html:26 @@ -343,5 +345,3 @@ msgstr "Войти" #: templates/password_change_form.html:5 msgid "Password change" msgstr "Изменение пароля" - - diff --git a/apps/converter/locale/en/LC_MESSAGES/django.po b/apps/converter/locale/en/LC_MESSAGES/django.po index 0618b2b086..fe6c069c5b 100644 --- a/apps/converter/locale/en/LC_MESSAGES/django.po +++ b/apps/converter/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: 2012-02-02 14:17-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" diff --git a/apps/converter/locale/es/LC_MESSAGES/django.mo b/apps/converter/locale/es/LC_MESSAGES/django.mo index c66d22def849717549815eee3279082d30ce216b..8d9dd153033df4facbac22475260bfdcfe4f5859 100644 GIT binary patch delta 23 fcmdlrjd9mB#tk=hISh>y3{9Pjg$odYJ~_P diff --git a/apps/converter/locale/es/LC_MESSAGES/django.po b/apps/converter/locale/es/LC_MESSAGES/django.po index 7089a649f6..f16164c470 100644 --- a/apps/converter/locale/es/LC_MESSAGES/django.po +++ b/apps/converter/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-12-14 14:37+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/converter/locale/it/LC_MESSAGES/django.mo b/apps/converter/locale/it/LC_MESSAGES/django.mo index c0fe6b694140bc2782f97d97ad86d83a0f9fd37a..2b4b16da2ca57d5c96138969620943d05ec31560 100644 GIT binary patch delta 23 fcmbO|g>m*2#tk=hISh>y3{9dl delta 23 fcmbO|g>m*2#tk=hISh;x3{9*I%{M>PwUPk\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/converter/locale/pt/LC_MESSAGES/django.mo b/apps/converter/locale/pt/LC_MESSAGES/django.mo index 79dcb617691902cfd0059f8c2284789243638d1c..81f34b957c7b30ec703785b0007010187d66c912 100644 GIT binary patch delta 23 ecmbO|nQ``H#tj;}9EL^;hNf0V2Ad6Zvt+4vt\n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" diff --git a/apps/converter/locale/ru/LC_MESSAGES/django.mo b/apps/converter/locale/ru/LC_MESSAGES/django.mo index 3b20cd936ab9ddc93d6efa858f62e324b4e794b9..b45929dc4237efef30d2f7117956c84609919f09 100644 GIT binary patch delta 23 fcmZ2IlX3M-#tk=hISh>y3{9PJtYSKX diff --git a/apps/converter/locale/ru/LC_MESSAGES/django.po b/apps/converter/locale/ru/LC_MESSAGES/django.po index 91d33f90f4..0522a5d130 100644 --- a/apps/converter/locale/ru/LC_MESSAGES/django.po +++ b/apps/converter/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-22 19:01+0000\n" "Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/django_gpg/locale/en/LC_MESSAGES/django.po b/apps/django_gpg/locale/en/LC_MESSAGES/django.po index 871e1b3274..a54056bc8e 100644 --- a/apps/django_gpg/locale/en/LC_MESSAGES/django.po +++ b/apps/django_gpg/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: 2012-02-02 14:17-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" @@ -205,10 +205,10 @@ msgstr "" msgid "Identifies" msgstr "" -#: conf/settings.py:13 +#: conf/settings.py:15 msgid "List of keyservers to be queried for unknown keys." msgstr "" -#: conf/settings.py:14 +#: conf/settings.py:16 msgid "Home directory used to store keys as well as configuration files." msgstr "" diff --git a/apps/django_gpg/locale/es/LC_MESSAGES/django.mo b/apps/django_gpg/locale/es/LC_MESSAGES/django.mo index fc5b4088c5df6fac53ba9153e3e7c42e48de7d04..23818ef915b0b9bfe20ca77b68d3e79e0de31425 100644 GIT binary patch delta 435 zcmXZXF-QVo7{>9(%(|;fBO(Y6IU2+%QV`@KqCE(LhKdLYla`iHJnvRA*f}o)> za0$ZI29aoK3uLM#@4J`#p7;4avhD0mJrUg{q&Y{rlJx6J(|9o?Ww3)u zd`1snaRj@#f`3@X%pA%h9L#4)_Z0NXf) z@3@2+wr}Gm4qyxEt`7S6gqHV-R@`Tc6$#KDlt=r&j3r!1M-q?F0Rvlnj23)`*0he} zc#U?k*|UYCd_SNqctKn6)|>yJ6>=F`eh%$^0sApT%b#ydCRbDOx#K&9Vo)fB#hJM2 ZJbH_j-P(SoRt67)4%glx)VGnY=Z!8fAgTg2G0RY2FrQbnl&ojY-K`DJ!wD zv6I=_NhwMG0wr4(n(UPCDRsM_=RWs2zjL0aq3@xa^M>ksgUEbPnajT(H1 zI_W+3;0tQu$G@N0$@dRxgJ#mTL712B52FqgL(N}7t=~XD8r1w;tqMUrRak3vPmluizlKneXRIo dGCp&97JNPRTDC&Vrj)OkJV&x_?YZS3@CU@nN8$hg diff --git a/apps/django_gpg/locale/es/LC_MESSAGES/django.po b/apps/django_gpg/locale/es/LC_MESSAGES/django.po index 897c9e4957..f33c7104c6 100644 --- a/apps/django_gpg/locale/es/LC_MESSAGES/django.po +++ b/apps/django_gpg/locale/es/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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, 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-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:37+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:14 views.py:67 @@ -166,8 +167,8 @@ msgid "" "well." msgstr "" "¿Esta seguro que desea borrar la llave: %s? Si trata de borrar una llave " -"pública que es parte de un par público/privado la llave privada será borrada" -" también." +"pública que es parte de un par público/privado la llave privada será borrada " +"también." #: views.py:129 msgid "Query key server" @@ -213,16 +214,14 @@ msgstr "revocada" msgid "Identifies" msgstr "Identidades" -#: conf/settings.py:13 +#: conf/settings.py:15 msgid "List of keyservers to be queried for unknown keys." msgstr "" "Lista de servidores de llaves a ser utilizados para buscar llaves " "desconocidas." -#: conf/settings.py:14 +#: conf/settings.py:16 msgid "Home directory used to store keys as well as configuration files." msgstr "" "Directorio de inicio utilizado para almacenar las llaves, así como los " "archivos de configuración." - - diff --git a/apps/django_gpg/locale/it/LC_MESSAGES/django.mo b/apps/django_gpg/locale/it/LC_MESSAGES/django.mo index 6178823a5bccbe1f8633f1ad15ec60f94a424bf7..f6df524b0b27f6044cd82b1236c0254aadbc0b9d 100644 GIT binary patch delta 403 zcmXZWJ4gdT6ouil>*B6)eWFcJScs4+Xd#bydv4OF>8m}be(6Z_zSNY|4Wwy2>yrlY8GG;@ zhwwA8i!0PlO3L9XX7CuZc!9Lk3%dA*EPb$9-!G(vep0Gyii6w#-yn-c>Lr}T0}SyR z$)O6mMdGOXnQ9< L4AxtnVA1;nT3a$# delta 464 zcmXZWy-Px26vy$S-SVbZQVt?S7m8kp+f|DSX^Gr=9fBZ;xP_>YUb*)=1c9|S1r9;b z*br0%2K@oy&{_~Qv@|vrElqtN5FYrP=XnmlbIy{F$@`-~{VgD}7!tV=kwmwMg)QvG zU+h3FEYgR1+XQZLA4e09aTxD#3}28)`NJRvBO;X2i7GdSM9WY_>M}wx!Gj7|!&!83 z8m}>mAE@IO8u){%KhCFGa30mb1yqaXQ1x$OKki@*tL^s_%@R>|{fc`v-NzG*JGdD|~J6*Fi1`K*yir88zq9V0!HP0uwhLaoMuz8zk% OD}|a}pr!ewuWJ7*MM0qe diff --git a/apps/django_gpg/locale/it/LC_MESSAGES/django.po b/apps/django_gpg/locale/it/LC_MESSAGES/django.po index 23eab54c81..f636d037db 100644 --- a/apps/django_gpg/locale/it/LC_MESSAGES/django.po +++ b/apps/django_gpg/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:14 views.py:67 @@ -77,8 +78,8 @@ msgstr "Errore di firma" #: api.py:60 msgid "Document is signed but no public key is available for verification." msgstr "" -"Il documento è stato firmato, ma la chiave pubblica non è disponibile per la" -" verifica" +"Il documento è stato firmato, ma la chiave pubblica non è disponibile per la " +"verifica" #: api.py:64 msgid "Document is signed, and signature is good." @@ -211,12 +212,10 @@ msgstr "revocata" msgid "Identifies" msgstr "Identifica" -#: conf/settings.py:13 +#: conf/settings.py:15 msgid "List of keyservers to be queried for unknown keys." msgstr "Lista di server per chiavi che si possono interrogare." -#: conf/settings.py:14 +#: conf/settings.py:16 msgid "Home directory used to store keys as well as configuration files." msgstr "" - - diff --git a/apps/django_gpg/locale/pt/LC_MESSAGES/django.mo b/apps/django_gpg/locale/pt/LC_MESSAGES/django.mo index 4a908407bbbcf2f722c2cde25739338c3a0dad57..8850a353d8294700e0129ae4e33fcf5a68847c31 100644 GIT binary patch delta 307 zcmXZXuMa^{6u|N0c@N|9{MrbN2@)Gdc~unzO)$YU6P{qRy(B2go8k}9Y<_Hls;Igk z3;qV*Yqq=d+1)w!oO|BZ%{rug?#U-o)kSI|@-jr?me?7Y2Q^&$ z^DaiXud#qzRPV1C!aL^hfqDD{#QhC2>82XS2`S8?dRV~(+Q^X(A&fm#A041-JViBl zjutNe`38PA5}kzJfRo@4aS IPa~#%0aR-tssI20 delta 369 zcmXZXJ4?e*6u|M**jj1T))y{{{Q@yf6)IUAbP*K`I@#$eA&tssmD}~GbaXGJhUMk;}hsE6BBPU|!Md~6_oD`|z7Ea(E&fp== zVjFed1s3rd4ZI!4@374K5!dh;b^RAk;Sa9hFRtQJQ3n5mHt41sHn|pX8+G9^&Y?n% z#9Sr3ME%hr>c&^72j5@?@5k{c)cJ47j`EJv_=)T-%aY9-En~lvBt6HnJU{8AXY1!- z*NVbeMSd7rUDa2C<;QXA#--NLiMbQGD)Ga>+*OI|)EafWVb=Aj*_)2t91ZiYqjur6 Qe4qj^RURq5EGtxvKd4AKZ~y=R diff --git a/apps/django_gpg/locale/pt/LC_MESSAGES/django.po b/apps/django_gpg/locale/pt/LC_MESSAGES/django.po index 0c468c911f..9715eed041 100644 --- a/apps/django_gpg/locale/pt/LC_MESSAGES/django.po +++ b/apps/django_gpg/locale/pt/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:14 views.py:67 @@ -206,12 +207,10 @@ msgstr "" msgid "Identifies" msgstr "" -#: conf/settings.py:13 +#: conf/settings.py:15 msgid "List of keyservers to be queried for unknown keys." msgstr "" -#: conf/settings.py:14 +#: conf/settings.py:16 msgid "Home directory used to store keys as well as configuration files." msgstr "" - - diff --git a/apps/django_gpg/locale/ru/LC_MESSAGES/django.mo b/apps/django_gpg/locale/ru/LC_MESSAGES/django.mo index a55c4e91b6b1235e1c111705ce2353794fe3c0e6..ad90c0bcb457f9ecbb809f63521033f4bfd38268 100644 GIT binary patch delta 403 zcmW;Gu}T9$6ouiF7_w_z6H!6MxLL8);0A26h1iKiENp~;k|G3)2ny+ht!zRHVe3>{ zSPJ_BD&`@yG^J=`l|t~p!Z6=(=ghtH?x+6abtaxC7w83L6;xAg>E1pTK94b`pB4V>a2e^Svw4cXljrwT$ z2dv^NF5(ZeZ(r1d)}GMHjup^Ysp;U^B` z5^3cY&f^}Y@e!iRxCl$;c&PkB{6J)qm(Bkl7OI0za2796 z-TV$!Q3qB21vB`CBRDbiSFB?n-z%u*h2S-G8{V#Y-f>>ntF~A3t;}Jwt~*WFbnK?1 z*UeM2q1&$OS6pqUyqjKkDyC;Q8|e+xtK?I;tdUD+)k+zQd1JYK6X~{(qWiIu*{J$v Mm5Ad9-Dsol2hyiRHvj+t diff --git a/apps/django_gpg/locale/ru/LC_MESSAGES/django.po b/apps/django_gpg/locale/ru/LC_MESSAGES/django.po index 25dc120cf3..9ada823954 100644 --- a/apps/django_gpg/locale/ru/LC_MESSAGES/django.po +++ b/apps/django_gpg/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # 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: 2012-02-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:14 views.py:67 msgid "private keys" @@ -208,12 +210,10 @@ msgstr "отозван" msgid "Identifies" msgstr "Identifies" -#: conf/settings.py:13 +#: conf/settings.py:15 msgid "List of keyservers to be queried for unknown keys." msgstr "Список ключевых серверов для запроса неизвестных ключей." -#: conf/settings.py:14 +#: conf/settings.py:16 msgid "Home directory used to store keys as well as configuration files." msgstr "" - - diff --git a/apps/document_comments/locale/en/LC_MESSAGES/django.po b/apps/document_comments/locale/en/LC_MESSAGES/django.po index b77b0a235e..983d92c36c 100644 --- a/apps/document_comments/locale/en/LC_MESSAGES/django.po +++ b/apps/document_comments/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: 2012-02-02 14:17-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" diff --git a/apps/document_comments/locale/es/LC_MESSAGES/django.mo b/apps/document_comments/locale/es/LC_MESSAGES/django.mo index 3a098dbda394827f1e416f5699ba00c8c5fc8862..be935d1e1eecdb8e4629e99b3abbcf9c1cba29fa 100644 GIT binary patch delta 223 zcmZqRyU9CYOZ{#}1_lpi1_osY1_l;Z1_l!#tpTLXfOIU7RtM5kfV3iz-UFn$f%H8f zEdiuo0cjB+&CJHYU7Ke3_vp& z4gm!?fbLFUl`YEXvF;($7t-Ow7~I yEG{lhEuLJ\n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:19 __init__.py:20 @@ -94,5 +95,3 @@ msgstr "Añadir comentario al documento: %s" #, python-format msgid "comments: %s" msgstr "comentarios: %s" - - diff --git a/apps/document_comments/locale/it/LC_MESSAGES/django.mo b/apps/document_comments/locale/it/LC_MESSAGES/django.mo index 1fbae45066ce0540d56e3cb460771c86aa7ee55f..abb91fe5a93a612bed63d2e4ae1bf11a2b597667 100644 GIT binary patch delta 225 zcmcb{yPkK#miqOK3=AI33=Ap^3=BV57#NI!v@9!x4g}JwKz=KbmIuEg)S0qDFCKav#{}5g0qSVBa%=|oEm&B4(D+MD1LnB=SBV9uy1w&ISBZJ8&n2+-K YB<7`;CZ+?WGfO7-utabE!t#g_08&jRLjV8( delta 239 zcmZ3_dyRL(milXq3=AI33=Ap^3=HzD3=GCV+678i0BKbqe+`h92hx{-GzXCW1f+$5 z^lu<72&DPh7#OU8v?7oOsfz*9Ao&^~4U(S#q(S-?LFv^%ng__=!p0!Rzyf3(gi0I( z(m=#;ezPZ|36pw8NlAf~zJ7XUNk(asUUGh}eo=mLVo_#(k$!GsWn!LwW^r+8YVqV+ oW*H6xBLzbfD?{_i3z?5jE@p}1@=44~FHKBOwNlu8isdOI0MrvLH2?qr diff --git a/apps/document_comments/locale/it/LC_MESSAGES/django.po b/apps/document_comments/locale/it/LC_MESSAGES/django.po index 1f21111d51..dfa8084546 100644 --- a/apps/document_comments/locale/it/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:19 __init__.py:20 @@ -95,5 +96,3 @@ msgstr "Aggiungi un comento al documento: %s" #, python-format msgid "comments: %s" msgstr "commenti: %s" - - diff --git a/apps/document_comments/locale/pt/LC_MESSAGES/django.mo b/apps/document_comments/locale/pt/LC_MESSAGES/django.mo index 570fe8c0fc7c14f00778317265be864c77ecc052..40e5ce5c2e1fbda318a9fe1c1f2435d86f2d3e86 100644 GIT binary patch delta 225 zcmZqRyU9CYOZ_HB1_lpi1_m_-28Q1(3=AefT8Wi`!3;=;18IfOHX%76sDHK$;s!&jivS{Y#ylWKYNcRgU}&UkV5Dnkq+n=j gWn?h<1oH_VpTxZM(!_M2bV14FewOIX-&r`B0B_PJ761SM delta 240 zcmXZTy$-=(7{&327EOv65QCv1!Q@36lDYvBS73XIR0rDhLt^l836f4mtF`P#gV>w6 z0*le=G%@{>|H%n6`|RPe3u8nBfv84Al?0Irhp-E`FzQ!Wg)f+flq4#F49vqCjDCIC zfELWbBP_r(l;I6V|Hpq1lT;)T;f;`jA1J|ZFpR13`rLIbjWOMD=ia0_H5be_9c~+@ t%@%ykm&|Y+Z|3+Lp)9pJN?X<1J^v)!{gpVDM|`P!T%T!*6+A^b{sUyhEOP(= diff --git a/apps/document_comments/locale/pt/LC_MESSAGES/django.po b/apps/document_comments/locale/pt/LC_MESSAGES/django.po index e06675dd45..a58288495c 100644 --- a/apps/document_comments/locale/pt/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/pt/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:19 __init__.py:20 @@ -95,5 +96,3 @@ msgstr "Adicionar comentário ao documento: %s" #, python-format msgid "comments: %s" msgstr "comentários: %s" - - diff --git a/apps/document_comments/locale/ru/LC_MESSAGES/django.mo b/apps/document_comments/locale/ru/LC_MESSAGES/django.mo index ade9d6c51b437ce29b0eadd1f4a9844828496ab2..e779895d6d07ab2486a9090845bdb4c6754751f7 100644 GIT binary patch delta 225 zcmZn`ydyASOZ`tq1_lpi1_nn41_mcq28J*o-2$a=18Gel--wNYK?6v~0BJEG-3p`) zfb<+7tqP>i0%?%G&p_G*NPDqE^z{R2bs&EykOt{{2&I1jX=xyzp93h&0c2l2j`NBLhPtT>~RsLn8%4Q!68b$tReP a^7tg?rI#kA1Eq^fC-<;KZ~ns4&kO*#2_{hh delta 241 zcmca3&@4D%OT7XU1A_-M1A`+214AY&149^)UJa$0*ccczf&54ytpTK)fwUNqUIU~J zfb?M?tqP>S0BMjuDRu@17a&~-q(S<&0cmw0{QyXV^l@-NXn7zl4dk0~0EK~Uh9Drp z2c)Bcv;>gO+U&__!la&2Qc_^0ub-Y-l2MwZmz(0d=m50OB2&mtrUt%H=kjdzzhI%b}S?S diff --git a/apps/document_comments/locale/ru/LC_MESSAGES/django.po b/apps/document_comments/locale/ru/LC_MESSAGES/django.po index f05dc86d13..b5a68031b9 100644 --- a/apps/document_comments/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_comments/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # 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: 2012-02-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:19 __init__.py:20 msgid "delete" @@ -95,5 +97,3 @@ msgstr "Добавить комментарий на документ: %s" #, python-format msgid "comments: %s" msgstr "комментарии: %s" - - diff --git a/apps/document_indexing/locale/en/LC_MESSAGES/django.po b/apps/document_indexing/locale/en/LC_MESSAGES/django.po index c01c807d4a..f9f412dcc2 100644 --- a/apps/document_indexing/locale/en/LC_MESSAGES/django.po +++ b/apps/document_indexing/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: 2012-02-02 14:17-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,8 +17,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 -#: views.py:282 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 +#: views.py:280 msgid "indexes" msgstr "" @@ -26,7 +26,7 @@ msgstr "" msgid "index list" msgstr "" -#: __init__.py:33 views.py:76 +#: __init__.py:33 views.py:74 msgid "create index" msgstr "" @@ -73,13 +73,13 @@ msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" msgstr "" -#: api.py:97 api.py:112 +#: api.py:96 api.py:111 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" msgstr "" -#: api.py:151 +#: api.py:150 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "" @@ -116,7 +116,7 @@ msgstr "" msgid "Available functions: %s" msgstr "" -#: models.py:17 views.py:42 +#: models.py:17 views.py:40 msgid "name" msgstr "" @@ -124,7 +124,7 @@ msgstr "" msgid "Internal name used to reference this index." msgstr "" -#: models.py:18 views.py:43 +#: models.py:18 views.py:41 msgid "title" msgstr "" @@ -140,8 +140,8 @@ msgstr "" msgid "Causes this index to be visible and updated when document data changes." msgstr "" -#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 -#: views.py:197 views.py:227 views.py:267 +#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 +#: views.py:195 views.py:225 views.py:265 msgid "index" msgstr "" @@ -239,110 +239,110 @@ msgstr "" msgid "document indexes" msgstr "" -#: views.py:70 +#: views.py:68 msgid "Index created successfully." msgstr "" -#: views.py:94 +#: views.py:92 msgid "Index edited successfully" msgstr "" -#: views.py:100 +#: views.py:98 #, python-format msgid "edit index: %s" msgstr "" -#: views.py:125 +#: views.py:123 #, python-format msgid "Index: %s deleted successfully." msgstr "" -#: views.py:127 +#: views.py:125 #, python-format msgid "Index: %(index)s delete error: %(error)s" msgstr "" -#: views.py:139 +#: views.py:137 #, python-format msgid "Are you sure you with to delete the index: %s?" msgstr "" -#: views.py:164 +#: views.py:162 #, python-format msgid "tree template nodes for index: %s" msgstr "" -#: views.py:167 +#: views.py:165 msgid "level" msgstr "" -#: views.py:188 +#: views.py:186 msgid "Index template node created successfully." msgstr "" -#: views.py:194 +#: views.py:192 msgid "create child node" msgstr "" -#: views.py:215 +#: views.py:213 msgid "Index template node edited successfully" msgstr "" -#: views.py:221 +#: views.py:219 #, python-format msgid "edit index template node: %s" msgstr "" -#: views.py:228 views.py:268 views.py:336 +#: views.py:226 views.py:266 views.py:334 msgid "node" msgstr "" -#: views.py:250 +#: views.py:248 #, python-format msgid "Node: %s deleted successfully." msgstr "" -#: views.py:252 +#: views.py:250 #, python-format msgid "Node: %(node)s delete error: %(error)s" msgstr "" -#: views.py:261 +#: views.py:259 #, python-format msgid "Are you sure you with to delete the index template node: %s?" msgstr "" -#: views.py:285 +#: views.py:283 msgid "nodes" msgstr "" -#: views.py:318 +#: views.py:316 #, python-format msgid "contents for index: %s" msgstr "" -#: views.py:340 +#: views.py:338 msgid "items" msgstr "" -#: views.py:365 +#: views.py:363 msgid "Are you sure you wish to rebuild all indexes?" msgstr "" -#: views.py:366 +#: views.py:364 msgid "On large databases this operation may take some time to execute." msgstr "" -#: views.py:372 +#: views.py:370 msgid "Index rebuild completed successfully." msgstr "" -#: views.py:377 +#: views.py:375 #, python-format msgid "Index rebuild error: %s" msgstr "" -#: views.py:399 +#: views.py:397 #, python-format msgid "indexes containing: %s" msgstr "" diff --git a/apps/document_indexing/locale/es/LC_MESSAGES/django.mo b/apps/document_indexing/locale/es/LC_MESSAGES/django.mo index 8b6871508c1c320ac2672c1901bfd3f9766c9631..823a92e7fadcfe668160de3fb50f73762de19157 100644 GIT binary patch delta 1944 zcmY+^OK4PA9LMp0nq(YJnwO(Sr?J<^M6DS$6JsWiR%0~AXRsh5l1fZ&!(bd+XNo1- zj@Y6lv>V4FE)<2}LU5r$QCA}9LM*zn8x5kxg`0rr!q$b~-^{TjhxyOvo-^m3bM86+ zJMZFWTQg%-MSmKloA``4^@-U&EG_1XawA~&4c^2kR!=c&!%kd=zu+vqiW~4gc4Ad9 zKh7?kL;Ws>@foWBdu%bwSZJ!*3>vzz9(~-5r?CrPpl+<2W;PqUFoJtg1O0|e@H{TU z`?wfi=5Lsf)zte?6C81l;BM*< zun`x3ssY(8=P;`Ob<_inVI{u7nHVUe&iq!x1!LH9WS6ZCwZaapz%8f&dXUYq6l#E< zun13~j_wTdvFm*4iSJ@L{)IZtr^v@%@HHJ@V}@O_0KL>uiMla@njq?2=iH6zcMvt; zap&)-fls0qbivgxy81O#|69n%ZoB%Ua`vCyu*Wpa!++cl0UrB#0lR{SXdh?a;y6%c zwi?f)w)z<=CrVk>POQZ}_%jaS7<#xXWVQf@oaeBa`kfH_uZiE&unOn0&l+e4?!e3F zVIkY0ehYCWcA}E(Fe+(BT>E2eq+UX1YQlEZQTn(UlSq2mE$qO187?%?G%`##HlT+I zRB{cYlJO-j!(tvchAVLZ2e1_%qF&1q-nC}zLXCF}b^i@yD*GE5%EnPgkqPo{=?JP( z$ybX?vMBQK)`ZI9t*Bi20rk2aMfJagU*HwwH0%kg-#98K{zc`~R5Fy)uu7!KBFO1x ztlc$yjoPXtvN$`0TKP%m733l95o&^0sHA#}oSyxMT2Mtze&MrF$rwfTi=p18IBG!~ zF{Jl@I~OZx_!iaiG!~#b*Agn)I_-wa7D7*^V~7$93Ei)!-$byE+#in?rSUcrTM0ds z7D$TZj%Gb-{@ivlXRd7Ed#$@xhOZ)&aIHiO;SnkkLQmJNiYpDMq|@>7FK$hQ{#WV< zmDPE2-%3IqL#EI*u0bW3l1D}Vh!aaLM`%zMt8@{{3l$xk-U7WLN@nFlC!qvuBXn#k zU**YVzAo44S@oCru`K7Jorn`UdnJsD&TC@%lFBwhd0?YGfsSBZBAH6}Ci{FZd7$67 zM6%!i(Hl&p((W?t@BePFH=X}EJ5m-|Kj{PE3#wd z3ySNTTVnCiK*jeZK_)xk_4{77FC58MR)w=C!jU#Lrqt@jPxQK4f1=M%+5bPYpkz8R MI5_d=?4|I-57X7mCjbBd delta 1736 zcmX}sNob5S8&WFnD< zxDbcpQi)g&O>7C3lr-TW4!98!6-y%F`X-E}3jL3%6ktc4H&n!~GbSY&I9Wa2}pU-G3Ep z%p&%H$_y_2#BxlZ;!b8YHq$V8Ggb{{Eq4%ajF@Mw|S@ze5g~ZLmgcZ`B*DoT5%U< z;89G(e&l0k`C=1n03*8b8WnYT6Q|=N)B|rk-yt9S$d?8j_u9X__GCuU{b{HHv%GdL zGIuM&MOf)w--_?!m}mz3-^&j{_N5x{;%fYc+R8wdd*-d!Lc0%l;V7O!KeKgk5c6=v z^DC~Pot^CtycsKLA4c_a9k<}$Z1&%wvW5NC43FV*yogGo7g&xzyz515Qw8mvr~#v> zqq>6|aTrM#OC!bC;A~VsJ5bN{ql5QRx$`zcMafo8hLvFp2JjT_!Mj+Ci%5OFb~{lk z8$fk9hI&4QcZ{yA7j)i@cCVUHDRGItO{&%s3kfBqb~Tq!zG?hehDwt6 ze^D|i5!Vsgb|upWVlAPfY*$(468i(=#9}$2OL~hYN+FdhHG)oiXIr@Q(7{mmaVNYt z6n2K5CzU2A9O&!`NAoj$L%kX4amoIGQ@*^WyefJwGcVEauL)EQ-OfCcnyI@&PJ4&b Rd5~^8dZJx9zUXMqi+>j}n#%wH diff --git a/apps/document_indexing/locale/es/LC_MESSAGES/django.po b/apps/document_indexing/locale/es/LC_MESSAGES/django.po index 41cd0a8759..40c1d04b70 100644 --- a/apps/document_indexing/locale/es/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/es/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-12 00:27+0000\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" @@ -18,8 +18,8 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 -#: views.py:282 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 +#: views.py:280 msgid "indexes" msgstr "índices" @@ -27,7 +27,7 @@ msgstr "índices" msgid "index list" msgstr "lista de indices" -#: __init__.py:33 views.py:76 +#: __init__.py:33 views.py:74 msgid "create index" msgstr "crear índice" @@ -76,7 +76,7 @@ msgstr "" "Error en la expresión de actualización de indexación: %(expression)s; " "%(exception)s " -#: api.py:97 api.py:112 +#: api.py:96 api.py:111 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -84,7 +84,7 @@ msgstr "" "Error actualizando el indice de documento, expresión: %(expression)s; " "%(exception)s " -#: api.py:151 +#: api.py:150 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "No se puede eliminar el nodo de indexación de documento; %s" @@ -123,7 +123,7 @@ msgstr "No se puede eliminar el directorio de indexación; %s" msgid "Available functions: %s" msgstr "Funciones disponibles: %s" -#: models.py:17 views.py:42 +#: models.py:17 views.py:40 msgid "name" msgstr "nombre" @@ -131,7 +131,7 @@ msgstr "nombre" msgid "Internal name used to reference this index." msgstr "Nombre interno que se utiliza para hacer referencia a este índice." -#: models.py:18 views.py:43 +#: models.py:18 views.py:41 msgid "title" msgstr "título" @@ -150,8 +150,8 @@ msgstr "" "Hace que este índice sea visible y actualizado cuando los datos de " "documentos cambien." -#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 -#: views.py:197 views.py:227 views.py:267 +#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 +#: views.py:195 views.py:225 views.py:265 msgid "index" msgstr "índice" @@ -183,11 +183,11 @@ msgstr "" #: models.py:57 models.py:63 msgid "index template node" -msgstr "" +msgstr "nodo de plantilla de indice" #: models.py:58 msgid "indexes template nodes" -msgstr "" +msgstr "nodos de plantillas de indices" #: models.py:64 msgid "value" @@ -199,11 +199,11 @@ msgstr "documentos" #: models.py:75 msgid "index instance node" -msgstr "" +msgstr "nodo de instancia de indice" #: models.py:76 msgid "indexes instance nodes" -msgstr "" +msgstr "nodos de instancias de indices" #: models.py:80 msgid "index instance" @@ -253,112 +253,112 @@ msgstr "Generar índices de documentos" msgid "document indexes" msgstr "indices de documentos" -#: views.py:70 +#: views.py:68 msgid "Index created successfully." msgstr "Índice creado con exitosamente." -#: views.py:94 +#: views.py:92 msgid "Index edited successfully" msgstr "Índice editado con exitosamente." -#: views.py:100 +#: views.py:98 #, python-format msgid "edit index: %s" msgstr "editar Índice: %s" -#: views.py:125 +#: views.py:123 #, python-format msgid "Index: %s deleted successfully." msgstr "Índice: %s eliminado exitosamente." -#: views.py:127 +#: views.py:125 #, python-format msgid "Index: %(index)s delete error: %(error)s" msgstr "Error al borrar índice: %(index)s, error: %(error)s " -#: views.py:139 +#: views.py:137 #, python-format msgid "Are you sure you with to delete the index: %s?" msgstr "¿Seguro que desea eliminar el índice: %s?" -#: views.py:164 +#: views.py:162 #, python-format msgid "tree template nodes for index: %s" msgstr "nodos de la plantilla del árbol del índice: %s" -#: views.py:167 +#: views.py:165 msgid "level" msgstr "nivel" -#: views.py:188 +#: views.py:186 msgid "Index template node created successfully." msgstr "Nodo de plantilla de índice creado exitosamente." -#: views.py:194 +#: views.py:192 msgid "create child node" msgstr "crear nodo hijo" -#: views.py:215 +#: views.py:213 msgid "Index template node edited successfully" msgstr "Nodo de la plantilla de índice editado exitosamente" -#: views.py:221 +#: views.py:219 #, python-format msgid "edit index template node: %s" msgstr "editar nodo de la plantilla de índice: %s" -#: views.py:228 views.py:268 views.py:336 +#: views.py:226 views.py:266 views.py:334 msgid "node" msgstr "nodo" -#: views.py:250 +#: views.py:248 #, python-format msgid "Node: %s deleted successfully." msgstr "Nodo: %s eliminado exitosamente." -#: views.py:252 +#: views.py:250 #, python-format msgid "Node: %(node)s delete error: %(error)s" msgstr "Error de eliminación para nodo: %(node)s, %(error)s " -#: views.py:261 +#: views.py:259 #, python-format msgid "Are you sure you with to delete the index template node: %s?" msgstr "¿Seguro que desea eliminar el nodo de plantilla de indice: %s?" -#: views.py:285 +#: views.py:283 msgid "nodes" msgstr "nodos" -#: views.py:318 +#: views.py:316 #, python-format msgid "contents for index: %s" msgstr "contenido del indice: %s" -#: views.py:340 +#: views.py:338 msgid "items" msgstr "artículos" -#: views.py:365 +#: views.py:363 msgid "Are you sure you wish to rebuild all indexes?" msgstr "¿Está seguro que desea reconstruir todos los índices?" -#: views.py:366 +#: views.py:364 msgid "On large databases this operation may take some time to execute." msgstr "" "En bases de datos de gran tamaño esta operación puede tardar algún tiempo en" " ejecutarse." -#: views.py:372 +#: views.py:370 msgid "Index rebuild completed successfully." msgstr "Reconstrucción de Índices completada exitosamente." -#: views.py:377 +#: views.py:375 #, python-format msgid "Index rebuild error: %s" msgstr "Error de reconstrucción de índices: %s" -#: views.py:399 +#: views.py:397 #, python-format msgid "indexes containing: %s" msgstr "índices que contienen: %s" diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.mo b/apps/document_indexing/locale/it/LC_MESSAGES/django.mo index 16406cd1096d26c2a2dbe37bdc7f7a36ec75bf12..666b1225ac56d27679d3a84376cb4d47d843b9c3 100644 GIT binary patch delta 379 zcmXZXze@sP9LMpGVsckkl0-kqPzVBD>aH5HAqdhX8>+3AgW_;V8Vs6pXmjkgwjhF9 z3T|nLwps+s#i0M7|3Dn1_i;|I=ktBw`+S~3_9y#t5^Friq&-6_NE(>ZEape0P29#U zyut%~M;Fs$(lXYufcKchFRWn~CveA-7V!}G@e&uXg%18%YUqqZW;}YZi8lEYH?W6m z=&)@bJ)FjC42#|(-4);zzTpyfkiV!m%<)u|^O$D7ieceWsvI?~Frbuo@r zF^vjSQn-cVc!a}vgeb~TGyu$%}z!7{wZ_rosvZK|tTyow0jH(t5w^Z4l-6@-@U3PTaDBG&3S9MD@ z9H&xnLbT<&TdxN5p%vXKR`eoInvcP5 F{~yxGNAmyx diff --git a/apps/document_indexing/locale/it/LC_MESSAGES/django.po b/apps/document_indexing/locale/it/LC_MESSAGES/django.po index f0d1e65bcb..4559e02b61 100644 --- a/apps/document_indexing/locale/it/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/it/LC_MESSAGES/django.po @@ -1,25 +1,26 @@ # 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 -#: views.py:282 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 +#: views.py:280 msgid "indexes" msgstr "indici" @@ -27,7 +28,7 @@ msgstr "indici" msgid "index list" msgstr "lista indici" -#: __init__.py:33 views.py:76 +#: __init__.py:33 views.py:74 msgid "create index" msgstr "" @@ -76,7 +77,7 @@ msgstr "" "Errore nella creazione dell'indice per l'espressione: %(expression)s; " "%(exception)s" -#: api.py:97 api.py:112 +#: api.py:96 api.py:111 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -84,7 +85,7 @@ msgstr "" "Errore nell'aggiornamento delle'indice documento per l'espressione: " "%(expression)s; %(exception)s" -#: api.py:151 +#: api.py:150 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "Impossibile cancellare l'indice del documento; %s" @@ -123,7 +124,7 @@ msgstr "Impossibile cancellare la directory degli indici; %s" msgid "Available functions: %s" msgstr "Funzioni disponibili: %s" -#: models.py:17 views.py:42 +#: models.py:17 views.py:40 msgid "name" msgstr "" @@ -131,7 +132,7 @@ msgstr "" msgid "Internal name used to reference this index." msgstr "" -#: models.py:18 views.py:43 +#: models.py:18 views.py:41 msgid "title" msgstr "" @@ -144,12 +145,11 @@ msgid "enabled" msgstr "abilitato" #: models.py:19 -msgid "" -"Causes this index to be visible and updated when document data changes." +msgid "Causes this index to be visible and updated when document data changes." msgstr "" -#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 -#: views.py:197 views.py:227 views.py:267 +#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 +#: views.py:195 views.py:225 views.py:265 msgid "index" msgstr "indice" @@ -171,8 +171,8 @@ msgstr "link al documento" #: models.py:51 msgid "" -"Check this option to have this node act as a container for documents and not" -" as a parent for further nodes." +"Check this option to have this node act as a container for documents and not " +"as a parent for further nodes." msgstr "" #: models.py:57 models.py:63 @@ -247,120 +247,120 @@ msgstr "Ricostruisci indici documento" msgid "document indexes" msgstr "indici dei documenti" -#: views.py:70 +#: views.py:68 msgid "Index created successfully." msgstr "" -#: views.py:94 +#: views.py:92 msgid "Index edited successfully" msgstr "" -#: views.py:100 +#: views.py:98 #, python-format msgid "edit index: %s" msgstr "" -#: views.py:125 +#: views.py:123 #, python-format msgid "Index: %s deleted successfully." msgstr "" -#: views.py:127 +#: views.py:125 #, python-format msgid "Index: %(index)s delete error: %(error)s" msgstr "" -#: views.py:139 +#: views.py:137 #, python-format msgid "Are you sure you with to delete the index: %s?" msgstr "" -#: views.py:164 +#: views.py:162 #, python-format msgid "tree template nodes for index: %s" msgstr "" -#: views.py:167 +#: views.py:165 msgid "level" msgstr "" -#: views.py:188 +#: views.py:186 msgid "Index template node created successfully." msgstr "" -#: views.py:194 +#: views.py:192 msgid "create child node" msgstr "" -#: views.py:215 +#: views.py:213 msgid "Index template node edited successfully" msgstr "" -#: views.py:221 +#: views.py:219 #, python-format msgid "edit index template node: %s" msgstr "" -#: views.py:228 views.py:268 views.py:336 +#: views.py:226 views.py:266 views.py:334 msgid "node" msgstr "" -#: views.py:250 +#: views.py:248 #, python-format msgid "Node: %s deleted successfully." msgstr "" -#: views.py:252 +#: views.py:250 #, python-format msgid "Node: %(node)s delete error: %(error)s" msgstr "" -#: views.py:261 +#: views.py:259 #, python-format msgid "Are you sure you with to delete the index template node: %s?" msgstr "" -#: views.py:285 +#: views.py:283 msgid "nodes" msgstr "" -#: views.py:318 +#: views.py:316 #, python-format msgid "contents for index: %s" msgstr "contenuto per indice: %s" -#: views.py:340 +#: views.py:338 msgid "items" msgstr "voci" -#: views.py:365 +#: views.py:363 msgid "Are you sure you wish to rebuild all indexes?" msgstr "Sei sicuro di voler ricostruire l'indice ?" -#: views.py:366 +#: views.py:364 msgid "On large databases this operation may take some time to execute." msgstr "" "Per un database di grosse dimensioni l'operazione protrebbe aver bisogno di " "tempo." -#: views.py:372 +#: views.py:370 msgid "Index rebuild completed successfully." msgstr "Ricostruzione dell'indice avvenuta con successo" -#: views.py:377 +#: views.py:375 #, python-format msgid "Index rebuild error: %s" msgstr "Errore nella ricostruzione dell'indice: %s" -#: views.py:399 +#: views.py:397 #, python-format msgid "indexes containing: %s" msgstr "Gli indici contengono: %s" #: conf/settings.py:22 msgid "" -"A dictionary that maps the index name and where on the filesystem that index" -" will be mirrored." +"A dictionary that maps the index name and where on the filesystem that index " +"will be mirrored." msgstr "" #: templates/indexing_help.html:3 @@ -370,7 +370,5 @@ msgstr "Cosa sono gli indici ?" #: templates/indexing_help.html:4 msgid "Indexes group documents into a tree like hierarchical structure." msgstr "" -"Gli Indici dei documenti rappresentano , nella forma di albero, la struttura" -" gerarchica dei documenti stessi.." - - +"Gli Indici dei documenti rappresentano , nella forma di albero, la struttura " +"gerarchica dei documenti stessi.." diff --git a/apps/document_indexing/locale/pt/LC_MESSAGES/django.mo b/apps/document_indexing/locale/pt/LC_MESSAGES/django.mo index 19b351c41bcb5688b0bd858866c3876d1c848f38..7e20b34214a58b779451f59a565099a98dfae8ab 100644 GIT binary patch delta 380 zcmXZXKT88a5Qg#h4ADD1y$}@fPw-Nxm3RqA^guL)U=h^HMnMBg(kLmkN|AuA-I0{} z01+e@3u{3U6idNiXKQ0+CHO1|%l>AEVP>}F|IBobtlEtwZQ0VYBx_Kb!VuSR7Z^Z?D_#dyhwLd)m%q{mfFB4Wd{3$t@I5OXtPXap+ghqK32A{dLm) Ef7Bc>%K!iX delta 442 zcmXZXJxD@P6u|NG3d@g7>4UzAjEEwzrxKV#ROAq3*$@N~#H~ahq)&WLA}Aai9o!pS z1gF3?_vWZU8k&PzYG?}jKL`%@ckj7}bI<*mxeMK&Yt^nMvga0A6_G`+$P_AE#~akK zgD3cj$GGbgiC_!o@fB$y+JHzJz39P145Pvf)^HZzFpipEs#0K+@QZ9>6F2Z3*Klc& zJIv!GHgF6(IE^ppJoJsD_>0a!!vTiC1TJ9e|9pXjT(b1zZD3nuh)s<|5F6WC) z2b{nsbm0d&bzeAwy&RnUc(C2->AH6Ewp~iMfLyy diff --git a/apps/document_indexing/locale/pt/LC_MESSAGES/django.po b/apps/document_indexing/locale/pt/LC_MESSAGES/django.po index 03a01c827f..f84c9621fb 100644 --- a/apps/document_indexing/locale/pt/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/pt/LC_MESSAGES/django.po @@ -1,25 +1,26 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Renata Oliveira , 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 -#: views.py:282 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 +#: views.py:280 msgid "indexes" msgstr "índices" @@ -27,7 +28,7 @@ msgstr "índices" msgid "index list" msgstr "lista de índice" -#: __init__.py:33 views.py:76 +#: __init__.py:33 views.py:74 msgid "create index" msgstr "" @@ -76,7 +77,7 @@ msgstr "" "Erro de atualização na expressão de indexação do documento: %(expression)s; " "%(exception)s " -#: api.py:97 api.py:112 +#: api.py:96 api.py:111 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -84,7 +85,7 @@ msgstr "" "Erro de atualização de índice do documento, a expressão: %(expression)s ; " "%(exception)s " -#: api.py:151 +#: api.py:150 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "Não é possível excluir o nó de indexação de documentos; %s" @@ -123,7 +124,7 @@ msgstr "Não é possível excluir o diretório de indexação; %s" msgid "Available functions: %s" msgstr "Funções disponíveis: %s " -#: models.py:17 views.py:42 +#: models.py:17 views.py:40 msgid "name" msgstr "" @@ -131,7 +132,7 @@ msgstr "" msgid "Internal name used to reference this index." msgstr "" -#: models.py:18 views.py:43 +#: models.py:18 views.py:41 msgid "title" msgstr "" @@ -144,12 +145,11 @@ msgid "enabled" msgstr "habilitado" #: models.py:19 -msgid "" -"Causes this index to be visible and updated when document data changes." +msgid "Causes this index to be visible and updated when document data changes." msgstr "" -#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 -#: views.py:197 views.py:227 views.py:267 +#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 +#: views.py:195 views.py:225 views.py:265 msgid "index" msgstr "índice" @@ -171,8 +171,8 @@ msgstr "ligar documentos" #: models.py:51 msgid "" -"Check this option to have this node act as a container for documents and not" -" as a parent for further nodes." +"Check this option to have this node act as a container for documents and not " +"as a parent for further nodes." msgstr "" #: models.py:57 models.py:63 @@ -247,120 +247,119 @@ msgstr "Reconstruir índices de documento" msgid "document indexes" msgstr "índices de documento" -#: views.py:70 +#: views.py:68 msgid "Index created successfully." msgstr "" -#: views.py:94 +#: views.py:92 msgid "Index edited successfully" msgstr "" -#: views.py:100 +#: views.py:98 #, python-format msgid "edit index: %s" msgstr "" -#: views.py:125 +#: views.py:123 #, python-format msgid "Index: %s deleted successfully." msgstr "" -#: views.py:127 +#: views.py:125 #, python-format msgid "Index: %(index)s delete error: %(error)s" msgstr "" -#: views.py:139 +#: views.py:137 #, python-format msgid "Are you sure you with to delete the index: %s?" msgstr "" -#: views.py:164 +#: views.py:162 #, python-format msgid "tree template nodes for index: %s" msgstr "" -#: views.py:167 +#: views.py:165 msgid "level" msgstr "" -#: views.py:188 +#: views.py:186 msgid "Index template node created successfully." msgstr "" -#: views.py:194 +#: views.py:192 msgid "create child node" msgstr "" -#: views.py:215 +#: views.py:213 msgid "Index template node edited successfully" msgstr "" -#: views.py:221 +#: views.py:219 #, python-format msgid "edit index template node: %s" msgstr "" -#: views.py:228 views.py:268 views.py:336 +#: views.py:226 views.py:266 views.py:334 msgid "node" msgstr "" -#: views.py:250 +#: views.py:248 #, python-format msgid "Node: %s deleted successfully." msgstr "" -#: views.py:252 +#: views.py:250 #, python-format msgid "Node: %(node)s delete error: %(error)s" msgstr "" -#: views.py:261 +#: views.py:259 #, python-format msgid "Are you sure you with to delete the index template node: %s?" msgstr "" -#: views.py:285 +#: views.py:283 msgid "nodes" msgstr "" -#: views.py:318 +#: views.py:316 #, python-format msgid "contents for index: %s" msgstr "conteúdos para o índice: %s" -#: views.py:340 +#: views.py:338 msgid "items" msgstr "itens" -#: views.py:365 +#: views.py:363 msgid "Are you sure you wish to rebuild all indexes?" msgstr "Tem certeza de que deseja reconstruir todos os índices?" -#: views.py:366 +#: views.py:364 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." +"Em grandes bases de dados esta operação pode levar algum tempo para executar." -#: views.py:372 +#: views.py:370 msgid "Index rebuild completed successfully." msgstr "Reconstrução de índice concluída com êxito." -#: views.py:377 +#: views.py:375 #, python-format msgid "Index rebuild error: %s" msgstr "Reconstrução de índice de erro: %s" -#: views.py:399 +#: views.py:397 #, python-format msgid "indexes containing: %s" msgstr "índices contendo: %s" #: conf/settings.py:22 msgid "" -"A dictionary that maps the index name and where on the filesystem that index" -" will be mirrored." +"A dictionary that maps the index name and where on the filesystem that index " +"will be mirrored." msgstr "" #: templates/indexing_help.html:3 @@ -371,5 +370,3 @@ msgstr "Quais são os índices?" msgid "Indexes group documents into a tree like hierarchical structure." msgstr "" "Indexar documentos agrupados em uma árvore como uma estrutura hierárquica." - - diff --git a/apps/document_indexing/locale/ru/LC_MESSAGES/django.mo b/apps/document_indexing/locale/ru/LC_MESSAGES/django.mo index 3c66adf6c69cdd836ccc90e3e1a1454a14b179ca..a0d6bd05b166b2e780cb86f2cc88d3a6694f62c7 100644 GIT binary patch delta 379 zcmXZXze_?<7{>AE3c>Za*_eqHlpv8;szD+g0)>9j(jo*m3b&}hAwi_UC8(j>(B>F9 z1GwV5Cl%{Du*f0srrJUt_F6;H}ZfMgzu2kL1Q9gB6^=|y-&aXch F_y-14HI)DW delta 442 zcmXZX%}WA77zXesAyC__>=1n%HiQylTNP385JEjs*yz?@C5WU{+sLMWJ(GRQvFoVDtZP88o zPPgb>7qCaq={}7}K!Kjn6#b+j8tn#ZG)+h74PB;>^pMI7W$7JVpg$qhamgar0~F~; z+m&8GctM({1ARb}mgq1&rYgOqjNp|<=r^6BgJFOR>)f(*r`=!C3HJAtGvh5h3yiY( z<$?F`Q2+l=QZ&kbrmaD}3rEz;pHhXks5ih@^TPMsnXfp`Zbnthx>IqBlO?mNTBa>5 z-L%xIs0l;WZQIrC;8I~#nYJ|H=%%6MgrjBTL@b_AV&0PD$xJ-mIP*U=YJm-DUKnLp Nlo_$y=2Jil{sGY{OEmxh diff --git a/apps/document_indexing/locale/ru/LC_MESSAGES/django.po b/apps/document_indexing/locale/ru/LC_MESSAGES/django.po index e61a3fd1bf..b8fcb2f9cc 100644 --- a/apps/document_indexing/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/ru/LC_MESSAGES/django.po @@ -1,24 +1,26 @@ # 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-02 14:17-0400\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-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:31 __init__.py:45 __init__.py:47 models.py:42 views.py:38 -#: views.py:282 +#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 +#: views.py:280 msgid "indexes" msgstr "индексы" @@ -26,7 +28,7 @@ msgstr "индексы" msgid "index list" msgstr "список индекса" -#: __init__.py:33 views.py:76 +#: __init__.py:33 views.py:74 msgid "create index" msgstr "" @@ -75,7 +77,7 @@ msgstr "" "Ошибка в выражении обновления индексов документа: %(expression)s; " "%(exception)s" -#: api.py:97 api.py:112 +#: api.py:96 api.py:111 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" @@ -83,7 +85,7 @@ msgstr "" "Ошибка при обновлении индекса документа, выражение: %(expression)s; " "%(exception)s" -#: api.py:151 +#: api.py:150 #, python-format msgid "Unable to delete document indexing node; %s" msgstr "Не удается удалить узел индексирования документов; %s." @@ -122,7 +124,7 @@ msgstr "Не удается удалить каталог индексации; msgid "Available functions: %s" msgstr "Доступные функции: %s." -#: models.py:17 views.py:42 +#: models.py:17 views.py:40 msgid "name" msgstr "" @@ -130,7 +132,7 @@ msgstr "" msgid "Internal name used to reference this index." msgstr "" -#: models.py:18 views.py:43 +#: models.py:18 views.py:41 msgid "title" msgstr "" @@ -143,12 +145,11 @@ msgid "enabled" msgstr "разрешено" #: models.py:19 -msgid "" -"Causes this index to be visible and updated when document data changes." +msgid "Causes this index to be visible and updated when document data changes." msgstr "" -#: models.py:41 models.py:47 views.py:103 views.py:134 views.py:161 -#: views.py:197 views.py:227 views.py:267 +#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 +#: views.py:195 views.py:225 views.py:265 msgid "index" msgstr "индекс" @@ -170,8 +171,8 @@ msgstr "связать документы" #: models.py:51 msgid "" -"Check this option to have this node act as a container for documents and not" -" as a parent for further nodes." +"Check this option to have this node act as a container for documents and not " +"as a parent for further nodes." msgstr "" #: models.py:57 models.py:63 @@ -246,120 +247,120 @@ msgstr "Восстановление индексов документа" msgid "document indexes" msgstr "индексы документов" -#: views.py:70 +#: views.py:68 msgid "Index created successfully." msgstr "" -#: views.py:94 +#: views.py:92 msgid "Index edited successfully" msgstr "" -#: views.py:100 +#: views.py:98 #, python-format msgid "edit index: %s" msgstr "" -#: views.py:125 +#: views.py:123 #, python-format msgid "Index: %s deleted successfully." msgstr "" -#: views.py:127 +#: views.py:125 #, python-format msgid "Index: %(index)s delete error: %(error)s" msgstr "" -#: views.py:139 +#: views.py:137 #, python-format msgid "Are you sure you with to delete the index: %s?" msgstr "" -#: views.py:164 +#: views.py:162 #, python-format msgid "tree template nodes for index: %s" msgstr "" -#: views.py:167 +#: views.py:165 msgid "level" msgstr "" -#: views.py:188 +#: views.py:186 msgid "Index template node created successfully." msgstr "" -#: views.py:194 +#: views.py:192 msgid "create child node" msgstr "" -#: views.py:215 +#: views.py:213 msgid "Index template node edited successfully" msgstr "" -#: views.py:221 +#: views.py:219 #, python-format msgid "edit index template node: %s" msgstr "" -#: views.py:228 views.py:268 views.py:336 +#: views.py:226 views.py:266 views.py:334 msgid "node" msgstr "" -#: views.py:250 +#: views.py:248 #, python-format msgid "Node: %s deleted successfully." msgstr "" -#: views.py:252 +#: views.py:250 #, python-format msgid "Node: %(node)s delete error: %(error)s" msgstr "" -#: views.py:261 +#: views.py:259 #, python-format msgid "Are you sure you with to delete the index template node: %s?" msgstr "" -#: views.py:285 +#: views.py:283 msgid "nodes" msgstr "" -#: views.py:318 +#: views.py:316 #, python-format msgid "contents for index: %s" msgstr "содержания для индекса: %s." -#: views.py:340 +#: views.py:338 msgid "items" msgstr "членов" -#: views.py:365 +#: views.py:363 msgid "Are you sure you wish to rebuild all indexes?" msgstr "Вы уверены, что хотите перестроить все индексы?" -#: views.py:366 +#: views.py:364 msgid "On large databases this operation may take some time to execute." msgstr "" "В больших базах данных эта операция может занять некоторое время для " "выполнения." -#: views.py:372 +#: views.py:370 msgid "Index rebuild completed successfully." msgstr "восстановление индекса успешно завершено." -#: views.py:377 +#: views.py:375 #, python-format msgid "Index rebuild error: %s" msgstr "Индекс восстановить ошибка: %s" -#: views.py:399 +#: views.py:397 #, python-format msgid "indexes containing: %s" msgstr "индексы, содержащие: %s" #: conf/settings.py:22 msgid "" -"A dictionary that maps the index name and where on the filesystem that index" -" will be mirrored." +"A dictionary that maps the index name and where on the filesystem that index " +"will be mirrored." msgstr "" #: templates/indexing_help.html:3 @@ -369,5 +370,3 @@ msgstr "что за индексы?" #: templates/indexing_help.html:4 msgid "Indexes group documents into a tree like hierarchical structure." msgstr "Индексы группы документов в древовидной иерархической структуре." - - diff --git a/apps/document_signatures/locale/en/LC_MESSAGES/django.po b/apps/document_signatures/locale/en/LC_MESSAGES/django.po index c20bb776e9..c7ad3b7d10 100644 --- a/apps/document_signatures/locale/en/LC_MESSAGES/django.po +++ b/apps/document_signatures/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: 2012-02-02 14:18-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" diff --git a/apps/document_signatures/locale/es/LC_MESSAGES/django.mo b/apps/document_signatures/locale/es/LC_MESSAGES/django.mo index 809b0a7cd65170f646edc2d848fa525fb8dd239f..42f691415c21a19c9826f29205dda88faef511f7 100644 GIT binary patch delta 250 zcmXZVEepZ`6ouhC*_>bC{0@rDqS)p@1i`Gqf3UP5VzG$XWE6xYn@t!tlZapvtJUl; z5ERyYC#L6~6Ykj?OJn_9oD`9sDpC`XKoiMhIVw^@3$r-*>!3lNVgnbL!5yaXh&jAs z86W@r!74eSi*QO4i)iW6{|)yk>J$@9;~L|*#RB>m4qwp3JBE*5n8ZLo_{uHfZPZGv gWt**b*S5T~dQT1A>3HsrM_qF?^H!R3cx#==7mej3IRF3v delta 313 zcmXZVKTE@45XbRLX>HYl@joI;Ty%<0QyfabMFj^1I|v20M+s?$CXzfEoCLwWQ1m4@ zh+79=f-VYu2O@%#yQANzaPZ-Gcidgu4|f0K^4${IE{m**h%+WKhda249h|}B-z&7q zH@Ja!IE}AZ$2XkCFI+~e`j=O5mFyuSY2yNRsTsr6)bM7k@My8veZk{DQl_r@^qa;;5eW7C&Wmz6%6YZm8cQ*~R siIUje(, 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-02 14:18-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:30+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:83 @@ -121,5 +122,3 @@ msgstr "Firma aparte subida exitosamente." #, python-format msgid "Upload detached signature for: %s" msgstr "Subir firma aparte para: %s" - - diff --git a/apps/document_signatures/locale/it/LC_MESSAGES/django.mo b/apps/document_signatures/locale/it/LC_MESSAGES/django.mo index ca0e80de7c2286290884144057497791c2f51bce..fe8816f982b3e80f3efeb72fe4fea47a2c0b308e 100644 GIT binary patch delta 233 zcmdnS+s`{;PyKpE28JkR1_m_-1_mxx1_o&$Z3v`!fwV7><^j^tKw1DuX8>t+AYBQh z1%dQJAk77&Hv?&q`h7rJ0Z5+#(o#VBEs&N6(j06Mbs9h#q|O*fa|3BdHU>Gc!M;EN zki~I88mNb%3P|$->4wdbjAl$KTmk+ey3R$Zi6xo&dAcr%C8<^lMh1pPx&}tNhDHj8 irdCD delta 247 zcmW;Fu@1pd6vpvWEfG{mObDHHb5%s7&mghV?GkA_P-$-mlSE>!q%Xka0h*Ys5>H?d zt0(XRzM6i?$^V=asaN%Q+dU;BOD5_Nk&z{8z$sLrfF-zx6&OJso?sO|U;(~h+JB%1 zzpxH#IifaXFzqHV?JQV?PL5jt!vcf!@d09&&aezG$xIq%bVrDd$(Zd5C!BW|-irBN vz\n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:83 @@ -120,5 +121,3 @@ msgstr "Firma scaduta aggiornata con successo." #, python-format msgid "Upload detached signature for: %s" msgstr "Aggiornata firma scaduta per: %s" - - diff --git a/apps/document_signatures/locale/pt/LC_MESSAGES/django.mo b/apps/document_signatures/locale/pt/LC_MESSAGES/django.mo index df072bfcdd2b8ee95db4c6a64c2986cc9160f2dd..fac895b9facc76d240db3333d78879008454db86 100644 GIT binary patch delta 266 zcmdlc&@V9IPW>iE1_m(}1_liV28NTY3=EP$`V)|r2hu!j3=I50S_eoA0%;o{EefRl zfV3u%P65(lK)Me|a{=k4K$;gwZvfJ2KzbjLRshmZp?o%W1_n+bUl&M=0BLh}273l2 zAj1bJpaP`xfi%d#DL|S7NUsLcAPctuX=NaN3P^JU>32XHWWX=>&9fLcGO2I{_=o5^ z7o{eaWaj7Tx+IpQS}7PA7#iss80i`sDHxhs85vBT#&UwkCowO*G%+10T~IPPmNk0w IQPx5x00w#}f&c&j delta 281 zcmeAd*d{RHPW??r1_m(}1_liV28Iu;3=EP$T9S={K^{mO18IIB9So!efpjvE76sC! zKw1+>cLQlLAiWhxa{=iyK$;gwUkB1^K>8_=RshmG>=3>#kmdyPLx8jhkd9+#uxC&L zGKzr$DnNP~kOmpJ8%T2i=}SNwWZ`Wftqi0;0%>j_Eeezb8KB6qc^2bFCiRSxk^(Dz z{q)R|jM5~%q4DG8_g*3Wg?Dh8C0aSx!uL YVU6PUNz6+xO-xU\n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:83 @@ -120,5 +121,3 @@ msgstr "Assinatura separado enviado com sucesso." #, python-format msgid "Upload detached signature for: %s" msgstr "Upload de assinatura separada para: %s" - - diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.mo b/apps/document_signatures/locale/ru/LC_MESSAGES/django.mo index 5bc118cc1650a3c9fe0b907e77248b649d9c8fce..654273b01a6b5d4f538fd9bbdd8b578a343f5554 100644 GIT binary patch delta 265 zcmaDPv|DJxo%)}Q3=Co{3=F0W3=9Hn3=E1u+6_n>0qG1NEeND%18Gqpy%tD|1L?y+ z+5kx32GWv1nui@|29Q<*(jfh|K-vyS#{+2-AUzLCUk1{AKt2Zt1A{z}7Uuve(*rWh zfdU{p4M@uZ>8U^(WZ-5X4YKeQkk$m!kAO7D03J?=0n(diGHzm0;R^5%(RD6LO)SaG z&(n2DEJ?LeFfuSS(ls#BH8fH%G_^7^m^_W;D34EKUV3R_I#9Z(baE7H^yWjX3zz{D CO((_x delta 281 zcmdlj^hjvJoq7c(1_m(}1_o0G1_pCB1_nhSoeQLmfOJ2Q76j6VfV3!(z5=Ahf%GdN zZ2+X1*clikfwVD@76a10KpLb!1xVWg={6v30;G>Z>0dya56IW&U|^63(smp`WqLqH z98ds6_X25IAiW1jgABX{q(K&b1k##7nv)Y^fH9B;8Q`>eCgUb1^^B5|0xNy}^vsfs z(j>j){9OH_{Nlu-%={w#+{DVnJpIh#;?mUO$=)n790o=Th9*{q7L)T?j!t%DjpFf1 U%u6p#Oi#5^C@S4Ni*+G00HIDWDgXcg diff --git a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po index f4645708af..ab6528772e 100644 --- a/apps/document_signatures/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_signatures/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # Sergey Glita , 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-02 14:18-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:83 msgid "upload signature" @@ -121,5 +123,3 @@ msgstr "Отделённая подпись выложена." #, python-format msgid "Upload detached signature for: %s" msgstr "Выложить отделённую подпись для %s" - - diff --git a/apps/documents/locale/en/LC_MESSAGES/django.po b/apps/documents/locale/en/LC_MESSAGES/django.po index 78ed932de9..35f52ed355 100644 --- a/apps/documents/locale/en/LC_MESSAGES/django.po +++ b/apps/documents/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: 2012-02-02 14:17-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,7 +21,7 @@ msgstr "" msgid "all documents" msgstr "" -#: __init__.py:64 models.py:636 views.py:871 +#: __init__.py:64 models.py:653 views.py:871 msgid "recent documents" msgstr "" @@ -366,7 +366,7 @@ msgstr "" msgid "added" msgstr "" -#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: models.py:89 models.py:300 models.py:642 models.py:657 views.py:227 #: views.py:351 msgid "document" msgstr "" @@ -502,47 +502,47 @@ msgstr "" msgid "document page transformations" msgstr "" -#: models.py:624 +#: models.py:641 msgid "user" msgstr "" -#: models.py:626 +#: models.py:643 msgid "accessed" msgstr "" -#: models.py:635 +#: models.py:652 msgid "recent document" msgstr "" -#: models.py:641 +#: models.py:658 msgid "Document type" msgstr "" -#: models.py:642 +#: models.py:659 msgid "MIME type" msgstr "" -#: models.py:643 views.py:132 +#: models.py:660 views.py:132 msgid "Filename" msgstr "" -#: models.py:644 +#: models.py:661 msgid "Metadata value" msgstr "" -#: models.py:645 +#: models.py:662 msgid "Content" msgstr "" -#: models.py:646 +#: models.py:663 msgid "Description" msgstr "" -#: models.py:647 +#: models.py:664 msgid "Tags" msgstr "" -#: models.py:648 +#: models.py:665 msgid "Comments" msgstr "" diff --git a/apps/documents/locale/es/LC_MESSAGES/django.mo b/apps/documents/locale/es/LC_MESSAGES/django.mo index 1b4bd1f00bc36a08eb6ff9f6545fe8f6c52ca7d0..977bccbbc52ac6d3d5b9b907a7f86b7bd588a383 100644 GIT binary patch delta 2019 zcmXZde@K;A9LMqRC98Xz-PFu%ncYk))=a%uQ*T=4tfl?Z*`^j*5_##;4x~E-XEUl4}G0;p68tJ`F_uN zxYzrAz5Tw6UyOIY@|op^&6b$i-H2HehKkKvaUZtfuect|OU#8{oQd^VgH!P%%);|g$80i<0S1!s4*KygB(^=lTFfU+*0jCYg_n?` zSV@Iji8w0I1yq1rsC6IUEVN3qRLDV9s2Ej=xI?3g#wk>$cW^0YFE*Qwn{ff|_xgRP zg|6Wo9Q4#=_GEKW>ulj)98aT;Dp+N<5*sled$7|-WpB{Xj;pKP2kVif?Fg#mS1|{F z#1KBlEKGaLJ%R#Er(cevxCTR5LDbiABWlC@P#ZbQKh6IMIeNz)&|po=UFMc1h8yXh zLRI29>P}QHH!HwxsLS>VszNs~8~;SzA^+QEd6Fdas^p^>!~ow^4rZbt2u{XER3F@AiP}gHl8k+g+Fiq>?zZ8{NB`SdiWFw9>doRRM0Xr}Q521GWDQe;c)W)u&G8sbMjS*C!=cqGJ zYI1)gQc?3~pw=x!eU{5`3btaZzW+`dTHrA1#p9@nXHXUS5*7Fx%*ETN+wN<2GtNT= zF7T{CRjd~EW7L9+aSu+#epCVj=+}Zj(@^PtN8N#8)aNy}#XY<9%e9kIW+y%jXZef5 tp`wy#xG-@hoSRe@Esi992%k${)wVPCep_s7G_-Y3qBFAL^6kiuyjK|6|Fi%A delta 2059 zcmXZdeN5F=9LMo51;N#;a(NPk1bGk#>BS4ggDGT!lB9{sV==BkaFYjl>Va0*X6e=@ zlc?Bg%dN64%azLfBWt$hSlAzJ)SUj)AC>*#mdj?j=6ZO4c77Y?|{D!3($*Qyw(ih^<(HZz7Lu z9*6Ni)coOcvkLqk31xmdic?)-QDe+z7)ZtMun4c?8yKi`8~YF!(f<_}<1O^zKc4Yb zt{=b^jAvjXmSG;&;p2D!m*W?hi9b|D&5~){V!)4aq?3S2$Q~>M>v1m<%ihJqcoiv% zJ@JsM#1tyf6;yz`sCAP!nXSeG3}8K~LhYzZOhswb(71#;g1F6Q4`VH6;89$U?|c0P z)Iv9L4Qi4sK=x!iQR}?Mucz@c>Zr!Q6;~D zIrt}LWBMbmbd{(hXu=fi#NTinv$2b)EAbW7hEE_rc7|V>_!pKF-;!(1Slf1>N;8R1 z;w4lia_Zcj=*A%ZW@^jw<0d*ntUL04>mq+Q0-3;3?F5>5sa*(1N-2k6}8V!KHW^+wmI4V;Se5yR`{l zC%!#HLp${~xKgdc1p39Og(^|c8&R3|;(d4o*Wxkk$Me{QxsSP{If|Y1r%;*yfni*+ z(?c+>0O z#Q^=-MmIkVl~8sg_1BI{8Bl5Ku>kw95RaoObOG>?^L-(HtU7AnEQsMpwnSq!wHCQhI-nM6&TK?OXGI{S;Ljm#m*+0UpAmhE!^ z_IP&S62>E_%l9m5ohT;BDH`i&e1LJdfU3k*Ou;+24E;@RLz$=}$VZI_QS++3@mjCH z3zfh=uit@6tQ(cUbI3-b7WH13LIs?`H2eg$!>>^jub?(|1C@!d+1-r*Do_sU%!_a_ zR-oo@MXlS6`kMMN6<@`GzW;Y, 2011, 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-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-12 00:24+0000\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" +"PO-Revision-Date: 2012-02-12 08:43+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:63 msgid "all documents" msgstr "todos los documentos" -#: __init__.py:64 models.py:636 views.py:871 +#: __init__.py:64 models.py:653 views.py:871 msgid "recent documents" msgstr "documentos recientes" @@ -305,7 +306,8 @@ msgstr "Documento \"%(content_object)s\", creado por %(fullname)s." #: literals.py:12 #, python-format -msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgid "" +"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." msgstr "" "Documento \"%(content_object)s\", creado en %(datetime)s por %(fullname)s." @@ -321,8 +323,8 @@ msgstr "Documento \"%(content_object)s\", editado por %(fullname)s." #: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." -" The following changes took place: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " +"The following changes took place: %(changes)s." msgstr "" "Documento \"%(content_object)s\" fue editado en \"%(datetime)s por " "%(fullname)s. Los siguientes cambios tuvieron lugar: %(changes)s." @@ -382,7 +384,7 @@ msgstr "descripción" msgid "added" msgstr "agregado" -#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: models.py:89 models.py:300 models.py:642 models.py:657 views.py:227 #: views.py:351 msgid "document" msgstr "documento" @@ -521,47 +523,47 @@ msgstr "transformación de página de documento" msgid "document page transformations" msgstr "transformaciones de páginas de documentos" -#: models.py:624 +#: models.py:641 msgid "user" msgstr "usuario" -#: models.py:626 +#: models.py:643 msgid "accessed" msgstr "accesado" -#: models.py:635 +#: models.py:652 msgid "recent document" msgstr "documento reciente" -#: models.py:641 +#: models.py:658 msgid "Document type" msgstr "Tipo de documento" -#: models.py:642 +#: models.py:659 msgid "MIME type" msgstr "Tipo MIME" -#: models.py:643 views.py:132 +#: models.py:660 views.py:132 msgid "Filename" msgstr "Nombre del archivo" -#: models.py:644 +#: models.py:661 msgid "Metadata value" msgstr "Valor de metadatos" -#: models.py:645 +#: models.py:662 msgid "Content" msgstr "Contenido" -#: models.py:646 +#: models.py:663 msgid "Description" msgstr "Descripción" -#: models.py:647 +#: models.py:664 msgid "Tags" msgstr "Etiquetas" -#: models.py:648 +#: models.py:665 msgid "Comments" msgstr "Comentarios" @@ -643,8 +645,8 @@ msgstr "Documentos en almacenamiento: %d" #: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" -" bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " +"bytes" msgstr "" "Espacio utilizado en el almacenamiento: %(base_2)s (base 2), %(base_10)s " "(base 10), %(bytes)d bytes" @@ -816,8 +818,8 @@ msgstr "¿Está seguro que desea encontrar todos los duplicados?" #: views.py:575 views.py:633 views.py:701 msgid "On large databases this operation may take some time to execute." msgstr "" -"En bases de datos de gran tamaño esta operación puede tardar algún tiempo en" -" ejecutarse." +"En bases de datos de gran tamaño esta operación puede tardar algún tiempo en " +"ejecutarse." #: views.py:598 msgid "duplicated documents" @@ -835,8 +837,7 @@ msgstr "" #: views.py:632 #, python-format msgid "" -"Are you sure you wish to update the page count for the office documents " -"(%d)?" +"Are you sure you wish to update the page count for the office documents (%d)?" msgstr "" "¿Seguro que desea actualizar el número de páginas de los documentos de " "oficina (%d)?" @@ -866,8 +867,7 @@ msgstr "transformación de documento" #: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: " -"%s?" +"Are you sure you wish to clear all the page transformations for document: %s?" msgstr "" "¿Está seguro que desea eliminar todas las transformaciones de página del " "documento: %s?" @@ -999,8 +999,8 @@ msgstr "Nombre de archivo para tipo de documento: %s eliminado exitosamente." msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" msgstr "" -"Error de eliminación: %(error)s para nombre de archivo de tipo de documento:" -" %(document_type_filename)s " +"Error de eliminación: %(error)s para nombre de archivo de tipo de documento: " +"%(document_type_filename)s " #: views.py:1257 #, python-format @@ -1094,8 +1094,8 @@ msgstr "Siguiente paso" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per" -" user." +"Maximum number of recent (created, edited, viewed) documents to remember per " +"user." msgstr "" "El número máximo de documentos recientes (creados, editados, vistos) a " "recordar por usuario." @@ -1142,8 +1142,8 @@ msgstr "" "Los tipos de documentos definene una clase que representa a un grupo amplio " "de documentos, tales como: facturas, reglamentos o manuales. La ventaja de " "utilizar los tipos de documentos son: la asignación de una lista de nombres " -"de archivos típicos para el cambio de nombre rápido durante la creación, así" -" como la asignación de tipos de metadatos y grupos por defecto." +"de archivos típicos para el cambio de nombre rápido durante la creación, así " +"como la asignación de tipos de metadatos y grupos por defecto." #: templates/recent_document_list_help.html:3 msgid "What are recent documents?" @@ -1157,5 +1157,3 @@ msgid "" msgstr "" "Aquí encontrará los últimos %(recent_count)s documentos que haya creado o " "editado de alguna manera." - - diff --git a/apps/documents/locale/it/LC_MESSAGES/django.mo b/apps/documents/locale/it/LC_MESSAGES/django.mo index 609e68a54c843ca90c7fdbaa3160f49c8a3b5cfa..adea6f63b033b85d3a2e6bfb81f16f893be40bca 100644 GIT binary patch delta 1643 zcmXZcduYvJ9LMqRif!1iiw(Q9ahP+k`)rPxT^PbNmqtb|8AB|YRx7_!avRB!lx^e> z?4Mm|C6}VyvPCHoxz$8Oiy}pNfBb&6_IjS@cYe?J`+T48Ip15t`dY%ei^H9+Ftd2S z*=jSp8!#)u)Tw6mxEAN(1JCGbW(CZbV>TYfEWD0&_!(=ldb(LAcH&}ujX4-#F%oNW zB5uw!=l{ZC7KX8K(z6v4m|w(^cnhnsA4g*(8L`kmMc-)0L*%2Ivou~sm z#7X!ZDYpH^Jj`(TuguoqdOVGD@E6XPbGRk>%VfNxQW{Kioj z&xc~rhpN~N&lMQU+}X`QB|3n5u^*|DeMJ5&vCzHSDx~_>>p6g`NL-OysZ!L2D=`|k zdh2^Jj`>kkqUX?u9au$td+a?(;li4Dkb$bmdEAJvP#cu6sOQU&CF{d<96HNQAOjVk z7BUI?{st2e)lj+&&0fdbq?ov06$@f%b(|3E(`((i)qiVo^z?Wk_Qfoj@Eo?lUw8(r=ms2G)CRXO!n;AR%a;sH#+cGO0_sLI?$1?)#9 z{0@iWAdbhMSdB3iZbF+-C*6E{u#ku^Pyq%p3iacl(nX`X zI>DR!P?egFL$DNMa2|$Z4XWAJp%UMNdjAmWz0;^G>~I(;!+WR=o}e~(@2!8r;mp5# z&;NRk;&)k&`Za?^4Og1OnDQ~vab+_dbXV18ccroSy}@rIpS8aHg&989a<6IvBm KbMVvM^^D)d8k|QT{)n&R-bc-P zaSW?*1&?7OgIesuRGh*xoUS(K|A~1fb~16z^)}`*{suE}4ZCm~_h37_7UOZu#0aM2 zyQmFfcmU7i6L=2;SWMQF_#*o8`x?irjfY*NSAkuah2xlwXIw8KMcP$Vht}|MEUSxm zq8|$w&!8&%9P@DnRlu*fAOAs`ZRL-d@n@Y5|CQNW_!{28BUnOuPvR^1AYR5b{0h~X zPdSGMTt;>7Z`6j#Oezr%?#6?-7ducLd)ajYGZ{M{^Pm>Zpz59P4SKdFq`=hD&T2+0MEMf7ch(Q7pO$P#B#igo$POaxC?C@*cc0)sE*vh6S#wc z0`#NS$B`x5!cwd{7*C)RwLu@Mpg|;8yMhzAi8(lMDBh7tOlE(3p9i((BkaXRd;v2L z#{-^3op}WL5NrXT!5>f+`&d+hEtrVMaTZ@fYO^HHQypr?B77D-IE)WFJbb`I3SLLP zK)Z#y%|D~g?k`kj=||(YI|mCHm!Q6e0BXGh^YMAqWgWs|JdgS+uA}1KcE{hLqf2t1 z2L)J1RkVf5IEgE++gyNNY<3+$ReTOh@G`2hWz=o|33X|Icg=2zcdijtP#-G6Xbb(< z#+R7bhjW;V%cwxBsLpJlHrz%foYG2in1=;ej9u7-O6WaQrL(B`i>RZy>5i9NzioBQ z9%A7>6M6VAYJNgS56W;872r=)fK+~WHNP9vFdwyE?%IIr)KjQ{ucGe42rBRtmg7Y%!zEO_byR1! zPziby_*QhQ^H2d>Q3>>*S|3DpAiU7M>$jqcfkb{{t-^kEta3nl5 z;u{Q(2T%FJqodLO(b&`8qSTr?Ppv;t+ZY@4mZsEtYMKK6`q+ow3$Y`WJ!!{+r$W(S Ns6XIYn5kSW{139U)Ybq1 diff --git a/apps/documents/locale/it/LC_MESSAGES/django.po b/apps/documents/locale/it/LC_MESSAGES/django.po index 55f18fa359..d2fce3d972 100644 --- a/apps/documents/locale/it/LC_MESSAGES/django.po +++ b/apps/documents/locale/it/LC_MESSAGES/django.po @@ -1,28 +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: # , 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-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-11 08:45+0000\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" +"PO-Revision-Date: 2012-02-12 08:43+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:63 msgid "all documents" msgstr "tutti i documenti" -#: __init__.py:64 models.py:636 views.py:871 +#: __init__.py:64 models.py:653 views.py:871 msgid "recent documents" msgstr "documenti recenti" @@ -297,8 +298,10 @@ msgstr "Documento \"%(content_object)s\" creato da by %(fullname)s." #: literals.py:12 #, python-format -msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." -msgstr "Documento \"%(content_object)s\" creato il %(datetime)s da %(fullname)s." +msgid "" +"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "" +"Documento \"%(content_object)s\" creato il %(datetime)s da %(fullname)s." #: literals.py:18 msgid "Document edited" @@ -312,8 +315,8 @@ msgstr "Documento \"%(content_object)s\" modificato da %(fullname)s." #: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." -" The following changes took place: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " +"The following changes took place: %(changes)s." msgstr "" "Documento \"%(content_object)s\" è stato modificato il %(datetime)s da " "%(fullname)s. Queste le seguenti modifiche: %(changes)s." @@ -373,7 +376,7 @@ msgstr "descrizione" msgid "added" msgstr "ha aggiunto" -#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: models.py:89 models.py:300 models.py:642 models.py:657 views.py:227 #: views.py:351 msgid "document" msgstr "documento" @@ -438,8 +441,7 @@ msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." msgstr "" -"Questo tipo di formato file è sconosciuto, per cui il numero di pagine sarà " -"1" +"Questo tipo di formato file è sconosciuto, per cui il numero di pagine sarà 1" #: models.py:525 views.py:1353 msgid "filename" @@ -511,47 +513,47 @@ msgstr "trasformazione della pagina del documento" msgid "document page transformations" msgstr "trasformazioni della pagina del documento" -#: models.py:624 +#: models.py:641 msgid "user" msgstr "utente" -#: models.py:626 +#: models.py:643 msgid "accessed" msgstr "accessi" -#: models.py:635 +#: models.py:652 msgid "recent document" msgstr "documenti recenti" -#: models.py:641 +#: models.py:658 msgid "Document type" msgstr "Tipo documento" -#: models.py:642 +#: models.py:659 msgid "MIME type" msgstr "Tipo MIME" -#: models.py:643 views.py:132 +#: models.py:660 views.py:132 msgid "Filename" msgstr "Nome file" -#: models.py:644 +#: models.py:661 msgid "Metadata value" msgstr "Valore del Metadato" -#: models.py:645 +#: models.py:662 msgid "Content" msgstr "Contenuto" -#: models.py:646 +#: models.py:663 msgid "Description" msgstr "Descrizione" -#: models.py:647 +#: models.py:664 msgid "Tags" msgstr "Etichette" -#: models.py:648 +#: models.py:665 msgid "Comments" msgstr "Commenti" @@ -633,8 +635,8 @@ msgstr "Documenti nello storage:%d" #: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" -" bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " +"bytes" msgstr "" "Spazio usato nello storage: %(base_2)s (base 2), %(base_10)s (base 10), " "%(bytes)d bytes" @@ -779,7 +781,8 @@ msgstr "Document page trasformation edited successfully." #: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" -msgstr "Modifica la trasformazione \"%(transformation)s\" per: %(document_page)s" +msgstr "" +"Modifica la trasformazione \"%(transformation)s\" per: %(document_page)s" #: views.py:533 msgid "Document page transformation deleted successfully." @@ -791,8 +794,8 @@ msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " "%(document_page)s" msgstr "" -"Sei sicuro di voler cancellare la trasformazione \"%(transformation)s\" per:" -" %(document_page)s" +"Sei sicuro di voler cancellare la trasformazione \"%(transformation)s\" per: " +"%(document_page)s" #: views.py:562 #, python-format @@ -805,8 +808,7 @@ msgstr "Sei sicuro di voler trovare tutti i duplicati?" #: views.py:575 views.py:633 views.py:701 msgid "On large databases this operation may take some time to execute." -msgstr "" -"In un grande database questa operazione potrebbe richiedere del tempo " +msgstr "In un grande database questa operazione potrebbe richiedere del tempo " #: views.py:598 msgid "duplicated documents" @@ -824,8 +826,7 @@ msgstr "" #: views.py:632 #, python-format msgid "" -"Are you sure you wish to update the page count for the office documents " -"(%d)?" +"Are you sure you wish to update the page count for the office documents (%d)?" msgstr "" "Sei sicuro di voler cambiare il numero di pagine deil documenti office (%d)?" @@ -854,8 +855,7 @@ msgstr "trasformazione del documento" #: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: " -"%s?" +"Are you sure you wish to clear all the page transformations for document: %s?" msgstr "Sei sicuro di voler cancellare le trasformazioni per il documento:%s?" #: views.py:683 @@ -1076,8 +1076,8 @@ msgstr "Next step" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per" -" user." +"Maximum number of recent (created, edited, viewed) documents to remember per " +"user." msgstr "" "Massimo numero recente (creazione, modifica, visualizzazione) di documenti " "da ricordare per utente" @@ -1120,8 +1120,8 @@ msgid "" "creation, as well as assigning default metadata types and sets to it." msgstr "" "Il tipo di documento definisce una raggruppamento di documenti, come : " -"fatture, regolamenti, manuali. Il vantaggio dell'uso di tale classificazione" -" permette di rinominare,aggiungere metadati e rinominare i file più " +"fatture, regolamenti, manuali. Il vantaggio dell'uso di tale classificazione " +"permette di rinominare,aggiungere metadati e rinominare i file più " "velocemente." #: templates/recent_document_list_help.html:3 @@ -1136,5 +1136,3 @@ msgid "" msgstr "" "qui troverete gli ultimi %(recent_count)s documenti da voi creati o " "modificati" - - diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.mo b/apps/documents/locale/pt/LC_MESSAGES/django.mo index 1ba95a785b7826b7c51bb8455442ad7af50d508c..2f39bc5b394590f7d2d92f49004fba110081b2b7 100644 GIT binary patch delta 1603 zcmXZcSxD4T6vy#nlv+)TwpfnKq?VH{?k$s=nPjvmV#SnY7?rfx1QpT7KU&cuswpah z3MmLe3?)dR@WEE-p+I_wA|E0uNMDL*|Ni*T)92p%zxUjG&b>1ao1!i?Mco}6?X*Xk z#bufW&8)|7R)xt^&DLNe*5XrKhZ$LB0X%|v_y7xV07E!=n!ElY&Y}MSOEG1-*$7;Z zn%{^XY?*G34W-e>z%cB@iP(dq@f|M5{z$)ghMAXsCC1}c9FB)D7MpN3p2rG&jyg#E zOtTZX6!Y;FF2v|;hpcEU$u>*C5RSo<7>8Gp%XJo$L3NUoPj!E4XTo-92zR|V^qL2>RO8RNL8%`S8zoyPzOw-eoVChs$$#GhkG#< zFJltk$2jbbeE*0#Xl$W7o{r`8okAKDXzWL27)E9C64&4#)QN+$+)U0QvFsk|K%X%g z2Qf*N^Iu^M$p`%xvkiOQr4 zlkhDn&`-=jPpP|cE^6K~R3ahN_oJwUZlmILpbq{FHLtIf`bX3F#(*aLMr{z!MQc0* zwed8p#Koupmr#M*B6guNe}sB$FHmvb;!NzvWK1b@-%JszqSa-NTapb7XyJBL$qu4U zcpP=dS5OPC;Sg*?ZEz1Y?+L1;Z&35Tq8I<+Nc8e=qwy?M{CViXawpQLMg^=x1>A{R za12$Mi>Rx*gQ?h!D)IY>L(1JmvQUW>p#DkAQE#ITweddG8#schVASc3p`K!IxG^&+ zHaE|gTNud837^ZH6qD!6nG-0;4|itX@GPs}(Xgk!VN<}jb9XrCukGme|MmU{{*k@7 delta 1664 zcmXZcTS!z<6vpvoSejWmR$8fOH??v+j#}xIr8X61WrYus_Ar^*6go9Cg55a16!{X= zguX>q5M78aM0BAdD3F36LMVa?f*!g<4+Rqazh+?Ix6eNNti9J-=gdG~%7ea?Ym>*g zuT#uCC1#t=>~pDEGY00GZNXF6ir;Z7HqA5h<3+5*k64Yl^UcDz7WMpntijAOvwB>C zMIFdP zIt4fvRk>9-3tKT8U7Uy~QI$N4QGAZH-nDufbbyI9*nm%QJEqqr0(7D7A4c6D!D3uW z{U&1vPQd-xjD5)2>@_OWti@(ia3<;_=D`g1w*UhLZq@|0qXKoKT5|}q zupjlcT)iE7OTbXCH32Bp}G>d_#oWY18U ze87B6txp7+fqECJP#bSXt&5@(=||nagi7cID&8B^!GECEr8iLjF%0r)tQO2dowOD; z--OzD6RyWFD!>C&;NhenP?>*0y==cwaZ(%2$}tBEa0UKP7*)~UMmJHCJ|^^F996P& zs1sg6_4pC$fhRZ`hfy26MXmdWD(NWxRkUsj=3z0am5s^yji~tBQ2&6t-Q=Jb74Qfu z-~cMnWmIMEqfY)33-J@G#A$(qWvJe6L?zOS({MMcMMqE@pFyp=h^k=9&6{I0>++g* z#$tQ?j?)>6?d;iB-X899BH?H-5(-D0uHe34w-bs+dpe>S8=70Z%Of4ZSSZ}>4FqEy z{-VkXU!}J~zan3?-?u2ft7Jx+uc)HNU%eoHvgAyBS?QK>YlGdLJ;6?v?>RS6n*R?T CEYQ9H diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.po b/apps/documents/locale/pt/LC_MESSAGES/django.po index 0b5fd1d47d..6c35f3b702 100644 --- a/apps/documents/locale/pt/LC_MESSAGES/django.po +++ b/apps/documents/locale/pt/LC_MESSAGES/django.po @@ -1,28 +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: # , 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-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-11 08:45+0000\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" +"PO-Revision-Date: 2012-02-12 08:43+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:63 msgid "all documents" msgstr "todos os documentos" -#: __init__.py:64 models.py:636 views.py:871 +#: __init__.py:64 models.py:653 views.py:871 msgid "recent documents" msgstr "documentos recentes" @@ -294,8 +295,10 @@ msgstr "Documento \"%(content_object)s\" criado por %(fullname)s." #: literals.py:12 #, python-format -msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." -msgstr "Documento \"%(content_object)s\" criado em %(datetime)s por %(fullname)s." +msgid "" +"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "" +"Documento \"%(content_object)s\" criado em %(datetime)s por %(fullname)s." #: literals.py:18 msgid "Document edited" @@ -309,8 +312,8 @@ msgstr "Documento \"%(content_object)s\" editado por %(fullname)s." #: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." -" The following changes took place: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " +"The following changes took place: %(changes)s." msgstr "" "Documento \"%(content_object)s\" foi editado em %(datetime)s por " "%(fullname)s. As seguintes alterações foram realizadas: %(changes)s." @@ -370,7 +373,7 @@ msgstr "descrição" msgid "added" msgstr "adicionado" -#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: models.py:89 models.py:300 models.py:642 models.py:657 views.py:227 #: views.py:351 msgid "document" msgstr "documento" @@ -435,8 +438,8 @@ msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." msgstr "" -"Este formato de arquivo não é conhecida, a contagem de página, portanto, tem" -" o padrão 1." +"Este formato de arquivo não é conhecida, a contagem de página, portanto, tem " +"o padrão 1." #: models.py:525 views.py:1353 msgid "filename" @@ -508,47 +511,47 @@ msgstr "página de transformações do documento" msgid "document page transformations" msgstr "Página de transformações de documentos" -#: models.py:624 +#: models.py:641 msgid "user" msgstr "usuário" -#: models.py:626 +#: models.py:643 msgid "accessed" msgstr "acessado" -#: models.py:635 +#: models.py:652 msgid "recent document" msgstr "documento recente" -#: models.py:641 +#: models.py:658 msgid "Document type" msgstr "Tipo de documento" -#: models.py:642 +#: models.py:659 msgid "MIME type" msgstr "Tipo MIME" -#: models.py:643 views.py:132 +#: models.py:660 views.py:132 msgid "Filename" msgstr "Nome do arquivo" -#: models.py:644 +#: models.py:661 msgid "Metadata value" msgstr "Valor de metadados" -#: models.py:645 +#: models.py:662 msgid "Content" msgstr "Conteúdo" -#: models.py:646 +#: models.py:663 msgid "Description" msgstr "Descrição" -#: models.py:647 +#: models.py:664 msgid "Tags" msgstr "Tags" -#: models.py:648 +#: models.py:665 msgid "Comments" msgstr "Comentários" @@ -630,8 +633,8 @@ msgstr "Documentos no armazenamento: %d" #: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" -" bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " +"bytes" msgstr "" "Espaço usado no armazenamento: %(base_2)s (base 2), %(base_10)s (base 10), " "%(bytes)d bytes" @@ -802,8 +805,7 @@ msgstr "Tem certeza de que deseja encontrar todas as duplicatas?" #: views.py:575 views.py:633 views.py:701 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." +"Em grandes bases de dados esta operação pode levar algum tempo para executar." #: views.py:598 msgid "duplicated documents" @@ -819,8 +821,7 @@ msgstr "" #: views.py:632 #, python-format msgid "" -"Are you sure you wish to update the page count for the office documents " -"(%d)?" +"Are you sure you wish to update the page count for the office documents (%d)?" msgstr "" #: views.py:664 @@ -848,8 +849,7 @@ msgstr "transformação de documento" #: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: " -"%s?" +"Are you sure you wish to clear all the page transformations for document: %s?" msgstr "" "Tem certeza de que deseja limpar todas as transformações de página para o " "documento: %s?" @@ -1075,8 +1075,8 @@ msgstr "Próximo passo" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per" -" user." +"Maximum number of recent (created, edited, viewed) documents to remember per " +"user." msgstr "" "Número máximo de documentos recentes (criado, editado, visualizado) à ser " "lembrado, por usuário." @@ -1120,9 +1120,9 @@ msgid "" "creation, as well as assigning default metadata types and sets to it." msgstr "" "Tipos de documentos definir uma classe que representa um grupo de " -"documentos, tais como: notas fiscais, regulamentos ou manuais. A vantagem de" -" usar os tipos de documentos são: a atribuição de uma lista de nomes típicos" -" para renomear rápidamente durante a criação, bem como atribuir tipos de " +"documentos, tais como: notas fiscais, regulamentos ou manuais. A vantagem de " +"usar os tipos de documentos são: a atribuição de uma lista de nomes típicos " +"para renomear rápidamente durante a criação, bem como atribuir tipos de " "padrão de metadados e conjuntos para ele." #: templates/recent_document_list_help.html:3 @@ -1137,5 +1137,3 @@ msgid "" msgstr "" "Aqui você encontrará os últimos %(recent_count)s documentos que você tenha " "criado ou editado de alguma maneira." - - diff --git a/apps/documents/locale/ru/LC_MESSAGES/django.mo b/apps/documents/locale/ru/LC_MESSAGES/django.mo index 19b6037a4f06d0cdbb80fb68ced3d15cfb225be6..9dc415ec6117791a2c450507584fd549f86325a1 100644 GIT binary patch delta 2022 zcmXZdTTE0(7{KulgJKj{G>9TnL7-beWOrF`T`HmlTkJ~lf>dxtL<*>2#9-54JtP)y zR9jeV42>9(HnFLf#0!}CVuY94)M%o-Xp|SDl{C==O=E)oKj%FCX6EdfneTG4kMD;K z+z-2SCBhmB6G`@n1Vv<$SELEIVFM0hH5O)z9L96lfu0P=vpkY2HSBRKEe>X zeIf^O2-jj@iAX7)#*;XR|r0@q?4p1{>Ojz42ynFx24 zNB9NK$v68{*&aeY=safNZQK8mv&Bi21z2M-sATX525<_e7GoKHg1;k=7g?~yfm zjE6CueCzrZWKW49EhIs5Vj8$b30QVk6GL7Sv20!_#;Nr*gjR zB5zug7Tkx|u@-Z<-c#(sBy6LF^#bSc2OPy3+)c}KM;XQqm_q(DaUW`v{)t`Kk5L$) z4*3|we$JO322R|-+w*Zh>JNKRBfW@m_zaUVoPz4csmL9~i^uQ~a)!+M+C1Nmdzm+5 zK8|85W^6R)TtLgs!aoecQ42H(6LAmzh1Hl>VLs1ZbTJ=9t@)TekK1G}8bGQiZRo&z zNPEc$&O~R>G_M~ufb~K0uMa9&n2b%Bh%K0br!XCFV+_8*Xmo5gUq=#Z>I0aA-KYoO zMa|$7)E;<=b8*~WkF7KrNUJ3OTH94DXbBoIAAdou^)Tx5xm!%v=b_fN0b}tLda)n1 z=|*us#?ra*coGlbHJp$BttJ!Y_%ZVai$MZ|F4S(miu&Rc)JVorFE))j%)xBbNQ%*i z^|&2-Q8O@Yo5)94fSTEA+r6k6K7#r+bmDBZ`WWOfxPiLyTTI3nT00SQQ7;rky-*8k zDUMVdCO-+PCt==g^J8T29VTe6IS{-7E)(k6_{Uhfq`h8a2h4^(G@LP~YE(^YB}AVi$gnH&EXXr(PdQiIJM>VjW-wreYoH#+|mm zT`rm)l@x0A%$w}?B)GHv9#^Q(lNjMiaQXb+tkB<{w#YzLV{LO)ZH+&nsX0`VRdIPB H%enYHg^(G% delta 2062 zcmXZbeN5DK9Ki7p#^hEk5Y(iOIE3RN9`3cU3{qc8yy}sY?@Av(Ezn_QS znYom!b15fIr5TnbB86^|fQVFhMEdY8?7>Cs!ku1`5xj^8v8_sE2hL+VZmkw+!jt$k zrq+lguod^?0ybmpL6K+hdpwL*pBT3fKJ639XCZs7$OiP{$M`aKV$M2|l{lC*fp;?h z9GBzir03De{3_ZpvsQ$&qzVUcH|FAXEJsV7VZP|C<7E~)FdcW|MjXHhevMC}eZ9yi z#*jNps$b+WT#tI-NYdk|2VKGnyphyKbet`XxC!4j7z7#oj1B1G)J7b_68s5yBsZ}X zYaSvS*ojm_29d1GN!*OraSN{H>*F|zTe0Y2GxbBL7r%soB_c+~BOWed|k^YMJVFraP#4^+mZ$|yCI`ADlj+`OuTFvJN z@g?T(qaU-|ME2qq)N|(0a54CYK`ItgplK|}82*i28168C&slUbpGU2^b(=Zgh;180s`L@fsE}A2S%(7@R}x=HF2_rjd7z#EyC~ z53a&(sFB1`Q$C6>;4EqeJkOIQ+<}_e14%zX&F~4-zu_$2gT@60bqubdet0!4U5K@q zkDaI&8b-a)1ZpY1zykaMHKhx<9REYDZPs@4z+BXQMOcbnT#7+tzaiTh=nDr>BRzuJ z?NdoFC%uK0tgq-cORx#;%==OQ^Y>6M@>$X|r~%BPzBiBh-DMHe3S6Q8e?0?DZ4fom zS5Rwp2sM%~QA;z0PFz4ueQwlDaSLijqNw}#q7^^HVmybB;x*L$Wz_3-DKTAB9oGTA zj-~i6YVFP@{c*BBBeS45(%-+^=WujK`y=tr%C6oXM_+F&)EDjTbM%A;Lc1K%SS%in zCEDCpi_>j$d3>(w#2$Bkn#<;_@p-(7qwY5n)oa?*8$!FfgV{Xfag BC{zFd diff --git a/apps/documents/locale/ru/LC_MESSAGES/django.po b/apps/documents/locale/ru/LC_MESSAGES/django.po index 85a5b50c3e..33dbe60733 100644 --- a/apps/documents/locale/ru/LC_MESSAGES/django.po +++ b/apps/documents/locale/ru/LC_MESSAGES/django.po @@ -1,29 +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: # Roberto Rosario , 2011. # Sergey Glita , 2011, 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-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-11 08:45+0000\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" +"PO-Revision-Date: 2012-02-12 08:43+0000\n" "Last-Translator: Sergey Glita \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:63 msgid "all documents" msgstr "все документы" -#: __init__.py:64 models.py:636 views.py:871 +#: __init__.py:64 models.py:653 views.py:871 msgid "recent documents" msgstr "последние документы" @@ -286,8 +288,8 @@ msgid "" "This option is selectable only when downloading one document, for multiple " "documents, the bundle will always be downloads as a compressed file." msgstr "" -"Скачать документ в исходном формате или сжатым. Этот вариант доступен только" -" при загрузке одного документа, для нескольких документов будет использован " +"Скачать документ в исходном формате или сжатым. Этот вариант доступен только " +"при загрузке одного документа, для нескольких документов будет использован " "сжатый файл." #: literals.py:10 @@ -301,7 +303,8 @@ msgstr "Документ \"%(content_object)s\", создан %(fullname)s ." #: literals.py:12 #, python-format -msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgid "" +"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." msgstr "" "Документ \"%(content_object)s\" создан %(datetime)s пользователем " "%(fullname)s." @@ -318,11 +321,11 @@ msgstr "Документ \"%(content_object)s\" редактировал %(fulln #: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." -" The following changes took place: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " +"The following changes took place: %(changes)s." msgstr "" -"Документ \"%(content_object)s\" был изменён %(datetime)s %(fullname)s. Были" -" внесены изменения: %(changes)s." +"Документ \"%(content_object)s\" был изменён %(datetime)s %(fullname)s. Были " +"внесены изменения: %(changes)s." #: literals.py:29 msgid "Document deleted" @@ -379,7 +382,7 @@ msgstr "описание" msgid "added" msgstr "добавлено" -#: models.py:89 models.py:300 models.py:625 models.py:640 views.py:227 +#: models.py:89 models.py:300 models.py:642 models.py:657 views.py:227 #: views.py:351 msgid "document" msgstr "документ" @@ -443,8 +446,7 @@ msgstr "версия документа" msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." -msgstr "" -"Этот формат файла документа не известен, количество страниц поэтому 1." +msgstr "Этот формат файла документа не известен, количество страниц поэтому 1." #: models.py:525 views.py:1353 msgid "filename" @@ -516,47 +518,47 @@ msgstr "преобразование страницы документа" msgid "document page transformations" msgstr "преобразования документов страницу" -#: models.py:624 +#: models.py:641 msgid "user" msgstr "пользователь" -#: models.py:626 +#: models.py:643 msgid "accessed" msgstr "допущен" -#: models.py:635 +#: models.py:652 msgid "recent document" msgstr "недавний документ" -#: models.py:641 +#: models.py:658 msgid "Document type" msgstr "Тип документа" -#: models.py:642 +#: models.py:659 msgid "MIME type" msgstr "MIME-тип" -#: models.py:643 views.py:132 +#: models.py:660 views.py:132 msgid "Filename" msgstr "Имя файла" -#: models.py:644 +#: models.py:661 msgid "Metadata value" msgstr "Метаданны значение" -#: models.py:645 +#: models.py:662 msgid "Content" msgstr "Содержимое" -#: models.py:646 +#: models.py:663 msgid "Description" msgstr "Описание" -#: models.py:647 +#: models.py:664 msgid "Tags" msgstr "Метки" -#: models.py:648 +#: models.py:665 msgid "Comments" msgstr "Комментарии" @@ -638,8 +640,8 @@ msgstr "Документы в хранилище: %d." #: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" -" bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " +"bytes" msgstr "" "Использовано:%(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d bytes" @@ -822,14 +824,13 @@ msgid "" "Page count update complete. Documents processed: %(total)d, documents with " "changed page count: %(change)d" msgstr "" -"Страницы посчитаны. Всего обработано %(total)d документов, из них количество" -" страниц изменилось у %(change)d" +"Страницы посчитаны. Всего обработано %(total)d документов, из них количество " +"страниц изменилось у %(change)d" #: views.py:632 #, python-format msgid "" -"Are you sure you wish to update the page count for the office documents " -"(%d)?" +"Are you sure you wish to update the page count for the office documents (%d)?" msgstr "" "Вы действительно хотите пересчитать количество страниц для офисных " "документов (%d)?" @@ -857,8 +858,7 @@ msgstr "преобразование документа" #: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: " -"%s?" +"Are you sure you wish to clear all the page transformations for document: %s?" msgstr "" "Вы действительно хотите удалить все преобразования странице документа: %s?" @@ -968,7 +968,8 @@ msgstr "Ошибка редактирования документа введи #: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" -msgstr "редактирование файла \"%(filename)s из типа документа \"%(document_type)s\"" +msgstr "" +"редактирование файла \"%(filename)s из типа документа \"%(document_type)s\"" #: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" @@ -1079,8 +1080,8 @@ msgstr "Далее" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per" -" user." +"Maximum number of recent (created, edited, viewed) documents to remember per " +"user." msgstr "" "Максимальное количество последних (созданных, измененных, просмотренных) " "документов, запоминаемых для каждого пользователя." @@ -1099,8 +1100,7 @@ msgstr "Максимальный процент увеличения стран msgid "" "Minimum amount in percent (%) to allow user to zoom out a document page " "interactively." -msgstr "" -"Процент уменьшения масштаба страницы документа в интерактивном режиме." +msgstr "Процент уменьшения масштаба страницы документа в интерактивном режиме." #: conf/settings.py:42 msgid "Amount in degrees to rotate a document page per user interaction." @@ -1135,5 +1135,3 @@ msgid "" msgstr "" "Здесь вы найдете последние %(recent_count)s документов созданные или " "отредактированные вами." - - diff --git a/apps/dynamic_search/locale/en/LC_MESSAGES/django.po b/apps/dynamic_search/locale/en/LC_MESSAGES/django.po index 376f359baf..c3fd56bad3 100644 --- a/apps/dynamic_search/locale/en/LC_MESSAGES/django.po +++ b/apps/dynamic_search/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: 2012-02-02 14:17-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" diff --git a/apps/dynamic_search/locale/es/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/es/LC_MESSAGES/django.mo index d881ae086a31978942268523d48d3aa353c96c8d..79851448858a8a9ac98183ac30bcad93d33f186f 100644 GIT binary patch delta 21 ccmeAb>=oRQ&%$A7q+n=jWn{3qoJEWU06)+LH2?qr delta 21 ccmeAb>=oRQ&%$9~q+n=bWoW*+oJEWU06*OYIRF3v diff --git a/apps/dynamic_search/locale/es/LC_MESSAGES/django.po b/apps/dynamic_search/locale/es/LC_MESSAGES/django.po index 8684a44011..d4b55be7e2 100644 --- a/apps/dynamic_search/locale/es/LC_MESSAGES/django.po +++ b/apps/dynamic_search/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-04 17:06+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/it/LC_MESSAGES/django.mo index 9e527654a7f93a6cc12fa76f18a4ce9c9a138b97..3de067b8dc0eee803dc4acaba633e9614bd425b2 100644 GIT binary patch delta 21 ccmbO)FkfIpJ`0DTk%FPAm65^ba+Vd$07IPx=l}o! delta 21 ccmbO)FkfIpJ`0C|k%FO#m7)3Oa+Vd$07I$;>;M1& diff --git a/apps/dynamic_search/locale/it/LC_MESSAGES/django.po b/apps/dynamic_search/locale/it/LC_MESSAGES/django.po index 0f6ede5321..9d354393b5 100644 --- a/apps/dynamic_search/locale/it/LC_MESSAGES/django.po +++ b/apps/dynamic_search/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-12-09 15:32+0000\n" "Last-Translator: Pierpaolo Baldan \n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/dynamic_search/locale/pt/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/pt/LC_MESSAGES/django.mo index ef93575b86874ef102d4eadc19df50b14238c051..8207135d9960f09794808056a450f9e163d1105f 100644 GIT binary patch delta 21 ccmca6a7|!CJ`0DTk%FPAm65^ba+dqd08FC>jQ{`u delta 21 ccmca6a7|!CJ`0C|k%FO#m7)3Oa+dqd08Fq3kpKVy diff --git a/apps/dynamic_search/locale/pt/LC_MESSAGES/django.po b/apps/dynamic_search/locale/pt/LC_MESSAGES/django.po index cd10f88f38..9129c591d2 100644 --- a/apps/dynamic_search/locale/pt/LC_MESSAGES/django.po +++ b/apps/dynamic_search/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: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-03 02:32+0000\n" "Last-Translator: emersonsoares \n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" diff --git a/apps/dynamic_search/locale/ru/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/ru/LC_MESSAGES/django.mo index a8b96f88e7876582b22418cafb7b7b5eec223a81..c15ebe1ad1d0a5932e701b61c5b941856bfdc3d1 100644 GIT binary patch delta 21 ccmZ20vQ}h6J`0DTk%FPAm65^ba+YnZ07iob8~^|S delta 21 ccmZ20vQ}h6J`0C|k%FO#m7)3Oa+YnZ07j4oAOHXW diff --git a/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po b/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po index 2fabd8f0dd..4dacc05b45 100644 --- a/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po +++ b/apps/dynamic_search/locale/ru/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-03 22:40+0000\n" "Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/feedback/locale/en/LC_MESSAGES/django.po b/apps/feedback/locale/en/LC_MESSAGES/django.po index 0321894c73..c06fa17bd4 100644 --- a/apps/feedback/locale/en/LC_MESSAGES/django.po +++ b/apps/feedback/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: 2012-02-02 14:18-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" diff --git a/apps/feedback/locale/es/LC_MESSAGES/django.mo b/apps/feedback/locale/es/LC_MESSAGES/django.mo index 1dad760209edc084a46d2fe62dda6c8d4463fd41..b4c24481899f3d4a595b3cdef27471562a82794d 100644 GIT binary patch delta 225 zcmXZUzY76z00r=;a2zY{OjoQ|ci*xolT(!ZiVUV3jx4AAm}O8#b!GKOoLkt5&1Cgg zSVZ1n`n=bx_f;Os_OLvKfNKP>0IVe-MQ?wfbkF{xIl7Ah33{X}dZrs%jRSdlr+xaO zL)wsm3JqwFzUhLtdD5Ym1k%VbWRn0l2&&SOUke4{yxeMb_43rQ=i`a1TlU;3YQivu hZV25Jnpr3c!>dK_$-3>17WRm5ovFor8g4K9Da9q?Lj6ULeg4q#pw5 zMj-tbNOu6~d`<=i6(IcsNQVPySuO^KG$36Hq+NmZ9UvVFq?Lf0OM!F+kPZUU@3x=C@Cqh($`PVEXgQM(o4?I)i25~PAtmIFVfFV ztW3<)&nzx3O)Z}Mk5z`lz(~Q+#LCcOvJ%_HN$gQPK8bnhrHSdORtl-bnb%j CxiO^x diff --git a/apps/feedback/locale/es/LC_MESSAGES/django.po b/apps/feedback/locale/es/LC_MESSAGES/django.po index 9325ac3438..bac7b96e9a 100644 --- a/apps/feedback/locale/es/LC_MESSAGES/django.po +++ b/apps/feedback/locale/es/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:28+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:9 @@ -27,8 +28,8 @@ msgid "" "What features of Mayan EDMS attracted you to start using it or consider " "using it?" msgstr "" -"¿Qué características de Mayan EDMS le atrajo a empezar a usarlo o considerar" -" usarlo?" +"¿Qué características de Mayan EDMS le atrajo a empezar a usarlo o considerar " +"usarlo?" #: forms.py:24 msgid "What features would you like to see implemented in Mayan EDMS?" @@ -64,8 +65,8 @@ msgstr "¿Esta actualmente o planifica proveer apoyo pagado para Mayan EDMS?" #: forms.py:55 msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" msgstr "" -"¿Estaría usted interesado en una solución pagada alojada en la nube de Mayan" -" EDMS?" +"¿Estaría usted interesado en una solución pagada alojada en la nube de Mayan " +"EDMS?" #: forms.py:60 msgid "" @@ -119,5 +120,3 @@ msgstr "Error remitiendo el formulario; %s." #: views.py:28 msgid "feedback form" msgstr "formulario de comentarios" - - diff --git a/apps/feedback/locale/it/LC_MESSAGES/django.mo b/apps/feedback/locale/it/LC_MESSAGES/django.mo index a84cfa37468edc5fa96767e7630fafb949777025..e458604c200c031ce99e5413e9225cafaeeab391 100644 GIT binary patch delta 72 zcmbQh@{)Oi3gh~Ts-7xb0sbMn&PAz-C7Jnox-N+&sa6U`28Kqu21dGuMhb?eRz?OB bcOK>ONz6+xO-u*MW|mB@WsIKulu;W1FkKe- delta 85 zcmaFKJb`6`3gfkjs-Ef@B_#z``ugdaB^jkjddc~@`bGK0iA9\n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:9 @@ -101,5 +102,3 @@ msgstr "" #: views.py:28 msgid "feedback form" msgstr "" - - diff --git a/apps/feedback/locale/pt/LC_MESSAGES/django.mo b/apps/feedback/locale/pt/LC_MESSAGES/django.mo index 83a3dfda3af6f2d1e67de126de0126b12807d1db..675ae005c70a944d18ba6d5abb4fd7f186e53408 100644 GIT binary patch delta 72 zcmbQt@`ibW3gf1Us-7xb0sbMn&PAz-C7Jnox-N+&sa6U`28Kqu21dGuMhb?eRz?OB bcb?$!Nz6+xO-u*M7L-hGV2qypf>9d)GjJCX delta 86 zcmaFEJeg&J3ggX*s-Ef@B_#z``ugdaB^jkjddc~@`bGK0iA9\n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:9 @@ -101,5 +102,3 @@ msgstr "" #: views.py:28 msgid "feedback form" msgstr "" - - diff --git a/apps/feedback/locale/ru/LC_MESSAGES/django.mo b/apps/feedback/locale/ru/LC_MESSAGES/django.mo index 72be997423a6aec7613a6f803691788f5d711adc..70c16f79685167da158ae837b41d45e7d59068a1 100644 GIT binary patch delta 73 zcmcb`vYBOq3e!)YZ_;>4oN{389_#LC1x{mkOx s($wOKc`_UZMhb=|R)!W6Cmo%f!WhNllbDxYnwXwyrBGBlc`sub05?1ys{jB1 diff --git a/apps/feedback/locale/ru/LC_MESSAGES/django.po b/apps/feedback/locale/ru/LC_MESSAGES/django.po index 29e1f02967..e8689b0071 100644 --- a/apps/feedback/locale/ru/LC_MESSAGES/django.po +++ b/apps/feedback/locale/ru/LC_MESSAGES/django.po @@ -1,21 +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: msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:18-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:21+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:9 msgid "Feedback" @@ -101,5 +103,3 @@ msgstr "" #: views.py:28 msgid "feedback form" msgstr "" - - diff --git a/apps/folders/locale/en/LC_MESSAGES/django.po b/apps/folders/locale/en/LC_MESSAGES/django.po index 9915a91111..a152e7c2bf 100644 --- a/apps/folders/locale/en/LC_MESSAGES/django.po +++ b/apps/folders/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: 2012-02-02 14:17-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" diff --git a/apps/folders/locale/es/LC_MESSAGES/django.mo b/apps/folders/locale/es/LC_MESSAGES/django.mo index 5f0a7d43ab026bd7836abd166a737f72b56b4f2a..93a010e497355d9f036242cfac871b588c69f4af 100644 GIT binary patch delta 387 zcmXZWu}cDB7{~EP!Sw7%ii8T`3>*r&xO?debdn+=gd7A1ryDMbz@Tg^q_L$%s-dAJ z5S)T@3)g6h`XkyL!atz;zMRvC=Xu`ud43;O-+HOXy00;j{glYMh{V$(7H(hztJuV6 z+(MZZsep&uc!eb#VgY|}1+%8eGCHX11N1P!ReZ!v9GTLU5&_0EmT0WaMT^Rqr9Q%W zyu=y2#YMbBGRpuB43Ug7!W_P%e*cXNIL0LYq5hxDME7!;o#=o^LockLPFzDB;AHAG z>IDx|pTe8?BvDA$4(s;rS>Sh$PuupM-wBF&<+#drllKyLdrN(pRlnW3@LP<7 N^WMGD41bN!#6NdWGpPUo delta 403 zcmXZXJxjw-6vpvWp_*#6Xcb>5q=Hyn5-Zh0>n7+TI4BgfOO%jy=!;E*h)8Ea7xMue z6m%4dn>aYQ2tpPI-K4wVC-8r1hs%$1xc8jr-Wwmr<6flw6A{_eM3#gzEMnj;7SY24 ze8()NM?|);gll+*1^mVZoYqC=a2;o{*sqUqmHHCr@fA(%>e7}10TQDkGcG;WR?(P_=RMYE++98)qOoKGJy#k!bMc?O;r0f;\n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:18 @@ -211,8 +212,8 @@ msgstr "" #: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder" -" \"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder " +"\"%(folder)s\"?" msgstr "" "¿Está seguro que desea eliminar los documentos: %(documents)s de la carpeta " "\"%(folder)s\"?" @@ -237,5 +238,3 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Agregar documento a una carpeta" - - diff --git a/apps/folders/locale/it/LC_MESSAGES/django.mo b/apps/folders/locale/it/LC_MESSAGES/django.mo index e6f9907b6ffcaf05145a06e205e77b6d0fbf03af..4b5095132dfdfe1ff6f7e87498d7c68a1723030e 100644 GIT binary patch delta 387 zcmXZWF-yZx6o%nbq0-c7QM6(a5=5K~O)eE7(n%2qL5B*8pkyee2vsCqEeHi-SMF!AUv@4ubC`cY65lIh^}FJ6-3ol4?DqL^d-b3nKDkiMTkI71_hk z*u^6G6Spuw#te^f4R3J?-%;QB!+CV=xxq@P{N8J3U~fl_S~IFK OuE)KOb=V(TgY-W`z%-oz delta 401 zcmXZWy-Pw-9LDjVfpIlWj7kW@OGGWv$qIxUK`qwMSVJ}4Qq)1M`!YnsZ7FDr?$FrO z5Htu5P6Z8-YfDROe?e1A(D&k*K0N0vVSK, 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:18 @@ -212,8 +213,8 @@ msgstr "" #: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder" -" \"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder " +"\"%(folder)s\"?" msgstr "" "Sei sicuro di voler rimuovere i documenti: %(documents)s dalla cartella " "\"%(folder)s\"?" @@ -238,5 +239,3 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Aggiungi documento alla cartella" - - diff --git a/apps/folders/locale/pt/LC_MESSAGES/django.mo b/apps/folders/locale/pt/LC_MESSAGES/django.mo index a3a65a47c9cc5f770502db75ff3b6f6c8eeb5d24..1f45e305ebd3124048b67fd64015c24839eaa01a 100644 GIT binary patch delta 387 zcmXZYKT88a5QpJkgwx!4M)40u&=`o8r@50L24bO-LInkb7J_m`2qHw06U$Tgt%wL#)_wrX2o|yOU9@_3W_D+W{mH%O?rW*mLrSWqrGlicE#+~_k#=wycku@2 z@Dr<;?Uxqt5SK7U^ZpI9*!kCSr3vB!dRW0}JjQvva@A6W1s+L^k?0OcvpAUfi%Uo^ zZD23%p&4+1eRzTFtQNAH+BlB4Xzt(P5GH8h6At4mj^IaTkzpJpfhnYM6erO% z@X-uhK|V|CNxSFEnsK(bYToKuJ&cY{n%-I%)yw&y=m%ag@cba}m&!pgeonu*n_;tY R9yTbSM)9@1pM2Yw)-SNGGYkL# delta 402 zcmXBQzb^w}7{KwT;<(dBn<7pkb%_Xzz7El7A_ig*8xax9p=obuukNmcNOVH1y0e)Z zo$wDBY@HabCSo%AzA?P-=Y8HE&-3K%=6-YSoka63A+lkLOp1szz`%9f#uD!0Bjz!a z4Hd_h0UZN%%DC{IE-tk6YQZb z=p&ycC!On_Z)3U=$MvF8Wk0So4)aGrRfR$1g?, 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:18 @@ -211,8 +212,8 @@ msgstr "" #: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder" -" \"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder " +"\"%(folder)s\"?" msgstr "" "Tem certeza de que deseja remover os documentos: %(documents)s da pasta " "\"%(folder)s\"?" @@ -228,8 +229,8 @@ msgid "" "created by one user and the documents contained by them don't affect any " "other user folders or documents." msgstr "" -"Estas pastas também podem ser descritas como pastas de usuário. Elas são uma" -" maneira de permitir que os usuários individuais criem os seus próprios " +"Estas pastas também podem ser descritas como pastas de usuário. Elas são uma " +"maneira de permitir que os usuários individuais criem os seus próprios " "métodos de organização do documento. Pastas criadas por um usuário e os " "documentos contidos nelas não afetam todas as pastas de outros usuários ou " "documentos." @@ -237,5 +238,3 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Adicionar documento à uma pasta" - - diff --git a/apps/folders/locale/ru/LC_MESSAGES/django.mo b/apps/folders/locale/ru/LC_MESSAGES/django.mo index 4e552decf85d4f2b299eafd9f82d139cf95ea9b9..8533b1b4e90ebe68d09e7fd8ffb8af032dbf9a34 100644 GIT binary patch delta 387 zcmXZXJ4*vW6o%n1qL9R_8bQ3F23;{k7k3vgm`YKif}%wVMJ$#Of=z@qDI`T|Z7jC4 z5G+LyVLMAfD=jRCO zPGV+28pT~CMFpHgzZ2ggLk~=Y_<|;W;utou-H4Ht_={F>95=9C?=-n84YR0q5(1nd zzQbvJ#daeN}GXI(pZ YkG>`LymG1Pl{ogR!FB8;Y{m-FKYK+tR{#J2 delta 403 zcmXZXze@sP7{KvIAvo)@Y$?m)r~{*<>q3x@h9)N)iiQdru9DM1&+f+{4lXUVG&tE3 z_yGUjmwT|B@W%-}cfpca>=Tt`Hzaglive-k2E zOihX`;4UVyhLp$^rm;PYACV(3TvPagI{x4+CKH22vdCZL80WBr{dpIOoX9kf&amJC zmxz0~h@aSBM5TLw&??U0R`)XcHIgm`LCrD@ryP{RleJT~VtB4^du7)%Dt6tj8fD)P ni+-!2q?Gjy&CFV6u63*QTIaDNwP07B&~}QJ=7rto*qQPVdci+B diff --git a/apps/folders/locale/ru/LC_MESSAGES/django.po b/apps/folders/locale/ru/LC_MESSAGES/django.po index a03ed62a57..1e4aaf4bbf 100644 --- a/apps/folders/locale/ru/LC_MESSAGES/django.po +++ b/apps/folders/locale/ru/LC_MESSAGES/django.po @@ -1,21 +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: msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:18 msgid "folder list" @@ -204,14 +206,14 @@ msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " "\"%(folder)s\"?" msgstr "" -"Вы действительно хотите удалить документ: %(document)s из папки \"%(folder)s" -" \"?" +"Вы действительно хотите удалить документ: %(document)s из папки \"%(folder)s " +"\"?" #: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder" -" \"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder " +"\"%(folder)s\"?" msgstr "" "Вы действительно хотите удалить документы: %(documents)s из папки " "\"%(folder)s\"?" @@ -234,5 +236,3 @@ msgstr "" #: templatetags/folder_tags.py:17 msgid "Add document to a folder" msgstr "Добавить документ в папку" - - diff --git a/apps/history/locale/en/LC_MESSAGES/django.po b/apps/history/locale/en/LC_MESSAGES/django.po index 5d192a1598..f2c4e37eca 100644 --- a/apps/history/locale/en/LC_MESSAGES/django.po +++ b/apps/history/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: 2012-02-02 14:17-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" diff --git a/apps/history/locale/es/LC_MESSAGES/django.mo b/apps/history/locale/es/LC_MESSAGES/django.mo index 69f4e6c347f25e8763faea4563f4f854a03834d6..7cd843151ce3bef7f346893be2f29b7c1347aeeb 100644 GIT binary patch delta 241 zcmZ3_-N8NKNd0a`28QiS3=FIc3=G9A3=G0Rx)Mn90qI^K%?YIE0BJTLy$njP1=2h~ z{uU^G5J(FG`R9N%H;{e+rQZN)kp3S)S_DWl0WFaQ(&9iGq~4U3L5)Ei$Z!V=fGmgy z(n3Hw4a%9bJ!3XtXj z@^3@w7eHDN$o~qYxq&o0&@d1!45UH&<$<&akk$m!vOwAnNQ2bJurjDIhyxjUKmm{i zZ9rNGNcTed3xG5`kiUF$CSxmU!44oIf}<8F)zI|F+J5vA+>n3JBuSD0JwQB A00000 diff --git a/apps/history/locale/es/LC_MESSAGES/django.po b/apps/history/locale/es/LC_MESSAGES/django.po index 965b386e56..b1c3b0d03e 100644 --- a/apps/history/locale/es/LC_MESSAGES/django.po +++ b/apps/history/locale/es/LC_MESSAGES/django.po @@ -1,20 +1,21 @@ # 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-02 14:17-0400\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: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:10 models.py:71 @@ -102,5 +103,3 @@ msgstr "Detalles del evento" #, python-format msgid "details for: %s" msgstr "Detalles para: %s" - - diff --git a/apps/history/locale/it/LC_MESSAGES/django.mo b/apps/history/locale/it/LC_MESSAGES/django.mo index 34020bf60cd3b5b2165c05fdb157688369a0b8b0..66749bbcf542a2c2a6dbcde6d99161faefb4dfa8 100644 GIT binary patch delta 241 zcmeyzb)9R%k^1$F3=G?u7#LU>7#PxlgaDAv0n*$+x)w-t0O?L3%?_j|0ckcMJqt+l z0_lZ78i*Ly0|}76EkK$JNFRmL7l1TK|7{>G2&A6?X+CZORzGifiD34EKUV3R_I#4>ZWb$w3=*`J2(u@FkTP0fn delta 255 zcmXZVI|{-;5C-7M!&gMmUPT-2Tm?Z);|25r7Q!kaNs&bID6A~(Mc6BN0Kq~m1qDx_ zg`Ks%o%pW^!+bEzKXW%e#^$`dDMSaANGGB-S`iAEhg+D1JD7n-n1&}|JH0G@Uq}n~d3R>?G6H zEbv$uL_BnZka>K;edb0{VnyPmmPK3B^{(0JiK2E9Pi<@rxo;=jw#?eTuUC~X+`=s! diff --git a/apps/history/locale/it/LC_MESSAGES/django.po b/apps/history/locale/it/LC_MESSAGES/django.po index 8a4b7a3f6a..823f6912a8 100644 --- a/apps/history/locale/it/LC_MESSAGES/django.po +++ b/apps/history/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:10 models.py:71 @@ -103,5 +104,3 @@ msgstr "Dettaglio evento" #, python-format msgid "details for: %s" msgstr "dettaglio per:%s" - - diff --git a/apps/history/locale/pt/LC_MESSAGES/django.mo b/apps/history/locale/pt/LC_MESSAGES/django.mo index a3d5e1b9e2fae56457324f750d635d6470253aa8..b5bb617450b35127fb2b98108023272f5bb67061 100644 GIT binary patch delta 241 zcmbQh{gP|Kk@`)H3=G?u7#LU>7#OmEgb7#Jo32_Yao4M_6=>6Jj56G-m>(riHb5RhgC(kFp5 zH;_ILq`83fZ6GZOq@O{>e?Y}qfQmu-`GK?ukd_3}vOro7NQ2b-urjEDEsO&S0QE2w z0%?$jG9V4IumMPO0O|J4nT*Yh>KP>^1y=g{>6s-NrAd0p`MLT<`NfGvnfXQfxrvpD zdHR{f#igmmlix7OOg3O, 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:10 models.py:71 @@ -103,5 +104,3 @@ msgstr "Detalhes do evento" #, python-format msgid "details for: %s" msgstr "detalhes para: %s" - - diff --git a/apps/history/locale/ru/LC_MESSAGES/django.mo b/apps/history/locale/ru/LC_MESSAGES/django.mo index 2a8e1de8960701dee237cd020b5140ff5c721ac8..44546ea13979282da2a848925b55a6582d596593 100644 GIT binary patch delta 241 zcmcb_vzlkZk@}yE3=G?u7#KJh7#KFPFfgbB>0Llt6i7b+(tJSr8<6G!(yXiu3|v53 z2uOC7=KskbVWE z6@m0eAPurm7$^v`P+@Z>V>6=)SAc(ru5(dpVo7Fxo~}z`Nvf5Ck%6I+u7Q!Rp^<{2 isg;qzWOL@DJU)qe>7|M3K\n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:10 models.py:71 msgid "history" @@ -102,5 +104,3 @@ msgstr "Подробности события" #, python-format msgid "details for: %s" msgstr "подробности: %s" - - diff --git a/apps/linking/locale/en/LC_MESSAGES/django.po b/apps/linking/locale/en/LC_MESSAGES/django.po index 49009ca01f..e9e180dde8 100644 --- a/apps/linking/locale/en/LC_MESSAGES/django.po +++ b/apps/linking/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: 2012-02-02 14:17-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" diff --git a/apps/linking/locale/es/LC_MESSAGES/django.mo b/apps/linking/locale/es/LC_MESSAGES/django.mo index 19618d1dea6293ce4c7c6e5444f5a8efd8eb5b34..b4ce8f22c054a5a447d38a96f2203be6e0fb34a1 100644 GIT binary patch delta 637 zcmXZZODIHP6u|Lg@|Zz}8N&5w#js3?iDE&5l@}SDAr&M z=Wr5FFp352K*MJ{iEYFy*o(VPe1$E4Bp2q=9Bd_EV54cz!hlytzc`$`V%;72SH(4T`ER1H6E}TZ{ zWECsXL~U#fyKxt_;Y-x~Yh-v*M4ikhmZQtC8}lGTlQGo&DC)V3sOK(QEOc}m&WmHz z(VaPQ9(#x%u^PXTY04jJBOa35(T8CSqULR)=53=+&$8?yCt#MrE<|j2kR2kHm-~AuFlMYod(Jf zBIvLzL3BvOK)MJEMb}PAm+Ddp?I8%%Kfq3r-^VTte17jY@BQZe-aJZdCbk|l`M-~d zq}xOSB4QpF8O6&ui3@lYKj2L~z&=d1*Ueyr_z9lJ^+x;|PZ95-jYm7`_4BCp?@;T0 zbcipzAU;EF>;?AYI%>n)sQKTJ;mKdro3)%2X~qkvjhV>M z#EEOd0w8!z6Yj_zY4uHiZ2J#57=FPW-DP#ZC^7ZaGo8PvQoYTj$q ziByqc$S2eWYuJQ0{;<#+@1hp$qZa%_E+y@!MWQ%}`p?p+ADG7hT*ek$t8NB<25-%I z-eS@)vN>8abX3CFg)T(J, 2011, 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-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:29+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:17 @@ -149,9 +150,9 @@ msgid "" "The document metadata is available as variables `metadata` and document " "properties under the variable `document`." msgstr "" -"Esta expresión sera evaluada con respecto al documento seleccionado actual." -" Los metadatos del documento están disponible como variables `metadata` y " -"las propiedades del documento en la variable `document`." +"Esta expresión sera evaluada con respecto al documento seleccionado actual. " +"Los metadatos del documento están disponible como variables `metadata` y las " +"propiedades del documento en la variable `document`." #: models.py:14 models.py:33 views.py:136 views.py:232 msgid "enabled" @@ -330,8 +331,7 @@ msgstr "" #: conf/settings.py:11 msgid "Show smart link that don't return any documents." msgstr "" -"Mostrar enlace inteligente que no devuelven ningun documentos como " -"resultado." +"Mostrar enlace inteligente que no devuelven ningun documentos como resultado." #: templates/smart_links_help.html:3 msgid "What are smart links?" @@ -351,5 +351,3 @@ msgstr "" "documentos que se relacionan de alguna manera al documento que se muestra y " "permite a los usuarios la capacidad de navegar entre los documentos " "vinculados con mucha facilidad." - - diff --git a/apps/linking/locale/it/LC_MESSAGES/django.mo b/apps/linking/locale/it/LC_MESSAGES/django.mo index 01c4149cc85733cd974414851cf99bbf419de7e4..0fd371e57b18e2ed0da85b0c2f2aeae814ff799e 100644 GIT binary patch delta 653 zcmXZZJ1j$C6u|N0O-Wkn(Rx-0^|-VbAsr;>NEkc@BI(dbmo}tL5J`8Fq+Lw4Sh|oj z5{WR8h{0rG5s3(?%^(Khf4Iqazu$Mhb06P1H$Qqgdc0DYJSq?wvvY~at3zZ4+p9$a z7{dX~VjJFLJ$_*$I%-7vun*gD33Y!97cq^)n78sCr$`g=B$nc;Q<74_BFx6$2XUM@ zi<9_f*X_^GF8Rt>+>)4CiR{qf1KS3?@0xR(vTk$SwZG0d@ zewg$|H+|HWcc4}_g_>W$5{w~35=;i}p&sZ0DN=4xf7J`p4EaWFxs(1EVIyk66Rj-t z10G8g^}!%&Wy{ErO(yM38e1@f`oi6CdZ%l23L-9x~Y6L^^aKK~w{HEbE j4ZrE}j|5C#>ePN!H64nsB|>YYBk|OZV>$QiD69Mhb*xXB delta 667 zcmXZZ%PT}t9Ki9PXJe!p#``%ULfjeD=q`lvNTeu5HkYQEF^$nY79vy1MmCz7D24w( zStzshDA_1kS&5Z}EUavN52x-upY!{jd+#~F-@W#I_|BJdQ_ndf0}gHxag>To;{=+R z!5)0XCX_OfN^oN>`mhUUu^G2@{uJklv)GSiuK)FMtRoI#A?~^)B}Gj3N&IbygT#+G zg3j`P=g>o(!4AAbb+9k3yF!FB$_$=Rkc9?uPL)U>dhs6pxQCuy80&FUuODJ3@tIzK(D@fsg}!4keqtm3q;#T|elnFd zR1XfJYWXCp%2xII78Vd^kV}pky73a#f!>iKo&Ueemt#DF4ac9!w5r!)j(VG?*X`{$y}tB;<0if0T(nPFYk{N{@SE<7E2q8q7d!n@rT_o{ diff --git a/apps/linking/locale/it/LC_MESSAGES/django.po b/apps/linking/locale/it/LC_MESSAGES/django.po index 903258ac6f..5951339586 100644 --- a/apps/linking/locale/it/LC_MESSAGES/django.po +++ b/apps/linking/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:17 @@ -322,8 +323,8 @@ msgstr "" #, python-format msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgstr "" -"Sei sicuro di voler cancellare le condizioni per il link intelligente : " -"\"%s\"?" +"Sei sicuro di voler cancellare le condizioni per il link intelligente : \"%s" +"\"?" #: conf/settings.py:11 msgid "Show smart link that don't return any documents." @@ -347,5 +348,3 @@ msgstr "" "query sono un elenco di documenti che riguardano in qualche modo al " "documento e consentire la visualizzazione agli utenti la possibilità di " "saltare da e per i documenti collegati molto facilmente." - - diff --git a/apps/linking/locale/pt/LC_MESSAGES/django.mo b/apps/linking/locale/pt/LC_MESSAGES/django.mo index ea1c804a3b76c04fe017ee69737f5278727431b5..6f66ae973560eeb65553e0af3f21c8a0b901ec09 100644 GIT binary patch delta 475 zcmXZYKS%;$7{~F)^G}}Mbwz}sS!Y2Ak)+XLLrV=oAZ>v-IE1xCgv~b=vXK^2W zJi{5hHTEz^{f$YCIwC1_a0xS*!A(;)uupxC9c;M6c|WcM!ujHk4hMM1Ov&O1E?^c* zIF4JW0qf>_VEU(+pnr)PH!`}J&leJT-}>5CXfc;C vY}3kwmJB-))g~vxlc5Q9v~VOEo;kT_csg->vBni6lPnlXO0uPQU%BQVbumh_ diff --git a/apps/linking/locale/pt/LC_MESSAGES/django.po b/apps/linking/locale/pt/LC_MESSAGES/django.po index e9104b3edc..69519ca3b9 100644 --- a/apps/linking/locale/pt/LC_MESSAGES/django.po +++ b/apps/linking/locale/pt/LC_MESSAGES/django.po @@ -1,22 +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: # , 2011. # Roberto Rosario , 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:17 @@ -338,5 +339,3 @@ msgid "" "some manner to the document being displayed and allow users the ability to " "jump to and from linked documents very easily." msgstr "" - - diff --git a/apps/linking/locale/ru/LC_MESSAGES/django.mo b/apps/linking/locale/ru/LC_MESSAGES/django.mo index d9072fc1ba8d1530f7059dc0794473d49df14a22..f19463bcf2fb566b7d09c0fd784ae7c79321c9f6 100644 GIT binary patch delta 653 zcmXZYy=zlZ7{~EnL#Pmfi5lZeqfMzV(DvfZZQ@Jn5Zh233emKK&_YN{42nc3y-Nt( zp$J`^B8Y#1pdtwwYL^Z|wk}FLWN2L+ly+}B>GzNe=bq1f&g*lYgWP7WwG{A92c-KE zX+aLdd4~hSxsmQI)hv07LM(9al!J1jEl-FLo vu37o=S|yuw?382Kj+JtfsZ7?fo8Kbc@Lai8b<0(zSKVeKy4d+0tw;U?#p+Z$ delta 669 zcmXZYPe@cz6vy#jGKh%yM#mJ>bRnZPT@6(?2u^{YO)nRV_7Q4VsEau?uJLG47!0$N`%C3p5@1g=SxXB<|7+ zH0MrZExPy;w=>?tSLBiUjfHrNHs;qzMc9oD4e>E~^Voo^_!{@oR-3+05E)6CIA2c diff --git a/apps/linking/locale/ru/LC_MESSAGES/django.po b/apps/linking/locale/ru/LC_MESSAGES/django.po index 9ffe9932ed..859baea2aa 100644 --- a/apps/linking/locale/ru/LC_MESSAGES/django.po +++ b/apps/linking/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # 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: 2012-02-02 14:17-0400\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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:17 msgid "smart links actions" @@ -338,10 +340,8 @@ msgid "" "some manner to the document being displayed and allow users the ability to " "jump to and from linked documents very easily." msgstr "" -"Отношение, в оригинале smart-link, представляет собой набор условий, которые" -" используются для поиска документов отвечающих им . Результатом такого " +"Отношение, в оригинале smart-link, представляет собой набор условий, которые " +"используются для поиска документов отвечающих им . Результатом такого " "поискового запроса является список документов, относящихся к текущему, и " "позволяющих быстро переходить от одного к другому. Условия строятся исходя " "из содержимого документа и метаданных." - - diff --git a/apps/main/locale/en/LC_MESSAGES/django.po b/apps/main/locale/en/LC_MESSAGES/django.po index 7cfcc72746..35a5b1a1dc 100644 --- a/apps/main/locale/en/LC_MESSAGES/django.po +++ b/apps/main/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: 2012-02-02 14:17-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" diff --git a/apps/main/locale/es/LC_MESSAGES/django.mo b/apps/main/locale/es/LC_MESSAGES/django.mo index 4897cb44a060811c92d833def3f02fa7a6348ed9..ea9b441199ade761fe7ad68c2f19bcb46f42ce75 100644 GIT binary patch delta 21 dcmZ1=x\n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/main/locale/it/LC_MESSAGES/django.mo b/apps/main/locale/it/LC_MESSAGES/django.mo index dac1ab2db9d9dfdf4b6f901d6b54ab305fa7ef44..00bd8125a4a40e0627da915a850b9cad9dfae1dd 100644 GIT binary patch delta 21 ccmX>sd{}rxJ1d8wk%FPAm65^bepV9}07|+A^#A|> delta 21 ccmX>sd{}rxJ1d8Qk%FO#m7)3OepV9}07}ON`2YX_ diff --git a/apps/main/locale/it/LC_MESSAGES/django.po b/apps/main/locale/it/LC_MESSAGES/django.po index 1072c590d1..9efd77430f 100644 --- a/apps/main/locale/it/LC_MESSAGES/django.po +++ b/apps/main/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-01-02 04:46+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/main/locale/pt/LC_MESSAGES/django.mo b/apps/main/locale/pt/LC_MESSAGES/django.mo index 06faf53e0cd35e85f4bc0f07e586538b7144d084..8b0b67f0e3ebacd081c959904ce2f3accb66f32e 100644 GIT binary patch delta 21 ccmaDO{6=^~J1d8wk%FPAm65^be%4qP08w-XZ~y=R delta 21 ccmaDO{6=^~J1d8Qk%FO#m7)3Oe%4qP08xPkbN~PV diff --git a/apps/main/locale/pt/LC_MESSAGES/django.po b/apps/main/locale/pt/LC_MESSAGES/django.po index 37d5417566..afe2cb2f60 100644 --- a/apps/main/locale/pt/LC_MESSAGES/django.po +++ b/apps/main/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: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-01-02 04:46+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" diff --git a/apps/main/locale/ru/LC_MESSAGES/django.mo b/apps/main/locale/ru/LC_MESSAGES/django.mo index cdf481963155c85dd2d32298ce0ce0d7931b6ecc..ded377f1114042e50dad247352984414a5c5155c 100644 GIT binary patch delta 21 ccmeB`>Xq7Xnw7)QNWsw5%E(~zWmYS807$b2C;$Ke delta 21 ccmeB`>Xq7Xnw7)ANWsv=%FulCWmYS807$?FEC2ui diff --git a/apps/main/locale/ru/LC_MESSAGES/django.po b/apps/main/locale/ru/LC_MESSAGES/django.po index d56bcfdd89..a465e0d820 100644 --- a/apps/main/locale/ru/LC_MESSAGES/django.po +++ b/apps/main/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-01-17 10:58+0000\n" "Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/metadata/locale/en/LC_MESSAGES/django.po b/apps/metadata/locale/en/LC_MESSAGES/django.po index b4d32bfd59..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: 2012-02-02 14:17-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" @@ -33,7 +33,7 @@ msgstr "" msgid "remove metadata" msgstr "" -#: __init__.py:29 models.py:34 views.py:315 +#: __init__.py:29 models.py:34 views.py:316 msgid "metadata types" msgstr "" @@ -49,7 +49,7 @@ msgstr "" msgid "create new" msgstr "" -#: __init__.py:34 views.py:415 +#: __init__.py:34 views.py:416 msgid "metadata sets" msgstr "" @@ -57,7 +57,7 @@ msgstr "" msgid "default metadata" msgstr "" -#: classes.py:12 +#: classes.py:14 #, python-format msgid "'metadata' object has no attribute '%s'" msgstr "" @@ -90,7 +90,7 @@ msgstr "" msgid "Remove" msgstr "" -#: forms.py:86 +#: forms.py:86 views.py:541 views.py:559 msgid "Metadata sets" msgstr "" @@ -140,11 +140,11 @@ msgid "" "User.objects.all()].%s" msgstr "" -#: models.py:33 models.py:58 views.py:352 views.py:397 +#: 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:467 views.py:513 +#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514 msgid "metadata set" msgstr "" @@ -164,7 +164,7 @@ msgstr "" msgid "type" msgstr "" -#: models.py:76 views.py:303 +#: models.py:76 views.py:304 msgid "value" msgstr "" @@ -172,7 +172,7 @@ msgstr "" msgid "document metadata" msgstr "" -#: models.py:91 views.py:581 +#: models.py:91 views.py:599 msgid "document type" msgstr "" @@ -240,182 +240,186 @@ msgstr "" msgid "View metadata sets" msgstr "" -#: views.py:40 views.py:203 +#: views.py:41 views.py:204 msgid "The selected document doesn't have any metadata." msgstr "" -#: views.py:51 views.py:143 views.py:215 +#: views.py:52 views.py:144 views.py:216 msgid "Must provide at least one document." msgstr "" -#: views.py:86 views.py:250 +#: views.py:87 views.py:251 #, python-format msgid "Error deleting document indexes; %s" msgstr "" -#: views.py:98 +#: views.py:99 #, python-format msgid "Error editing metadata for document %(document)s; %(error)s." msgstr "" -#: views.py:101 +#: views.py:102 #, python-format msgid "Metadata for document %s edited successfully." msgstr "" -#: views.py:106 views.py:267 +#: views.py:107 views.py:268 #, python-format msgid "Error updating document indexes; %s" msgstr "" -#: views.py:108 views.py:269 +#: views.py:109 views.py:270 msgid "Document indexes updated successfully." msgstr "" -#: views.py:119 +#: views.py:120 #, python-format msgid "Edit metadata for document: %s" msgstr "" -#: views.py:121 +#: views.py:122 #, python-format msgid "Edit metadata for documents: %s" msgstr "" -#: views.py:160 +#: views.py:161 #, python-format msgid "" "Metadata type: %(metadata_type)s successfully added to document %(document)s." msgstr "" -#: views.py:163 +#: views.py:164 #, python-format msgid "" "Metadata type: %(metadata_type)s already present in document %(document)s." msgstr "" -#: views.py:187 +#: views.py:188 #, python-format msgid "Add metadata type to document: %s" msgstr "" -#: views.py:189 +#: views.py:190 #, python-format msgid "Add metadata type to documents: %s" msgstr "" -#: views.py:258 +#: views.py:259 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " "%(document)s." msgstr "" -#: views.py:261 +#: views.py:262 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." msgstr "" -#: views.py:280 +#: views.py:281 #, python-format msgid "Remove metadata types from document: %s" msgstr "" -#: views.py:282 +#: views.py:283 #, python-format msgid "Remove metadata types from documents: %s" msgstr "" -#: views.py:301 +#: views.py:302 #, python-format msgid "metadata for: %s" msgstr "" -#: views.py:319 +#: views.py:320 msgid "internal name" msgstr "" -#: views.py:340 +#: views.py:341 msgid "Metadata type edited successfully" msgstr "" -#: views.py:343 +#: views.py:344 #, python-format msgid "Error editing metadata type; %s" msgstr "" -#: views.py:349 +#: views.py:350 #, python-format msgid "edit metadata type: %s" msgstr "" -#: views.py:364 +#: views.py:365 msgid "Metadata type created successfully" msgstr "" -#: views.py:370 +#: views.py:371 msgid "create metadata type" msgstr "" -#: views.py:389 +#: views.py:390 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "" -#: views.py:391 +#: views.py:392 #, python-format msgid "Metadata type: %(metadata_type)s delete error: %(error)s" msgstr "" -#: views.py:402 +#: views.py:403 #, python-format msgid "Are you sure you wish to delete the metadata type: %s?" msgstr "" -#: views.py:419 +#: views.py:420 msgid "members" msgstr "" -#: views.py:463 -#, python-format -msgid "non members of metadata set: %s" -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:479 +#: views.py:480 msgid "Metadata set created successfully" msgstr "" -#: views.py:485 +#: views.py:486 msgid "create metadata set" msgstr "" -#: views.py:504 +#: views.py:505 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "" -#: views.py:507 +#: views.py:508 #, python-format msgid "Metadata set: %(metadata_set)s delete error: %(error)s" msgstr "" -#: views.py:518 +#: views.py:519 #, python-format msgid "Are you sure you wish to delete the metadata set: %s?" msgstr "" -#: views.py:576 +#: 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:577 +#: 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 e17b35335cdac74c08234c8e7de7f6be8ff864e4..1448638f9e1208cb44bbfc041287382e4d2e84a1 100644 GIT binary patch delta 2174 zcmXxlZA@EL9LMpq4N7q!4%X^~Nyp>ZD22KXD4QENtuP)Y!zZ>mF06s7P(q7_EU_j& zkR^KoHWCbKjLt-(&JY%t`OZ1xi^fcGnwS`~EO8?yi`kncYBYX-x7QQS{hV`e&-4FY zZuea7P5oM&^M)Z=%xD$7yh3an+w-}Q$%M>nX1s)&$STse`4eet^6tvk zy{MH|q1r{T3uD-V=dcHFqIRxrQ?~sGRx-YsqL70Ns9j$|&GbD~gNwKwf5%6$gk?8k z6!rTB%*D5HE548XnJ>9$XRhGgxQ5z#-DGpk7EI{}HC%KAVY~zTFb@ZjNtl|q^f0Eap$~7McG&G<|2a;xo#knO7SvX@qZ&k< zdN*EMNAx36YeFnfE9~P^hok7?`8P*~pD7Gc z_!kvy$C(AMvYEvo&Z8P$!U+C>P1x+q#zYJ?(G==vmarN>LG`zahw(4$z+PUF$8a7S z^#0$VptJKt5_N>HAzho($lA_m zMQn!#+=cr65wzbbEMt6=pr9a}Lq+Sms183v?Z5?Ok>(<*qu-q81yt;vL*mlZp?mszE8s(*%N;hkGyw4`42K;yTnl;?n-S4yOIC z^3;B6|EEq050RfBcR4q8AUX^NveT1Xb$I>Rsy%HLk2!Unht9y~)U{3RWP90oh^**b zPbQ@^uC4h!6!dX;AbrbKl2WKBSy}AZBkoKy`Ejzo&^j%p0J+sJWiJEJ=hTm5H(9aV z=G=SGQG4}>Qx?0OGJ92Fo~H6JSsSc3_y}1^Z?(eUK>CBca_b-^1sxwIJE}WSDNI(> z?;`Wnv_BqCVI!FUHofHg$wOqN2)U5V3EBTEHlR{)rP>|HFN`Lw6IRmlC1)n1iIx6M z-kjR8WO6bb2#m&(W7ES8Bk}RTR6Jo##o|+eacjn!2*eVJ>1ZN7<|%VG1$|ASaIi6b z+EZE>^fw0my3-mCHmA>dK1x619W3a!CPt^N(P-Gm0AG0vHx>`XCgTa;iKuTpJ9<2^ Ja(P>A?thWW-p&93 delta 2107 zcmXxlS!`5Q9LMp0%XFsG4PjcaEzn`mF2XH$rX9*msg$x*=>TnEY7v)~SV+~>rBxC` zxF*$TLS2%2(O!W-C(k?LZ@XA+B0v+r|H86=9@oCgR7Lm5?Ci1TR>z@Z7 zD9*GN^D~baQHogHikrmEoJn>RGss{Hud{rm0lMP%pIl=MFBE zm~|k#)ow9O%`nWN4cB9k`vdqbQyV7FT8ainulrlk!K1hxKg4caLT%0}kLhYeuJ0gn z&tAqP&fz9pL^XU1^Pp21$QSaq&481R@XtUKb z3Vy=20~0uadhrzY;{}Z4-$*iSL$o;16c&~SALjZoRC{xH5HDgMmh;od;sCbeJTei_ zmZ)eC+(s?MJ&a+1gHqRm>Ntx};XBxazoRy7j8?RC4)UsXAak-T>Vq_c&G-RofR|Bw z=Q=jhzx_!?Yg$2G_*hxYw;h$zG-^hNPy;=Q%G4}s*T08q@I3NompQ1zYpCZ-=~WpD zBdcc(sLj`fHS}-&RMg-IDg$H4d?e-nT zAm=Y2kJ_uK&3P76dSQ`@2JjPx@HY(LA6SNeVF~J*W}qE>IM)+w^0rgEUml~fix?pu z_b+Nev=}r{C{J+QMhq2C3&U1b3#+27uQiAgD#}wYq3LL(2MF!TQi77Z7F-+7P|-)B zCsz`Rc&@Hf#tKJP4YiH75ZZrTgjP#M`%qu#`$hY8zkl)!4iLjc+P~K4t6cT_b&>Sz zB)nsDQB$4xmMZq!Yt-Bj*w-G!>m_|);&#*cG*Vmfzj)scL~>Z;0oTdcY4 Ee_?mPA^-pY diff --git a/apps/metadata/locale/es/LC_MESSAGES/django.po b/apps/metadata/locale/es/LC_MESSAGES/django.po index 395f09a291..6134319ba7 100644 --- a/apps/metadata/locale/es/LC_MESSAGES/django.po +++ b/apps/metadata/locale/es/LC_MESSAGES/django.po @@ -1,21 +1,21 @@ # 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: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2011-09-30 05:09+0000\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" -"Language: es\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:21 __init__.py:23 @@ -34,7 +34,7 @@ msgstr "añadir metadatos" msgid "remove metadata" msgstr "eliminar los metadatos" -#: __init__.py:29 models.py:34 views.py:315 +#: __init__.py:29 models.py:34 views.py:316 msgid "metadata types" msgstr "tipos de metadatos" @@ -50,7 +50,7 @@ msgstr "borrar" msgid "create new" msgstr "crear nuevo" -#: __init__.py:34 views.py:415 +#: __init__.py:34 views.py:416 msgid "metadata sets" msgstr "conjuntos de metadatos" @@ -58,7 +58,7 @@ msgstr "conjuntos de metadatos" 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'" @@ -91,7 +91,7 @@ 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" @@ -140,14 +140,14 @@ 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:33 models.py:58 views.py:352 views.py:397 +#: models.py:33 models.py:58 views.py:353 views.py:398 msgid "metadata type" msgstr "tipos de metadatos" -#: models.py:48 models.py:49 models.py:57 views.py:467 views.py:513 +#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514 msgid "metadata set" msgstr "conjunto de metadatos" @@ -167,7 +167,7 @@ msgstr "documento" msgid "type" msgstr "tipo" -#: models.py:76 views.py:303 +#: models.py:76 views.py:304 msgid "value" msgstr "valor" @@ -175,7 +175,7 @@ msgstr "valor" msgid "document metadata" msgstr "metadatos de documento" -#: models.py:91 views.py:581 +#: models.py:91 views.py:599 msgid "document type" msgstr "tipo de documento" @@ -243,57 +243,58 @@ msgstr "Eliminar conjuntos de metadatos" msgid "View metadata sets" msgstr "Ver los conjuntos de metadatos" -#: views.py:40 views.py:203 +#: 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:51 views.py:143 views.py:215 +#: 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:86 views.py:250 +#: views.py:87 views.py:251 #, python-format msgid "Error deleting document indexes; %s" msgstr "Error eliminando indicies de documento; %s" -#: views.py:98 +#: 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:101 +#: views.py:102 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Metadatos para documento %s editados exitosamente." -#: views.py:106 views.py:267 +#: views.py:107 views.py:268 #, python-format msgid "Error updating document indexes; %s" msgstr "Error editando indices de documento; %s" -#: views.py:108 views.py:269 +#: views.py:109 views.py:270 msgid "Document indexes updated successfully." msgstr "Indices documento actualizados exitosamente." -#: views.py:119 +#: views.py:120 #, python-format msgid "Edit metadata for document: %s" msgstr "Editar metadatos para documento: %s" -#: views.py:121 +#: views.py:122 #, python-format msgid "Edit metadata for documents: %s" msgstr "Editar metadatos para documentos: %s" -#: views.py:160 +#: 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:163 +#: 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:187 +#: views.py:188 #, python-format msgid "Add metadata type to document: %s" msgstr "Agregar tipo de metadato al documento: %s" -#: views.py:189 +#: views.py:190 #, python-format msgid "Add metadata type to documents: %s" msgstr "Agregar tipo de metadato a los documentos: %s" -#: views.py:258 +#: 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:261 +#: 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:280 +#: views.py:281 #, python-format msgid "Remove metadata types from document: %s" msgstr "Eliminar tipos de metadatos del documento: %s" -#: views.py:282 +#: views.py:283 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Eliminar tipos de metadatos de los documentos: %s" -#: views.py:301 +#: views.py:302 #, python-format msgid "metadata for: %s" msgstr "metadatos para: %s" -#: views.py:319 +#: views.py:320 msgid "internal name" msgstr "nombre interno" -#: views.py:340 +#: views.py:341 msgid "Metadata type edited successfully" msgstr "Tipo de metadatos editado exitosamente." -#: views.py:343 +#: views.py:344 #, python-format msgid "Error editing metadata type; %s" msgstr "Error editando tipo de metadatos; %s" -#: views.py:349 +#: views.py:350 #, python-format msgid "edit metadata type: %s" msgstr "editar tipo de metadatos: %s" -#: views.py:364 +#: views.py:365 msgid "Metadata type created successfully" msgstr "Tipo de metadatos creado exitosamente" -#: views.py:370 +#: views.py:371 msgid "create metadata type" msgstr "crear tipo de metadatos" -#: views.py:389 +#: views.py:390 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Tipos de metadatos: %s eliminado exitosamente." -#: views.py:391 +#: 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:402 +#: 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:419 +#: views.py:420 msgid "members" msgstr "miembros" -#: views.py:463 +#: views.py:464 #, python-format msgid "non members of metadata set: %s" msgstr "no miembros del conjunto de metadatos: %s" -#: views.py:464 +#: views.py:465 #, python-format msgid "members of metadata set: %s" msgstr "miembros del conjunto de metadatos: %s" -#: views.py:479 +#: views.py:480 msgid "Metadata set created successfully" msgstr "Conjunto de metadatos creados exitosamente" -#: views.py:485 +#: views.py:486 msgid "create metadata set" msgstr "crear conjunto de metadatos" -#: views.py:504 +#: views.py:505 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Conjunto de metadatos: %s eliminado exitosamente." -#: views.py:507 +#: 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:518 +#: 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:576 +#: 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:577 +#: 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 index 4dfe2c2d8daec61b8f650e535fbdcbed9a33ff33..0303c94f855333232bcb704c250f39d9d4752471 100644 GIT binary patch delta 943 zcmXZaO=uHQ5Ww*_E)->6CSX+Z$`~a~j(xMh49yTQ;fhH@v31}|? z(VL*SS1$@)tB?wU^rRO-5D|J&=|S*NuzuV;i2kQ;Sn_)_c{}gDdAXNg%|DBFwAQwX zWWyp65efE-4B!Zk;7R<2MSK|$xx|nAiF*e{VwlBIEZ_v*!byCAL-+&t;qIsik0gB0 zW1P4gm6nV#@JMLkRn)@kcnG_wLJb*5QgRM!SVArE0d>K@n8!(0Gx0Vq;0jLRz_3U+ z&Z2I#fCusZa7*M2gB23v_!~nQGuSmA!yY_~y1~nM7;oSVKEl)Z9cMAiBt6g_)cH^O z>cschg=@$X@);BOr{xdg2Sl!txPn^XIRoQ^?_E-nWUp#GW5N z!G7XbsP#VLcKnKau(ioxFM|LVt}PnE9T-E+r%*dF?Z*Yw1)HezJ=6ss`uSxH5WmG; z_zv{|pM1ZdLA-&~X~|A5S__S#wm#!~3bj>pzK)-NfO;j5ecRYc{2Hk#Z;+t~M&oVsgQ*nU3vRPStkInsw8vn^o6s zmRzqAj&`RrMtUNbNqKj}gEN^#DwEL6@m%I;JjExNx7r2*RY03K*zUIyM6(~_JH?49hXSA35tk6HI0ED&x delta 920 zcmXxiO=uHA6u|LklGZj9qi9pxrgpWpwj`^&X{0uI(m+8Xty1(*6t;FLftZve+T-d$ z1ur=Sy$FJc(2F0X2!a)=9zBTQ!GlH7n;wK7q~PcO*)fFt=Dp0mnK!e~^7Z_qL^xR3 zBr@DC(kUYE<03opJN9F&Lu3sz_%tN4k3V-4f9?_)z@~0;n8JfNi6eL&d+-JB!jG81 zKgI+>l6W*BfebP5Noe6ZYT-rPi|>$U z&cDo01n*)qE+D1lA=>ylFoRz>MIyOpqrf$c5-*}YxQu$#FOg>Ct1(I&G%rKOG2BM% zn|L0%J-LBe?>=tEC%7Gh6$V_VyhS~tZ`g|KCLiKO(39vvotHvga13?6kGf#VHNA0E&+%;HO(&Ev5~y**KI(w3Xax+Aueah&MHxP8*USg01tB|GQU z{H&FBT-SEfwmWP&qgmHUI((veuUfMwD_*Hu^lIfw)|x2zl{v3mEL%ss;*3|a4$uA1 g?4SOZX>`ZWwB^0h>;-R@x`kR}K0dYdA$~UY7c_l)1ONa4 diff --git a/apps/metadata/locale/it/LC_MESSAGES/django.po b/apps/metadata/locale/it/LC_MESSAGES/django.po index 957ce8aa8e..a37122bdee 100644 --- a/apps/metadata/locale/it/LC_MESSAGES/django.po +++ b/apps/metadata/locale/it/LC_MESSAGES/django.po @@ -1,22 +1,21 @@ # 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-02 14:17-0400\n" -"PO-Revision-Date: 2011-12-13 09:10+0000\n" -"Last-Translator: Pierpaolo Baldan \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\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 @@ -35,7 +34,7 @@ msgstr "aggiungi metadata" msgid "remove metadata" msgstr "revoca metadata" -#: __init__.py:29 models.py:34 views.py:315 +#: __init__.py:29 models.py:34 views.py:316 msgid "metadata types" msgstr "tipo di metadata" @@ -51,7 +50,7 @@ msgstr "cancella" msgid "create new" msgstr "crea nuovo" -#: __init__.py:34 views.py:415 +#: __init__.py:34 views.py:416 msgid "metadata sets" msgstr "set di metadati" @@ -59,7 +58,7 @@ msgstr "set di metadati" msgid "default metadata" msgstr "metadati di default" -#: classes.py:12 +#: classes.py:14 #, python-format msgid "'metadata' object has no attribute '%s'" msgstr "'metadata' non ha gli attributi '%s'" @@ -92,7 +91,7 @@ msgstr "Tipo di metadato" msgid "Remove" msgstr "Revoca" -#: forms.py:86 +#: forms.py:86 views.py:541 views.py:559 msgid "Metadata sets" msgstr "Set di metadati" @@ -144,11 +143,11 @@ 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:352 views.py:397 +#: 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:467 views.py:513 +#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514 msgid "metadata set" msgstr "set di metadata" @@ -168,7 +167,7 @@ msgstr "documento" msgid "type" msgstr "tipo" -#: models.py:76 views.py:303 +#: models.py:76 views.py:304 msgid "value" msgstr "valore" @@ -176,7 +175,7 @@ msgstr "valore" msgid "document metadata" msgstr "metadata per il doccumento" -#: models.py:91 views.py:581 +#: models.py:91 views.py:599 msgid "document type" msgstr "tipo documento" @@ -244,75 +243,76 @@ msgstr "Cancella il set dei metadati" msgid "View metadata sets" msgstr "Visualizza il set dei metadati" -#: views.py:40 views.py:203 +#: views.py:41 views.py:204 msgid "The selected document doesn't have any metadata." msgstr "Il documento selezionato non ha metadati." -#: views.py:51 views.py:143 views.py:215 +#: views.py:52 views.py:144 views.py:216 msgid "Must provide at least one document." msgstr "Devi fornire almeno un documento." -#: views.py:86 views.py:250 +#: 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:98 +#: 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:101 +#: views.py:102 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Metadata per il documento %s modificato con successo." -#: views.py:106 views.py:267 +#: 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:108 views.py:269 +#: views.py:109 views.py:270 msgid "Document indexes updated successfully." msgstr "Indici documento aggiornati con successo." -#: views.py:119 +#: views.py:120 #, python-format msgid "Edit metadata for document: %s" msgstr "Modifica metadata per il documento: %s" -#: views.py:121 +#: views.py:122 #, python-format msgid "Edit metadata for documents: %s" msgstr "Modifica metadata per i documenti: %s" -#: views.py:160 +#: 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 metadata: %(metadata_type)s aggiunto con successo al documento " "%(document)s." -#: views.py:163 +#: 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:187 +#: views.py:188 #, python-format msgid "Add metadata type to document: %s" msgstr "Aggiungi tipo metadata al document: %s" -#: views.py:189 +#: views.py:190 #, python-format msgid "Add metadata type to documents: %s" msgstr "Aggiungi tipo metadata ai documents: %s" -#: views.py:258 +#: views.py:259 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " @@ -321,7 +321,7 @@ msgstr "" "Rimuovere con successo tipo di metadati: %(metadata_type)s per il " "documento: %(document)s." -#: views.py:261 +#: views.py:262 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." @@ -329,105 +329,109 @@ msgstr "" "Errore durante la rimozione dei metadati di tipo: %(metadata_type)s per il " "documento: %(document)s." -#: views.py:280 +#: views.py:281 #, python-format msgid "Remove metadata types from document: %s" msgstr "Rimuovi il tipo metadata per il documento: %s" -#: views.py:282 +#: views.py:283 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Rimuovi il tipo metadata per il documenti: %s" -#: views.py:301 +#: views.py:302 #, python-format msgid "metadata for: %s" msgstr "metadata per:%s" -#: views.py:319 +#: views.py:320 msgid "internal name" msgstr "nome interno" -#: views.py:340 +#: views.py:341 msgid "Metadata type edited successfully" msgstr "Tipo di metadata modificato con successo" -#: views.py:343 +#: views.py:344 #, python-format msgid "Error editing metadata type; %s" msgstr "Errore nella modifica del tipo di metadata ; %s" -#: views.py:349 +#: views.py:350 #, python-format msgid "edit metadata type: %s" msgstr "modifica tipo di metadata: %s" -#: views.py:364 +#: views.py:365 msgid "Metadata type created successfully" msgstr "Tipo metadata creato con successo" -#: views.py:370 +#: views.py:371 msgid "create metadata type" msgstr "create tipo di metadata" -#: views.py:389 +#: views.py:390 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Tipo metadata:%s cancellato con successo." -#: views.py:391 +#: 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:402 +#: 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:419 +#: views.py:420 msgid "members" msgstr "membri" -#: views.py:463 +#: views.py:464 #, python-format msgid "non members of metadata set: %s" msgstr "non membri del set di metadata:%s" -#: views.py:464 +#: views.py:465 #, python-format msgid "members of metadata set: %s" msgstr "membri del set di metadata:%s" -#: views.py:479 +#: views.py:480 msgid "Metadata set created successfully" msgstr "Set di metadata creata con successo" -#: views.py:485 +#: views.py:486 msgid "create metadata set" msgstr "creazione del set di metadata" -#: views.py:504 +#: views.py:505 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Set di metadata: %s cancellata con successo." -#: views.py:507 +#: 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:518 +#: 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:576 +#: 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:577 +#: views.py:595 #, python-format msgid "members of document type: %s" msgstr "membri del tipo di documento: %s" @@ -453,23 +457,25 @@ 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 " +"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 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 " +"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 " +"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/pt/LC_MESSAGES/django.mo b/apps/metadata/locale/pt/LC_MESSAGES/django.mo index 7d7e1b543c7658a39f12d253094acdcee0201a2f..e2f2d544c3f78dcf477110e8272eb5edfd6b1f30 100644 GIT binary patch delta 944 zcmXZaO=uHA6u|LkzO2<)KbmMwG^_QawI-XSE!ag`q^Ji|wY5|fM7I)?LXr)eq>zdP zFFlAJB!?bEMDV17LIrOk^i(|P)m}V#D<~8%qUis{gkgWPGjHd;naRh@y@@wbZ{y1* zk-?D2J`oA-5!s7+g?G< zGmj~J6qSaUbXFKJa03rx_kNKhID#~}!J`N7VhNY94+E^;k0zeMtL^uvILZ4e>P8|l zku7)*hj0@0`^8v8WSq`x2DFe33}dgsM`+u#SWH8MR_xuZSPFqk-M1M>vdH=p`gna;OX6$KCh} z*}Qx}jsJ?B_zSfVKfBS5HG*_BForrYikkQ=wi2KQ=1{MqjvSIKVF2IZ4t$T?o_sgZCgZ)Q|)nO?Vl1;dSKyC}q@yi>L)YM=fXtwV*ZB_;vK*U!;kT zbMMFFsBzP%iEp0n)v{%pxw&e-Hk-KR6iwHu*zTO;nnk;A zm(00JrIxKU^Py-*Ds7~Ot#q>aAQYKM$CK%}j*M98p@Ag7&Wv5D#;0AoR4Le1$F+
      ') tags_template.append(get_single_tag_template(tag)) - tags_template.append('
    ') + tags_template.append('') return mark_safe(u''.join(tags_template)) From 27081240cfb282e369d4e5734d6eb3abfdcfc05d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 14:52:14 -0400 Subject: [PATCH 462/484] Fix PermissionDenied exception import --- apps/linking/views.py | 3 ++- apps/sources/views.py | 3 ++- apps/tags/views.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/linking/views.py b/apps/linking/views.py index e02fdabc29..ab85947403 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -8,6 +8,7 @@ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, render_to_response from django.core.urlresolvers import reverse from django.template import RequestContext +from django.core.exceptions import PermissionDenied from common.utils import encapsulate from common.widgets import two_state_template @@ -16,7 +17,7 @@ from documents.views import document_list from documents.permissions import PERMISSION_DOCUMENT_VIEW from permissions.models import Permission from acls.views import acl_list_for -from acls.models import AccessEntry, PermissionDenied +from acls.models import AccessEntry from acls.utils import apply_default_acls from .models import SmartLink, SmartLinkCondition diff --git a/apps/sources/views.py b/apps/sources/views.py index 775ddf2917..ddbf4c71b0 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -9,6 +9,7 @@ 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.permissions import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_NEW_VERSION) @@ -18,7 +19,7 @@ from metadata.api import decode_metadata_from_url, metadata_repr_as_list from permissions.models import Permission from common.utils import encapsulate import sendfile -from acls.models import AccessEntry, PermissionDenied +from acls.models import AccessEntry from sources.models import (WebForm, StagingFolder, SourceTransformation, WatchFolder) diff --git a/apps/tags/views.py b/apps/tags/views.py index cb82ae0c64..a153506e02 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -8,13 +8,14 @@ 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 import Permission from taggit.models import Tag from documents.models import Document from documents.views import document_list from documents.permissions import PERMISSION_DOCUMENT_VIEW -from acls.models import AccessEntry, PermissionDenied +from acls.models import AccessEntry from acls.views import acl_list_for from acls.utils import apply_default_acls From 3768835219558d5b737d425a7e6c84ecb986c19a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 15:01:54 -0400 Subject: [PATCH 463/484] Add sanity check when assembling a full path --- apps/document_indexing/filesystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py index b29f63fb74..bf6ead9655 100644 --- a/apps/document_indexing/filesystem.py +++ b/apps/document_indexing/filesystem.py @@ -22,7 +22,7 @@ def assemble_suffixed_filename(filename, suffix=0): def assemble_path_from_list(directory_list): - return os.sep.join(directory_list) + return os.path.normpath(os.sep.join(directory_list)) def get_instance_path(index_instance): From 1cbe8f78e8e64555b301f0ad396fb686a74ea64b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 15:58:58 -0400 Subject: [PATCH 464/484] Add column showing index and index node enabled/disabled status --- apps/document_indexing/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 8a94e77cf2..b8c3647158 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -15,6 +15,7 @@ from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list from common.utils import encapsulate +from common.widgets import two_state_template from acls.utils import apply_default_acls from acls.models import AccessEntry @@ -40,6 +41,7 @@ def index_setup_list(request): 'extra_columns': [ {'name': _(u'name'), 'attribute': 'name'}, {'name': _(u'title'), 'attribute': 'title'}, + {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, ] } @@ -164,6 +166,7 @@ def index_setup_view(request, index_pk): 'hide_object': True, 'extra_columns': [ {'name': _(u'level'), 'attribute': encapsulate(lambda x: node_level(x))}, + {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, ], } From 4e1c8ff0eb73a2b5a464873b6b6b3d3c5111c18d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 16:05:53 -0400 Subject: [PATCH 465/484] Initial Polish translation by mic (https://www.transifex.net/accounts/profile/mic/) --- .tx/config | 25 + apps/acls/locale/pl/LC_MESSAGES/django.po | 241 ++++ apps/common/locale/pl/LC_MESSAGES/django.po | 339 +++++ .../converter/locale/pl/LC_MESSAGES/django.po | 933 ++++++++++++++ .../locale/pl/LC_MESSAGES/django.po | 215 ++++ .../locale/pl/LC_MESSAGES/django.po | 99 ++ .../locale/pl/LC_MESSAGES/django.po | 364 ++++++ .../locale/pl/LC_MESSAGES/django.po | 123 ++ .../documents/locale/pl/LC_MESSAGES/django.po | 1096 +++++++++++++++++ .../locale/pl/LC_MESSAGES/django.po | 117 ++ apps/feedback/locale/pl/LC_MESSAGES/django.po | 103 ++ apps/folders/locale/pl/LC_MESSAGES/django.po | 230 ++++ apps/history/locale/pl/LC_MESSAGES/django.po | 107 ++ apps/linking/locale/pl/LC_MESSAGES/django.po | 334 +++++ apps/main/locale/pl/LC_MESSAGES/django.po | 146 +++ apps/metadata/locale/pl/LC_MESSAGES/django.po | 455 +++++++ .../locale/pl/LC_MESSAGES/django.po | 31 + apps/ocr/locale/pl/LC_MESSAGES/django.po | 415 +++++++ .../locale/pl/LC_MESSAGES/django.po | 205 +++ .../locale/pl/LC_MESSAGES/django.po | 29 + .../locale/pl/LC_MESSAGES/django.po | 23 + .../locale/pl/LC_MESSAGES/django.po | 37 + apps/sources/locale/pl/LC_MESSAGES/django.po | 525 ++++++++ apps/tags/locale/pl/LC_MESSAGES/django.po | 248 ++++ .../locale/pl/LC_MESSAGES/django.po | 257 ++++ .../web_theme/locale/pl/LC_MESSAGES/django.po | 75 ++ settings.py | 1 + 27 files changed, 6773 insertions(+) create mode 100644 apps/acls/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/common/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/converter/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/django_gpg/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/document_comments/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/document_indexing/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/document_signatures/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/documents/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/dynamic_search/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/feedback/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/folders/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/history/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/linking/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/main/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/metadata/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/navigation/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/ocr/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/permissions/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/project_setup/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/project_tools/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/smart_settings/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/sources/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/tags/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/user_management/locale/pl/LC_MESSAGES/django.po create mode 100644 apps/web_theme/locale/pl/LC_MESSAGES/django.po diff --git a/.tx/config b/.tx/config index 64a8261443..27ed2c26db 100644 --- a/.tx/config +++ b/.tx/config @@ -5,6 +5,7 @@ trans.es = apps/converter/locale/es/LC_MESSAGES/django.po trans.pt = apps/converter/locale/pt/LC_MESSAGES/django.po trans.ru = apps/converter/locale/ru/LC_MESSAGES/django.po trans.it = apps/converter/locale/it/LC_MESSAGES/django.po +trans.pl = apps/converter/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-common] source_file = apps/common/locale/en/LC_MESSAGES/django.po @@ -13,6 +14,7 @@ trans.es = apps/common/locale/es/LC_MESSAGES/django.po trans.pt = apps/common/locale/pt/LC_MESSAGES/django.po trans.ru = apps/common/locale/ru/LC_MESSAGES/django.po trans.it = apps/common/locale/it/LC_MESSAGES/django.po +trans.pl = apps/common/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-permissions] source_file = apps/permissions/locale/en/LC_MESSAGES/django.po @@ -21,6 +23,7 @@ trans.es = apps/permissions/locale/es/LC_MESSAGES/django.po trans.pt = apps/permissions/locale/pt/LC_MESSAGES/django.po trans.ru = apps/permissions/locale/ru/LC_MESSAGES/django.po trans.it = apps/permissions/locale/it/LC_MESSAGES/django.po +trans.pl = apps/permissions/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-sources] source_file = apps/sources/locale/en/LC_MESSAGES/django.po @@ -29,6 +32,7 @@ trans.es = apps/sources/locale/es/LC_MESSAGES/django.po trans.pt = apps/sources/locale/pt/LC_MESSAGES/django.po trans.ru = apps/sources/locale/ru/LC_MESSAGES/django.po trans.it = apps/sources/locale/it/LC_MESSAGES/django.po +trans.pl = apps/sources/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-document_indexing] source_file = apps/document_indexing/locale/en/LC_MESSAGES/django.po @@ -37,6 +41,7 @@ trans.es = apps/document_indexing/locale/es/LC_MESSAGES/django.po trans.pt = apps/document_indexing/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_indexing/locale/ru/LC_MESSAGES/django.po trans.it = apps/document_indexing/locale/it/LC_MESSAGES/django.po +trans.pl = apps/document_indexing/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-user_management] source_file = apps/user_management/locale/en/LC_MESSAGES/django.po @@ -45,6 +50,7 @@ trans.es = apps/user_management/locale/es/LC_MESSAGES/django.po trans.pt = apps/user_management/locale/pt/LC_MESSAGES/django.po trans.ru = apps/user_management/locale/ru/LC_MESSAGES/django.po trans.it = apps/user_management/locale/it/LC_MESSAGES/django.po +trans.pl = apps/user_management/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-main] source_file = apps/main/locale/en/LC_MESSAGES/django.po @@ -53,6 +59,7 @@ trans.es = apps/main/locale/es/LC_MESSAGES/django.po trans.pt = apps/main/locale/pt/LC_MESSAGES/django.po trans.ru = apps/main/locale/ru/LC_MESSAGES/django.po trans.it = apps/main/locale/it/LC_MESSAGES/django.po +trans.pl = apps/main/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-ocr] source_file = apps/ocr/locale/en/LC_MESSAGES/django.po @@ -61,6 +68,7 @@ trans.es = apps/ocr/locale/es/LC_MESSAGES/django.po trans.pt = apps/ocr/locale/pt/LC_MESSAGES/django.po trans.ru = apps/ocr/locale/ru/LC_MESSAGES/django.po trans.it = apps/ocr/locale/it/LC_MESSAGES/django.po +trans.pl = apps/ocr/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-project_setup] source_file = apps/project_setup/locale/en/LC_MESSAGES/django.po @@ -69,6 +77,7 @@ trans.es = apps/project_setup/locale/es/LC_MESSAGES/django.po trans.pt = apps/project_setup/locale/pt/LC_MESSAGES/django.po trans.ru = apps/project_setup/locale/ru/LC_MESSAGES/django.po trans.it = apps/project_setup/locale/it/LC_MESSAGES/django.po +trans.pl = apps/project_setup/locale/pl/LC_MESSAGES/django.po [main] host = https://www.transifex.net @@ -80,6 +89,7 @@ trans.es = apps/folders/locale/es/LC_MESSAGES/django.po trans.pt = apps/folders/locale/pt/LC_MESSAGES/django.po trans.ru = apps/folders/locale/ru/LC_MESSAGES/django.po trans.it = apps/folders/locale/it/LC_MESSAGES/django.po +trans.pl = apps/folders/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-history] source_file = apps/history/locale/en/LC_MESSAGES/django.po @@ -88,6 +98,7 @@ trans.es = apps/history/locale/es/LC_MESSAGES/django.po trans.pt = apps/history/locale/pt/LC_MESSAGES/django.po trans.ru = apps/history/locale/ru/LC_MESSAGES/django.po trans.it = apps/history/locale/it/LC_MESSAGES/django.po +trans.pl = apps/history/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-dynamic_search] source_file = apps/dynamic_search/locale/en/LC_MESSAGES/django.po @@ -96,6 +107,7 @@ trans.es = apps/dynamic_search/locale/es/LC_MESSAGES/django.po trans.pt = apps/dynamic_search/locale/pt/LC_MESSAGES/django.po trans.ru = apps/dynamic_search/locale/ru/LC_MESSAGES/django.po trans.it = apps/dynamic_search/locale/it/LC_MESSAGES/django.po +trans.pl = apps/dynamic_search/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-smart_settings] source_file = apps/smart_settings/locale/en/LC_MESSAGES/django.po @@ -104,6 +116,7 @@ trans.es = apps/smart_settings/locale/es/LC_MESSAGES/django.po trans.pt = apps/smart_settings/locale/pt/LC_MESSAGES/django.po trans.ru = apps/smart_settings/locale/ru/LC_MESSAGES/django.po trans.it = apps/smart_settings/locale/it/LC_MESSAGES/django.po +trans.pl = apps/smart_settings/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-navigation] source_file = apps/navigation/locale/en/LC_MESSAGES/django.po @@ -112,6 +125,7 @@ trans.es = apps/navigation/locale/es/LC_MESSAGES/django.po trans.pt = apps/navigation/locale/pt/LC_MESSAGES/django.po trans.ru = apps/navigation/locale/ru/LC_MESSAGES/django.po trans.it = apps/navigation/locale/it/LC_MESSAGES/django.po +trans.pl = apps/navigation/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-tags] source_file = apps/tags/locale/en/LC_MESSAGES/django.po @@ -120,6 +134,7 @@ trans.es = apps/tags/locale/es/LC_MESSAGES/django.po trans.pt = apps/tags/locale/pt/LC_MESSAGES/django.po trans.ru = apps/tags/locale/ru/LC_MESSAGES/django.po trans.it = apps/tags/locale/it/LC_MESSAGES/django.po +trans.pl = apps/tags/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-documents] source_file = apps/documents/locale/en/LC_MESSAGES/django.po @@ -128,6 +143,7 @@ trans.es = apps/documents/locale/es/LC_MESSAGES/django.po trans.pt = apps/documents/locale/pt/LC_MESSAGES/django.po trans.ru = apps/documents/locale/ru/LC_MESSAGES/django.po trans.it = apps/documents/locale/it/LC_MESSAGES/django.po +trans.pl = apps/documents/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-project_tools] source_file = apps/project_tools/locale/en/LC_MESSAGES/django.po @@ -136,6 +152,7 @@ trans.es = apps/project_tools/locale/es/LC_MESSAGES/django.po trans.pt = apps/project_tools/locale/pt/LC_MESSAGES/django.po trans.ru = apps/project_tools/locale/ru/LC_MESSAGES/django.po trans.it = apps/project_tools/locale/it/LC_MESSAGES/django.po +trans.pl = apps/project_tools/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-linking] source_file = apps/linking/locale/en/LC_MESSAGES/django.po @@ -144,6 +161,7 @@ trans.es = apps/linking/locale/es/LC_MESSAGES/django.po trans.pt = apps/linking/locale/pt/LC_MESSAGES/django.po trans.ru = apps/linking/locale/ru/LC_MESSAGES/django.po trans.it = apps/linking/locale/it/LC_MESSAGES/django.po +trans.pl = apps/linking/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-document_comments] source_file = apps/document_comments/locale/en/LC_MESSAGES/django.po @@ -152,6 +170,7 @@ trans.es = apps/document_comments/locale/es/LC_MESSAGES/django.po trans.pt = apps/document_comments/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_comments/locale/ru/LC_MESSAGES/django.po trans.it = apps/document_comments/locale/it/LC_MESSAGES/django.po +trans.pl = apps/document_comments/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-metadata] source_file = apps/metadata/locale/en/LC_MESSAGES/django.po @@ -160,6 +179,7 @@ trans.es = apps/metadata/locale/es/LC_MESSAGES/django.po trans.pt = apps/metadata/locale/pt/LC_MESSAGES/django.po trans.ru = apps/metadata/locale/ru/LC_MESSAGES/django.po trans.it = apps/metadata/locale/it/LC_MESSAGES/django.po +trans.pl = apps/metadata/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-web_theme] source_file = apps/web_theme/locale/en/LC_MESSAGES/django.po @@ -168,6 +188,7 @@ trans.es = apps/web_theme/locale/es/LC_MESSAGES/django.po trans.pt = apps/web_theme/locale/pt/LC_MESSAGES/django.po trans.ru = apps/web_theme/locale/ru/LC_MESSAGES/django.po trans.it = apps/web_theme/locale/it/LC_MESSAGES/django.po +trans.pl = apps/web_theme/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-django_gpg] source_file = apps/django_gpg/locale/en/LC_MESSAGES/django.po @@ -176,6 +197,7 @@ trans.es = apps/django_gpg/locale/es/LC_MESSAGES/django.po trans.pt = apps/django_gpg/locale/pt/LC_MESSAGES/django.po trans.ru = apps/django_gpg/locale/ru/LC_MESSAGES/django.po trans.it = apps/django_gpg/locale/it/LC_MESSAGES/django.po +trans.pl = apps/django_gpg/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-document_signatures] source_file = apps/document_signatures/locale/en/LC_MESSAGES/django.po @@ -184,6 +206,7 @@ trans.es = apps/document_signatures/locale/es/LC_MESSAGES/django.po trans.pt = apps/document_signatures/locale/pt/LC_MESSAGES/django.po trans.ru = apps/document_signatures/locale/ru/LC_MESSAGES/django.po trans.it = apps/document_signatures/locale/it/LC_MESSAGES/django.po +trans.pl = apps/document_signatures/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-acls] source_file = apps/acls/locale/en/LC_MESSAGES/django.po @@ -192,6 +215,7 @@ trans.es = apps/acls/locale/es/LC_MESSAGES/django.po trans.pt = apps/acls/locale/pt/LC_MESSAGES/django.po trans.ru = apps/acls/locale/ru/LC_MESSAGES/django.po trans.it = apps/acls/locale/it/LC_MESSAGES/django.po +trans.pl = apps/acls/locale/pl/LC_MESSAGES/django.po [mayan-edms.apps-feedback] source_file = apps/feedback/locale/en/LC_MESSAGES/django.po @@ -200,3 +224,4 @@ trans.es = apps/feedback/locale/es/LC_MESSAGES/django.po trans.pt = apps/feedback/locale/pt/LC_MESSAGES/django.po trans.ru = apps/feedback/locale/ru/LC_MESSAGES/django.po trans.it = apps/feedback/locale/it/LC_MESSAGES/django.po +trans.pl = apps/feedback/locale/pl/LC_MESSAGES/django.po diff --git a/apps/acls/locale/pl/LC_MESSAGES/django.po b/apps/acls/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..00b723be0d --- /dev/null +++ b/apps/acls/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,241 @@ +# 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: 2012-01-02 09:45+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:14 +msgid "ACLs" +msgstr "" + +#: __init__.py:15 __init__.py:23 +msgid "details" +msgstr "" + +#: __init__.py:16 __init__.py:25 +msgid "grant" +msgstr "" + +#: __init__.py:17 __init__.py:26 +msgid "revoke" +msgstr "" + +#: __init__.py:18 __init__.py:24 forms.py:21 +msgid "New holder" +msgstr "" + +#: __init__.py:20 +msgid "Default ACLs" +msgstr "" + +#: __init__.py:21 +msgid "List of classes" +msgstr "" + +#: __init__.py:22 +msgid "ACLs for class" +msgstr "" + +#: forms.py:38 +msgid "Users" +msgstr "" + +#: forms.py:41 +msgid "Groups" +msgstr "" + +#: forms.py:44 +msgid "Roles" +msgstr "" + +#: forms.py:47 +msgid "Special" +msgstr "" + +#: managers.py:116 managers.py:128 +msgid "Insufficient access." +msgstr "" + +#: models.py:27 models.py:69 +msgid "permission" +msgstr "" + +#: models.py:53 +msgid "access entry" +msgstr "" + +#: models.py:54 +msgid "access entries" +msgstr "" + +#: models.py:90 +msgid "default access entry" +msgstr "" + +#: models.py:91 +msgid "default access entries" +msgstr "" + +#: models.py:109 +msgid "Creator" +msgstr "" + +#: models.py:112 models.py:113 +msgid "creator" +msgstr "" + +#: permissions.py:7 permissions.py:8 +msgid "Access control lists" +msgstr "" + +#: permissions.py:10 +msgid "Edit ACLs" +msgstr "" + +#: permissions.py:11 +msgid "View ACLs" +msgstr "" + +#: permissions.py:13 +msgid "Edit class default ACLs" +msgstr "" + +#: permissions.py:14 +msgid "View class default ACLs" +msgstr "" + +#: views.py:47 +#, python-format +msgid "access control lists for: %s" +msgstr "" + +#: views.py:49 views.py:411 +msgid "holder" +msgstr "" + +#: views.py:50 views.py:412 +msgid "permissions" +msgstr "" + +#: views.py:97 +#, python-format +msgid "permissions available to: %(actor)s for %(obj)s" +msgstr "" + +#: views.py:104 views.py:444 +msgid "namespace" +msgstr "" + +#: views.py:105 views.py:445 +msgid "label" +msgstr "" + +#: views.py:107 views.py:447 +msgid "has permission" +msgstr "" + +#: views.py:185 views.py:279 views.py:528 views.py:608 +msgid ", " +msgstr "" + +#: views.py:186 views.py:280 views.py:529 views.py:609 +#, python-format +msgid " for %s" +msgstr "" + +#: views.py:187 views.py:530 +#, python-format +msgid " to %s" +msgstr "" + +#: views.py:190 views.py:533 +#, python-format +msgid "Are you sure you wish to grant the permission %(title_suffix)s?" +msgstr "" + +#: views.py:192 views.py:535 +#, python-format +msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:199 views.py:542 +#, python-format +msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." +msgstr "" + +#: views.py:205 views.py:548 +#, python-format +msgid "" +"%(actor)s, already had the permission \"%(permission)s\" granted for " +"%(object)s." +msgstr "" + +#: views.py:281 views.py:610 +#, python-format +msgid " from %s" +msgstr "" + +#: views.py:284 views.py:613 +#, python-format +msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" +msgstr "" + +#: views.py:286 views.py:615 +#, python-format +msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" +msgstr "" + +#: views.py:293 views.py:622 +#, python-format +msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." +msgstr "" + +#: views.py:299 views.py:628 +#, python-format +msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." +msgstr "" + +#: views.py:355 +#, python-format +msgid "add new holder for: %s" +msgstr "" + +#: views.py:356 views.py:488 +msgid "Select" +msgstr "" + +#: views.py:388 +msgid "classes" +msgstr "" + +#: views.py:390 +msgid "class" +msgstr "" + +#: views.py:409 +#, python-format +msgid "default access control lists for class: %s" +msgstr "" + +#: views.py:437 +#, python-format +msgid "permissions available to: %(actor)s for class %(class)s" +msgstr "" + +#: views.py:486 +#, python-format +msgid "add new holder for class: %s" +msgstr "" diff --git a/apps/common/locale/pl/LC_MESSAGES/django.po b/apps/common/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..6998e25932 --- /dev/null +++ b/apps/common/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,339 @@ +# 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. +# 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-21 15:17+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 "change password" +msgstr "zmień hasło" + +#: __init__.py:21 +msgid "user details" +msgstr "szczegóły konta użytkownika" + +#: __init__.py:22 +msgid "edit details" +msgstr "edytuj szczegóły" + +#: __init__.py:26 __init__.py:31 +msgid "about" +msgstr "informacje o" + +#: __init__.py:27 +msgid "license" +msgstr "licencja" + +#: forms.py:101 +msgid "Selection" +msgstr "Zaznaczenie" + +#: forms.py:133 +msgid "Email" +msgstr "E-mail" + +#: forms.py:144 +msgid "" +"Please enter a correct email and password. Note that the password fields is " +"case-sensitive." +msgstr "Proszę wpisać poprawną nazwę użytkownika i hasło. Uwaga: wielkość liter ma znaczenie." + +#: forms.py:146 +msgid "This account is inactive." +msgstr "To konto jest nieaktywne." + +#: literals.py:24 +msgid "A5" +msgstr "A5" + +#: literals.py:25 +msgid "A4" +msgstr "A4" + +#: literals.py:26 +msgid "A3" +msgstr "A3" + +#: literals.py:27 +msgid "B5" +msgstr "B5" + +#: literals.py:28 +msgid "B4" +msgstr "B4" + +#: literals.py:29 +msgid "Letter" +msgstr "Letter" + +#: literals.py:30 +msgid "Legal" +msgstr "Legal" + +#: literals.py:31 +msgid "Ledger" +msgstr "Ledger" + +#: literals.py:38 +msgid "Portrait" +msgstr "Portrait" + +#: literals.py:39 +msgid "Landscape" +msgstr "Landscape" + +#: models.py:16 +msgid "lock field" +msgstr "zablokować pole" + +#: models.py:43 +msgid "Anonymous user" +msgstr "Użytkownik anonimowy" + +#: models.py:46 models.py:47 +msgid "anonymous user" +msgstr "użytkownik anonimowy" + +#: utils.py:295 +msgid "function found" +msgstr "znaleźć funkcję" + +#: views.py:36 +msgid "No action selected." +msgstr "Nie wybrano żadnego działania" + +#: views.py:40 +msgid "Must select at least one item." +msgstr "Musisz wybrać co najmniej jeden element." + +#: views.py:88 +#, python-format +msgid "%(selection)s added successfully added to %(right_list_title)s." +msgstr " %(selection)s pomyślnie dodana do %(right_list_title)s." + +#: views.py:94 views.py:121 +#, python-format +msgid "Unable to add %(selection)s to %(right_list_title)s." +msgstr "Nie można dodać %(selection)s do %(right_list_title)s." + +#: views.py:115 +#, python-format +msgid "%(selection)s added successfully removed from %(right_list_title)s." +msgstr " %(selection)s pomyślnie dodana usunięty z %(right_list_title)s." + +#: views.py:136 +msgid "Add" +msgstr "Dodaj" + +#: views.py:147 +msgid "Remove" +msgstr "Usuń" + +#: views.py:170 +msgid "current user details" +msgstr "aktualne dane użytkownika" + +#: views.py:187 +msgid "E-mail conflict, another user has that same email." +msgstr "Użytkownik o podanym adresie e-mail już istnieje." + +#: views.py:190 +msgid "Current user's details updated." +msgstr "Aktualne dane użytkownika aktualizowane." + +#: views.py:199 +msgid "edit current user details" +msgstr "edytuj aktualne dane użytkownika" + +#: views.py:230 +msgid "License" +msgstr "Licencja" + +#: views.py:239 +msgid "Current user password change" +msgstr "Zmiana hasła użytkownika" + +#: views.py:254 templates/password_change_done.html:5 +msgid "Your password has been successfully changed." +msgstr "Twoje hasło zostało pomyślnie zmienione." + +#: widgets.py:58 +msgid "None" +msgstr "Brak" + +#: conf/settings.py:15 +msgid "" +"Temporary directory used site wide to store thumbnails, previews and " +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" +msgstr "Katalog tymczasowy używany do przechowywania całej witryny, miniatur, podglądów i plików tymczasowych. Jeśli nie zostanie określony, zostanie utworzony za pomocą tempfile.mkdtemp ()" + +#: conf/settings.py:65 +msgid "" +"Controls the mechanism used to authenticated user. Options are: username, " +"email" +msgstr "" + +#: conf/settings.py:74 +msgid "Allow non authenticated users, access to all views" +msgstr "" + +#: templates/403.html:3 templates/403.html.py:7 +msgid "Insufficient permissions" +msgstr "Niewystarczające uprawnienia" + +#: templates/403.html:9 +msgid "You don't have enough permissions for this operation." +msgstr "Nie masz wystarczających uprawnień do tej operacji." + +#: templates/404.html:3 templates/404.html.py:7 +msgid "Page not found" +msgstr "Nie znaleziono strony" + +#: templates/404.html:9 +msgid "Sorry, but the requested page could not be found." +msgstr "Przykro nam, ale żądana strona nie została odnaleziona." + +#: templates/calculate_form_title.html:11 +#, python-format +msgid "Details for %(object_name)s: %(object)s" +msgstr "Szczegóły dla %(object_name)s : %(object)s " + +#: templates/calculate_form_title.html:13 +#, python-format +msgid "Details for: %(object)s" +msgstr "Szczegóły: %(object)s " + +#: templates/calculate_form_title.html:18 +#, python-format +msgid "Edit %(object_name)s:" +msgstr "Edytuj %(object_name)s :" + +#: templates/calculate_form_title.html:20 +msgid "Edit" +msgstr "Edytuj" + +#: templates/calculate_form_title.html:24 +#, python-format +msgid "Create new %(object_name)s" +msgstr "Utwórz nową %(object_name)s " + +#: templates/calculate_form_title.html:26 +msgid "Create" +msgstr "Utwórz" + +#: templates/generic_assign_remove.html:3 +#, python-format +msgid "Assign %(title)s %(object)s" +msgstr "Przypisz %(title)s %(object)s" + +#: templates/generic_confirm.html:3 templates/generic_confirm.html.py:18 +msgid "Confirm" +msgstr "Potwierdź" + +#: templates/generic_confirm.html:16 +msgid "Confirm delete" +msgstr "Potwierdź usunięcie" + +#: templates/generic_confirm.html:32 +msgid "form icon" +msgstr "form icon" + +#: templates/generic_confirm.html:40 +#, python-format +msgid "Are you sure you wish to delete %(object_name)s: %(object)s?" +msgstr "Czy na pewno chcesz usunąć %(object_name)s : %(object)s ?" + +#: templates/generic_confirm.html:42 +#, python-format +msgid "Are you sure you wish to delete: %(object)s?" +msgstr "Czy na pewno chcesz usunąć: %(object)s?" + +#: templates/generic_confirm.html:50 +msgid "Yes" +msgstr "Tak" + +#: templates/generic_confirm.html:54 +msgid "No" +msgstr "Nie" + +#: templates/generic_form_instance.html:37 +#: templates/generic_form_subtemplate.html:56 +msgid "required" +msgstr "wymagane" + +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 +#: templates/generic_list_horizontal_subtemplate.html:51 +#: templates/generic_list_horizontal_subtemplate.html:90 +#: templates/generic_list_subtemplate.html:52 +#: templates/generic_list_subtemplate.html:178 +msgid "Save" +msgstr "Zapisz" + +#: templates/generic_form_subtemplate.html:80 +#: templates/generic_form_subtemplate.html:82 +#: templates/generic_list_horizontal_subtemplate.html:51 +#: templates/generic_list_horizontal_subtemplate.html:90 +#: templates/generic_list_subtemplate.html:52 +#: templates/generic_list_subtemplate.html:178 +msgid "Submit" +msgstr "Wyślij" + +#: templates/generic_form_subtemplate.html:87 +msgid "Cancel" +msgstr "Anuluj" + +#: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 +#, python-format +msgid "List of %(stripped_title)s" +msgstr "Wykaz %(stripped_title)s" + +#: templates/generic_list_horizontal_subtemplate.html:23 +#: templates/generic_list_subtemplate.html:24 +#, python-format +msgid "" +"List of %(title)s (%(start)s - %(end)s out of %(total)s) (Page " +"%(page_number)s of %(total_pages)s)" +msgstr "Wykaz %(title)s (%(start)s - %(end)s z %(total)s) (Page %(page_number)s z %(total_pages)s)" + +#: templates/generic_list_horizontal_subtemplate.html:25 +#: templates/generic_list_subtemplate.html:26 +#, python-format +msgid "List of %(title)s (%(total)s)" +msgstr "Wykaz %(title)s (%(total)s)" + +#: templates/generic_list_subtemplate.html:72 +msgid "Identifier" +msgstr "Identyfikator" + +#: templates/generic_list_subtemplate.html:152 +#, python-format +msgid "There are no %(stripped_title)s" +msgstr "Brak %(stripped_title)s" + +#: templates/login.html:5 +msgid "Login" +msgstr "Zaloguj" + +#: templates/password_change_done.html:3 templates/password_change_form.html:3 +#: templates/password_change_form.html:5 +msgid "Password change" +msgstr "Zmiana hasła" diff --git a/apps/converter/locale/pl/LC_MESSAGES/django.po b/apps/converter/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..87445824f2 --- /dev/null +++ b/apps/converter/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,933 @@ +# 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:09+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:15 +msgid "file formats" +msgstr "formaty plików" + +#: literals.py:19 +msgid "Resize" +msgstr "Zmiana rozmiaru" + +#: literals.py:20 +msgid "Resize." +msgstr "Zmiana rozmiaru." + +#: literals.py:22 literals.py:37 +msgid "width" +msgstr "szerokość" + +#: literals.py:23 literals.py:38 +msgid "height" +msgstr "wysokość" + +#: literals.py:27 +msgid "Rotate" +msgstr "Obracać" + +#: literals.py:28 +msgid "Rotate by n degress." +msgstr "" + +#: literals.py:30 +msgid "degrees" +msgstr "" + +#: literals.py:34 +msgid "Density" +msgstr "" + +#: literals.py:35 +msgid "Change the resolution (ie: DPI) without resizing." +msgstr "Zmiana rozdzielczości (np.: DPI) bez zmiany rozmiaru." + +#: literals.py:42 +msgid "Zoom" +msgstr "Powiększ" + +#: literals.py:43 +msgid "Zoom by n percent." +msgstr "" + +#: literals.py:45 +msgid "percent" +msgstr "procent" + +#: literals.py:51 +msgid "Hasselblad Photo RAW, CFV/H3D39II" +msgstr "Hasselblad Photo RAW, CFV/H3D39II" + +#: literals.py:52 literals.py:53 +msgid "Photoshop resource format" +msgstr "" + +#: literals.py:54 +msgid "Photoshop resource text format" +msgstr "" + +#: literals.py:55 +msgid "Photoshop resource wide text format" +msgstr "" + +#: literals.py:57 +msgid "Raw alpha samples" +msgstr "" + +#: literals.py:58 +msgid "Adobe Illustrator CS2" +msgstr "Adobe Illustrator CS2" + +#: literals.py:59 +msgid "Raw application information" +msgstr "" + +#: literals.py:60 +msgid "Raw JPEG binary data" +msgstr "" + +#: literals.py:61 +msgid "PFS: 1st Publisher Clip Art" +msgstr "" + +#: literals.py:62 +msgid "Sony Alpha DSLR Raw Image Format" +msgstr "Sony Alpha DSLR Raw Image Format" + +#: literals.py:63 +msgid "Microsoft Audio/Visual Interleaved" +msgstr "Microsoft Audio/Visual Interleaved" + +#: literals.py:64 +msgid "AVS X image" +msgstr "AVS X image" + +#: literals.py:66 +msgid "Raw blue samples" +msgstr "Raw blue samples" + +#: literals.py:67 +msgid "Raw blue, green, and red samples" +msgstr "Raw blue, green, and red samples" + +#: literals.py:68 +msgid "Raw blue, green, red and alpha samples" +msgstr "Raw blue, green, red and alpha samples" + +#: literals.py:69 +msgid "Microsoft Windows bitmap image" +msgstr "Microsoft Windows bitmap image" + +#: literals.py:70 +msgid "Microsoft Windows bitmap image version 2" +msgstr "Microsoft Windows bitmap image version 2" + +#: literals.py:71 +msgid "Microsoft Windows bitmap image version 3" +msgstr "Microsoft Windows bitmap image version 3" + +#: literals.py:72 +msgid "BRF ASCII Braille format" +msgstr "BRF ASCII Braille format" + +#: literals.py:73 +msgid "Raw blue, red, and green samples" +msgstr "Raw blue, red, and green samples" + +#: literals.py:75 +msgid "Raw cyan samples" +msgstr "Raw cyan samples" + +#: literals.py:76 literals.py:181 +msgid "Magick Persistent Cache image format" +msgstr "Magick Persistent Cache image format" + +#: literals.py:77 literals.py:78 +msgid "Continuous Acquisition and Life-cycle Support Type 1 image" +msgstr "Continuous Acquisition and Life-cycle Support Type 1 image" + +#: literals.py:79 +msgid "Image caption" +msgstr "" + +#: literals.py:80 +msgid "Cineon Image File" +msgstr "" + +#: literals.py:81 +msgid "Cisco IP phone image format" +msgstr "" + +#: literals.py:82 +msgid "Image Clip Mask" +msgstr "" + +#: literals.py:83 +msgid "Raw cyan, magenta, yellow, and black samples" +msgstr "" + +#: literals.py:84 +msgid "Raw cyan, magenta, yellow, black, and opacity samples" +msgstr "" + +#: literals.py:85 literals.py:86 +msgid "Canon Digital Camera Raw Image Format" +msgstr "Canon Digital Camera Raw Image Format" + +#: literals.py:87 +msgid "Microsoft Cursor Icon" +msgstr "Microsoft Cursor Icon" + +#: literals.py:88 +msgid "DR Halo" +msgstr "" + +#: literals.py:90 +msgid "Digital Imaging and Communications in Medicine image" +msgstr "" + +#: literals.py:91 +msgid "Kodak Digital Camera Raw Image File" +msgstr "Kodak Digital Camera Raw Image File" + +#: literals.py:92 +msgid "ZSoft IBM PC multi-page Paintbrush" +msgstr "ZSoft IBM PC multi-page Paintbrush" + +#: literals.py:93 +msgid "Microsoft DirectDraw Surface" +msgstr "Microsoft DirectDraw Surface" + +#: literals.py:94 +msgid "Multi-face font package (Freetype 2.4.2)" +msgstr "Multi-face font package (Freetype 2.4.2)" + +#: literals.py:95 +msgid "Déjà vu" +msgstr "" + +#: literals.py:96 +msgid "Adobe Digital Negative" +msgstr "" + +#: literals.py:97 +msgid "Graphviz" +msgstr "" + +#: literals.py:98 +msgid "SMPTE 268M-2003 (DPX 2.0)" +msgstr "" + +#: literals.py:100 +msgid "Encapsulated Portable Document Format" +msgstr "" + +#: literals.py:101 literals.py:106 +msgid "Adobe Encapsulated PostScript Interchange format" +msgstr "" + +#: literals.py:102 literals.py:105 +msgid "Adobe Encapsulated PostScript" +msgstr "" + +#: literals.py:103 +msgid "Adobe Level II Encapsulated PostScript" +msgstr "" + +#: literals.py:104 +msgid "Adobe Level III Encapsulated PostScript" +msgstr "" + +#: literals.py:107 +msgid "Adobe Encapsulated PostScript with TIFF preview" +msgstr "" + +#: literals.py:108 +msgid "Adobe Level II Encapsulated PostScript with TIFF preview" +msgstr "" + +#: literals.py:109 +msgid "Adobe Level III Encapsulated PostScript with TIFF preview" +msgstr "" + +#: literals.py:110 +msgid "Epson RAW Format" +msgstr "" + +#: literals.py:111 +msgid "Exif digital camera binary data" +msgstr "" + +#: literals.py:112 +msgid "High Dynamic-range (HDR)" +msgstr "" + +#: literals.py:114 +msgid "Group 3 FAX (Not TIFF Group3 FAX)" +msgstr "" + +#: literals.py:115 +msgid "Autodesk FLI animations file" +msgstr "" + +#: literals.py:116 +msgid "Autodesk FLC animations file" +msgstr "" + +#: literals.py:117 literals.py:120 +msgid "Flexible Image Transport System" +msgstr "" + +#: literals.py:118 +msgid "Kodak FlashPix file" +msgstr "" + +#: literals.py:119 literals.py:225 +msgid "Plasma fractal image" +msgstr "" + +#: literals.py:122 +msgid "Raw green samples" +msgstr "" + +#: literals.py:123 +msgid "Group 3 FAX" +msgstr "" + +#: literals.py:124 +msgid "Raw green, blue, and red samples" +msgstr "" + +#: literals.py:125 +msgid "GIMP brush file" +msgstr "" + +#: literals.py:126 +msgid "CompuServe graphics interchange format (version 89a)" +msgstr "" + +#: literals.py:127 +msgid "CompuServe graphics interchange format (version 87a)" +msgstr "" + +#: literals.py:128 +msgid "Gradual passing from one shade to another" +msgstr "" + +#: literals.py:129 +msgid "Raw gray samples" +msgstr "" + +#: literals.py:130 +msgid "Raw green, red, and blue samples" +msgstr "" + +#: literals.py:131 +msgid "Raw CCITT Group4" +msgstr "" + +#: literals.py:133 +msgid "Histogram of the image" +msgstr "Histogram of the image" + +#: literals.py:134 +msgid "HRZ: Slow scan TV" +msgstr "HRZ: Slow scan TV" + +#: literals.py:135 literals.py:136 literals.py:255 +msgid "Hypertext Markup Language and a client-side image map" +msgstr "" + +#: literals.py:138 literals.py:264 literals.py:279 literals.py:283 +msgid "Truevision Targa image" +msgstr "Truevision Targa image" + +#: literals.py:139 literals.py:140 +msgid "ICC Color Profile" +msgstr "ICC Color Profile" + +#: literals.py:141 literals.py:142 +msgid "Microsoft Icon" +msgstr "Microsoft Icon" + +#: literals.py:143 +msgid "Hald CLUT identity image" +msgstr "Hald CLUT identity image" + +#: literals.py:144 +msgid "LabEye image format" +msgstr "LabEye image format" + +#: literals.py:145 +msgid "GraphicsMagick Embedded Image" +msgstr "GraphicsMagick Embedded Image" + +#: literals.py:146 +msgid "The image format and characteristics" +msgstr "" + +#: literals.py:147 +msgid "Base64-encoded inline images" +msgstr "" + +#: literals.py:148 +msgid "IPL Image Sequence" +msgstr "" + +#: literals.py:149 +msgid "IPTC Newsphoto" +msgstr "IPTC Newsphoto" + +#: literals.py:150 literals.py:151 +msgid "IPTC Newsphoto text format" +msgstr "IPTC Newsphoto text format" + +#: literals.py:152 +msgid "ISO/TR 11548-1 format" +msgstr "ISO/TR 11548-1 format" + +#: literals.py:154 literals.py:157 +msgid "JPEG-2000 Code Stream Syntax" +msgstr "JPEG-2000 Code Stream Syntax" + +#: literals.py:155 +msgid "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "JPEG Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" + +#: literals.py:156 +msgid "JPEG-2000 JP2 File Format Syntax" +msgstr "JPEG-2000 JP2 File Format Syntax" + +#: literals.py:158 literals.py:159 +msgid "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" +msgstr "Joint Photographic Experts Group JFIF format (IJG JPEG 62)" + +#: literals.py:160 +msgid "JPEG-2000 File Format Syntax" +msgstr "JPEG-2000 File Format Syntax" + +#: literals.py:162 +msgid "Raw black samples" +msgstr "" + +#: literals.py:163 literals.py:164 +msgid "Kodak Digital Camera Raw Image Format" +msgstr "Kodak Digital Camera Raw Image Format" + +#: literals.py:166 +msgid "Image label" +msgstr "" + +#: literals.py:168 +msgid "Raw magenta samples" +msgstr "" + +#: literals.py:169 literals.py:179 literals.py:182 literals.py:183 +msgid "MPEG Video Stream" +msgstr "MPEG Video Stream" + +#: literals.py:170 +msgid "Raw MPEG-4 Video" +msgstr "Raw MPEG-4 Video" + +#: literals.py:171 +msgid "Colormap intensities and indices" +msgstr "" + +#: literals.py:172 +msgid "MATLAB image format" +msgstr "MATLAB image format" + +#: literals.py:173 +msgid "MATTE raw opacity format" +msgstr "MATTE raw opacity format" + +#: literals.py:174 +msgid "8-bit McIdas area file" +msgstr "8-bit McIdas area file" + +#: literals.py:175 +msgid "Microsoft Image Composer (MIC) file" +msgstr "Microsoft Image Composer (MIC) file" + +#: literals.py:176 +msgid "Magick Image File Format" +msgstr "Magick Image File Format" + +#: literals.py:177 +msgid "" +"Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" + +#: literals.py:178 +msgid "Raw Bi-level bitmap in least-significant-byte first order" +msgstr "Raw Bi-level bitmap in least-significant-byte first order" + +#: literals.py:180 +msgid "MPEG-4 Video Stream" +msgstr "MPEG-4 Video Stream" + +#: literals.py:184 +msgid "Sony (Minolta) Raw Image File" +msgstr "Sony (Minolta) Raw Image File" + +#: literals.py:185 +msgid "Magick Scripting Language" +msgstr "Magick Scripting Language" + +#: literals.py:186 +msgid "Windows 1 and 2 MSP file format" +msgstr "Windows 1 and 2 MSP file format" + +#: literals.py:187 +msgid "ImageMagick's own SVG internal renderer" +msgstr "ImageMagick's own SVG internal renderer" + +#: literals.py:188 +msgid "MTV Raytracing image format" +msgstr "MTV Raytracing image format" + +#: literals.py:189 +msgid "Magick Vector Graphics" +msgstr "Magick Vector Graphics" + +#: literals.py:191 +msgid "Nikon Digital SLR Camera Raw Image File" +msgstr "Nikon Digital SLR Camera Raw Image File" + +#: literals.py:192 +msgid "Constant image of uniform color" +msgstr "Constant image of uniform color" + +#: literals.py:194 +msgid "Raw opacity samples" +msgstr "" + +#: literals.py:195 +msgid "Olympus Digital Camera Raw Image File" +msgstr "Olympus Digital Camera Raw Image File" + +#: literals.py:196 +msgid "On-the-air bitmap" +msgstr "" + +#: literals.py:197 +msgid "Open Type font (Freetype 2.4.2)" +msgstr "" + +#: literals.py:199 +msgid "Xv thumbnail format" +msgstr "" + +#: literals.py:200 literals.py:277 +msgid "16bit/pixel interleaved YUV" +msgstr "" + +#: literals.py:201 +msgid "Palm pixmap" +msgstr "" + +#: literals.py:202 +msgid "Common 2-dimensional bitmap format" +msgstr "" + +#: literals.py:203 +msgid "Predefined pattern" +msgstr "" + +#: literals.py:204 +msgid "Portable bitmap format (black and white)" +msgstr "" + +#: literals.py:205 literals.py:206 +msgid "Photo CD" +msgstr "" + +#: literals.py:207 +msgid "Page Control Language" +msgstr "" + +#: literals.py:208 literals.py:221 +msgid "Apple Macintosh QuickDraw/PICT" +msgstr "" + +#: literals.py:209 +msgid "ZSoft IBM PC Paintbrush" +msgstr "" + +#: literals.py:210 +msgid "Palm Database ImageViewer Format" +msgstr "" + +#: literals.py:211 +msgid "Portable Document Format" +msgstr "" + +#: literals.py:212 +msgid "Portable Document Archive Format" +msgstr "" + +#: literals.py:213 +msgid "Pentax Electronic File" +msgstr "" + +#: literals.py:214 +msgid "Embrid Embroidery Format" +msgstr "" + +#: literals.py:215 +msgid "Postscript Type 1 font (ASCII) (Freetype 2.4.2)" +msgstr "" + +#: literals.py:216 +msgid "Postscript Type 1 font (binary) (Freetype 2.4.2)" +msgstr "" + +#: literals.py:217 +msgid "Portable float format" +msgstr "" + +#: literals.py:218 +msgid "Portable graymap format (gray scale)" +msgstr "" + +#: literals.py:219 +msgid "JPEG-2000 VM Format" +msgstr "" + +#: literals.py:220 +msgid "Personal Icon" +msgstr "" + +#: literals.py:222 +msgid "Alias/Wavefront RLE image format" +msgstr "" + +#: literals.py:223 +msgid "PIXAR raster file" +msgstr "" + +#: literals.py:224 +msgid "Joint Photographic Experts Group JFIF format (62)" +msgstr "" + +#: literals.py:226 +msgid "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:227 +msgid "" +"24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:228 +msgid "" +"32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:229 +msgid "" +"8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " +"1.2.3.3,1.2.3.4)" +msgstr "" + +#: literals.py:230 +msgid "Portable anymap" +msgstr "" + +#: literals.py:231 +msgid "Portable pixmap format (color)" +msgstr "" + +#: literals.py:232 +msgid "Show a preview an image enhancement, effect, or f/x" +msgstr "" + +#: literals.py:233 +msgid "Adobe PostScript" +msgstr "" + +#: literals.py:234 +msgid "Adobe Level II PostScript" +msgstr "" + +#: literals.py:235 +msgid "Adobe Level III PostScript" +msgstr "" + +#: literals.py:236 +msgid "Adobe Large Document Format" +msgstr "" + +#: literals.py:237 +msgid "Adobe Photoshop bitmap" +msgstr "" + +#: literals.py:238 +msgid "Pyramid encoded TIFF" +msgstr "" + +#: literals.py:239 literals.py:253 +msgid "Seattle Film Works" +msgstr "" + +#: literals.py:241 +msgid "Raw red samples" +msgstr "" + +#: literals.py:242 +msgid "Fuji CCD-RAW Graphic File" +msgstr "Fuji CCD-RAW Graphic File" + +#: literals.py:243 literals.py:259 +msgid "SUN Rasterfile" +msgstr "SUN Rasterfile" + +#: literals.py:244 +msgid "Raw red, blue, and green samples" +msgstr "" + +#: literals.py:245 +msgid "Raw red, green, and blue samples" +msgstr "" + +#: literals.py:246 +msgid "Raw red, green, blue, and matte samples" +msgstr "" + +#: literals.py:247 +msgid "Raw red, green, blue, and opacity samples" +msgstr "" + +#: literals.py:248 +msgid "Alias/Wavefront image" +msgstr "Alias/Wavefront image" + +#: literals.py:249 +msgid "Utah Run length encoded image" +msgstr "Utah Run length encoded image" + +#: literals.py:251 +msgid "ZX-Spectrum SCREEN$" +msgstr "" + +#: literals.py:252 +msgid "Scitex HandShake" +msgstr "Scitex HandShake" + +#: literals.py:254 +msgid "Irix RGB image" +msgstr "" + +#: literals.py:256 +msgid "Sony Raw Format 2" +msgstr "Sony Raw Format 2" + +#: literals.py:257 +msgid "Sony Raw Format" +msgstr "Sony Raw Format" + +#: literals.py:258 +msgid "Steganographic image" +msgstr "" + +#: literals.py:260 +msgid "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" +msgstr "Scalable Vector Graphics (XML 2.7.6, RSVG 2.32.0)" + +#: literals.py:261 +msgid "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" +msgstr "Scalable Vector Graphics (ZIP compressed) (XML 2.7.6, RSVG 2.32.0)" + +#: literals.py:263 literals.py:273 +msgid "Text" +msgstr "" + +#: literals.py:265 +msgid "EXIF Profile Thumbnail" +msgstr "" + +#: literals.py:266 +msgid "Tagged Image File Format (LIBTIFF, Version 3.9.4)" +msgstr "Tagged Image File Format (LIBTIFF, Version 3.9.4)" + +#: literals.py:267 +msgid "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" +msgstr "Tagged Image File Format (64-bit) (LIBTIFF, Version 3.9.4)" + +#: literals.py:268 +msgid "Tile image with a texture" +msgstr "" + +#: literals.py:269 +msgid "PSX TIM" +msgstr "PSX TIM" + +#: literals.py:270 +msgid "TOPOL X Image" +msgstr "TOPOL X Image" + +#: literals.py:271 +msgid "TrueType font collection (Freetype 2.4.2)" +msgstr "TrueType font collection (Freetype 2.4.2)" + +#: literals.py:272 +msgid "TrueType font (Freetype 2.4.2)" +msgstr "TrueType font (Freetype 2.4.2)" + +#: literals.py:275 +msgid "Unicode Text format" +msgstr "" + +#: literals.py:276 +msgid "X-Motif UIL table" +msgstr "X-Motif UIL table" + +#: literals.py:280 +msgid "VICAR rasterfile format" +msgstr "VICAR rasterfile format" + +#: literals.py:281 +msgid "Visual Image Directory" +msgstr "" + +#: literals.py:282 literals.py:299 +msgid "Khoros Visualization image" +msgstr "Khoros Visualization image" + +#: literals.py:285 +msgid "Wireless Bitmap (level 0) image" +msgstr "Wireless Bitmap (level 0) image" + +#: literals.py:286 +msgid "Windows Meta File" +msgstr "Windows Meta File" + +#: literals.py:287 +msgid "Word Perfect Graphics" +msgstr "Word Perfect Graphics" + +#: literals.py:288 +msgid "Windows Media Video" +msgstr "Windows Media Video" + +#: literals.py:289 +msgid "Compressed Windows Meta File" +msgstr "Compressed Windows Meta File" + +#: literals.py:291 +msgid "X Window System" +msgstr "" + +#: literals.py:292 +msgid "Foveon X3 (Sigma/Polaroid) Raw picture file" +msgstr "Foveon X3 (Sigma/Polaroid) Raw picture file" + +#: literals.py:293 +msgid "X Windows system bitmap (black and white)" +msgstr "X Windows system bitmap (black and white)" + +#: literals.py:294 +msgid "Constant image uniform color" +msgstr "" + +#: literals.py:295 +msgid "GIMP image" +msgstr "GIMP image" + +#: literals.py:296 +msgid "Adobe XML metadata" +msgstr "Adobe XML metadata" + +#: literals.py:297 +msgid "X Windows system pixmap (color)" +msgstr "" + +#: literals.py:298 +msgid "Microsoft XML Paper Specification" +msgstr "" + +#: literals.py:300 +msgid "XV thumbnail file" +msgstr "" + +#: literals.py:301 +msgid "X Windows system window dump (color)" +msgstr "" + +#: literals.py:303 +msgid "Raw yellow samples" +msgstr "" + +#: literals.py:304 +msgid "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" +msgstr "CCIR 601 4:1:1 or 4:2:2 (8-bit only)" + +#: views.py:17 +msgid "suported file formats" +msgstr "" + +#: views.py:22 +msgid "name" +msgstr "nazwa" + +#: views.py:26 +msgid "description" +msgstr "opis" + +#: conf/settings.py:11 +msgid "File path to imagemagick's convert program." +msgstr "" + +#: conf/settings.py:12 +msgid "File path to imagemagick's identify program." +msgstr "" + +#: conf/settings.py:13 +msgid "File path to graphicsmagick's program." +msgstr "" + +#: conf/settings.py:15 +msgid "" +"Graphics conversion backend to use. Options are: " +"converter.backends.imagemagick, converter.backends.graphicsmagick and " +"converter.backends.python." +msgstr "" + +#: conf/settings.py:16 +msgid "Path to the unoconv program." +msgstr "" + +#: conf/settings.py:17 +msgid "" +"Use alternate method of connection to LibreOffice using a pipe, it is slower" +" but less prone to segmentation faults." +msgstr "" + +#: templates/converter_file_formats_help.html:3 +msgid "Help" +msgstr "" + +#: templates/converter_file_formats_help.html:4 +#, python-format +msgid "" +"These are the file formats supported by the currently selected converter " +"backend. In this case: '%(backend)s'" +msgstr "" diff --git a/apps/django_gpg/locale/pl/LC_MESSAGES/django.po b/apps/django_gpg/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..ba61b51c10 --- /dev/null +++ b/apps/django_gpg/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,215 @@ +# 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:34+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:14 views.py:67 +msgid "private keys" +msgstr "private keys" + +#: __init__.py:15 views.py:70 +msgid "public keys" +msgstr "public keys" + +#: __init__.py:16 +msgid "delete" +msgstr "usunąć" + +#: __init__.py:17 +msgid "query keyservers" +msgstr "query keyservers" + +#: __init__.py:18 +msgid "import" +msgstr "import" + +#: __init__.py:19 +msgid "key management" +msgstr "zarządzanie kluczami" + +#: api.py:19 +msgid "Public" +msgstr "Publiczny" + +#: api.py:20 +msgid "Secret" +msgstr "Secret" + +#: api.py:28 api.py:33 +msgid "RSA" +msgstr "RSA" + +#: api.py:29 +msgid "DSA" +msgstr "DSA" + +#: api.py:34 +msgid "Elgamal" +msgstr "Elgamal" + +#: api.py:48 +msgid "Bad signature." +msgstr "Zły podpis." + +#: api.py:52 +msgid "Document not signed or invalid signature." +msgstr "Dokumentu nie podpisany lub nieprawidłowy podpis." + +#: api.py:56 +msgid "Signature error." +msgstr "Błąd podpisu." + +#: api.py:60 +msgid "Document is signed but no public key is available for verification." +msgstr "Dokument został podpisany, ale klucz publiczny nie jest dostępny do weryfikacji." + +#: api.py:64 +msgid "Document is signed, and signature is good." +msgstr "Dokument został podpisany, a podpis jest dobry." + +#: api.py:68 +msgid "Document is signed with a valid signature." +msgstr "Dokument podpisany za pomocą ważnego podpisu." + +#: api.py:141 +msgid "unknown" +msgstr "nieznany" + +#: forms.py:8 +msgid "Term" +msgstr "Term" + +#: forms.py:9 +msgid "Name, e-mail, key ID or key fingerprint to look for." +msgstr "Imię i nazwisko, e-mail, key ID lub key fingerprint kluc szukać." + +#: permissions.py:7 +msgid "Key management" +msgstr "Zarządzanie kluczami" + +#: permissions.py:9 +msgid "View keys" +msgstr "View keys" + +#: permissions.py:10 +msgid "Delete keys" +msgstr "Delete keys" + +#: permissions.py:11 +msgid "Query keyservers" +msgstr "Query keyservers" + +#: permissions.py:12 +msgid "Import keys from keyservers" +msgstr "Import keys from keyservers" + +#: views.py:38 +#, python-format +msgid "Key: %s, imported successfully." +msgstr "Klucz:%s, zaimportowany." + +#: views.py:43 +#, python-format +msgid "Unable to import key id: %(key_id)s; %(error)s" +msgstr "Nie można zaimportować ID klucza: %(key_id)s ; %(error)s " + +#: views.py:52 +msgid "Import key" +msgstr "Importuj klucz" + +#: views.py:53 +#, python-format +msgid "Are you sure you wish to import key id: %s?" +msgstr "Czy na pewno chcesz importować ID klucza:%s?" + +#: views.py:78 +msgid "Key ID" +msgstr "Key ID" + +#: views.py:82 +msgid "Owner" +msgstr "Właściciel" + +#: views.py:102 +#, python-format +msgid "Key: %s, deleted successfully." +msgstr "Klucz:%s, został usunięty." + +#: views.py:109 +msgid "Delete key" +msgstr "Usuń klucz" + +#: views.py:111 +#, python-format +msgid "" +"Are you sure you wish to delete key: %s? If you try to delete a public key " +"that is part of a public/private pair the private key will be deleted as " +"well." +msgstr "Czy na pewno chcesz usunąć klucz:%s? Jeśli próbujesz usunąć klucza publiczny, który jest częścią pary publiczny / prywatny klucz prywatny zostanie usunięty również." + +#: views.py:129 +msgid "Query key server" +msgstr "Query key server" + +#: views.py:142 +msgid "results" +msgstr "wyniki" + +#: views.py:147 +msgid "ID" +msgstr "ID" + +#: views.py:151 +msgid "type" +msgstr "typ" + +#: views.py:155 +msgid "creation date" +msgstr "creation date" + +#: views.py:159 +msgid "disabled" +msgstr "wyłączone" + +#: views.py:163 +msgid "expiration date" +msgstr "data ważności" + +#: views.py:167 +msgid "expired" +msgstr "wygasł" + +#: views.py:171 +msgid "length" +msgstr "długość" + +#: views.py:175 +msgid "revoked" +msgstr "odwołany" + +#: views.py:180 +msgid "Identifies" +msgstr "Identyfikuje" + +#: conf/settings.py:15 +msgid "List of keyservers to be queried for unknown keys." +msgstr "List of keyservers to be queried for unknown keys." + +#: conf/settings.py:16 +msgid "Home directory used to store keys as well as configuration files." +msgstr "Katalog domowy używany do przechowywania kluczy oraz plików konfiguracyjnych." diff --git a/apps/document_comments/locale/pl/LC_MESSAGES/django.po b/apps/document_comments/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..45c3f93de1 --- /dev/null +++ b/apps/document_comments/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,99 @@ +# 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-21 14:50+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 __init__.py:20 +msgid "delete" +msgstr "usunąć" + +#: __init__.py:21 +msgid "add comment" +msgstr "dodaj komentarz" + +#: __init__.py:22 +msgid "comments" +msgstr "komentarze" + +#: __init__.py:26 +msgid "date" +msgstr "data" + +#: __init__.py:30 +msgid "user" +msgstr "użytkownik" + +#: __init__.py:34 +msgid "comment" +msgstr "komentarz" + +#: permissions.py:7 +msgid "Comments" +msgstr "Komentarze" + +#: permissions.py:9 +msgid "Create new comments" +msgstr "Tworzenie nowych komentarzy" + +#: permissions.py:10 +msgid "Delete comments" +msgstr "Usuń komentarzy" + +#: permissions.py:11 +msgid "View comments" +msgstr "Zobacz komentarze" + +#: views.py:36 +msgid "Must provide at least one comment." +msgstr "Musi podać co najmniej jeden komentarz." + +#: views.py:46 +#, python-format +msgid "Comment \"%s\" deleted successfully." +msgstr "Komentarz \"%s\" został usunięta." + +#: views.py:48 +#, python-format +msgid "Error deleting comment \"%(comment)s\": %(error)s" +msgstr "Błąd podczas usuwania komentarza \" %(comment)s \": %(error)s" + +#: views.py:63 +#, python-format +msgid "Are you sure you wish to delete the comment: %s?" +msgstr "Czy na pewno chcesz usunąć komentarz:%s?" + +#: views.py:65 +#, python-format +msgid "Are you sure you wish to delete the comments: %s?" +msgstr "Czy na pewno chcesz usunąć komentarze:%s?" + +#: views.py:99 +msgid "Comment added successfully." +msgstr "Komentarz został dodany pomyślnie." + +#: views.py:106 +#, python-format +msgid "Add comment to document: %s" +msgstr "Dodaj komentarz do dokumentu:%s" + +#: views.py:126 +#, python-format +msgid "comments: %s" +msgstr "komentarze: %s" diff --git a/apps/document_indexing/locale/pl/LC_MESSAGES/django.po b/apps/document_indexing/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..5570eb9949 --- /dev/null +++ b/apps/document_indexing/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,364 @@ +# 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:50+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:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 +#: views.py:280 +msgid "indexes" +msgstr "indeksy" + +#: __init__.py:32 __init__.py:42 +msgid "index list" +msgstr "Lista główna" + +#: __init__.py:33 views.py:74 +msgid "create index" +msgstr "tworzenie indeksu" + +#: __init__.py:34 __init__.py:39 +msgid "edit" +msgstr "edytuj" + +#: __init__.py:35 __init__.py:40 +msgid "delete" +msgstr "usunąć" + +#: __init__.py:36 +msgid "tree template" +msgstr "szablon drzewo" + +#: __init__.py:38 +msgid "new child node" +msgstr "new child node" + +#: __init__.py:44 +msgid "go up one level" +msgstr "przejść o jeden poziom" + +#: __init__.py:49 +msgid "rebuild indexes" +msgstr "odbudować indeksy" + +#: __init__.py:49 +msgid "Deletes and creates from scratch all the document indexes." +msgstr "Usuwa i tworzy od podstaw wszystkie indeksy dokumentów." + +#: __init__.py:51 +msgid "Indexes" +msgstr "Indeksy" + +#: api.py:71 +#, python-format +msgid "Maximum suffix (%s) count reached." +msgstr "Maximum suffix (%s) count reached." + +#: api.py:85 +#, python-format +msgid "" +"Error in document indexing update expression: %(expression)s; %(exception)s" +msgstr "Error in document indexing update expression: %(expression)s; %(exception)s" + +#: api.py:96 api.py:111 +#, python-format +msgid "" +"Error updating document index, expression: %(expression)s; %(exception)s" +msgstr "Error updating document index, expression: %(expression)s; %(exception)s" + +#: api.py:150 +#, python-format +msgid "Unable to delete document indexing node; %s" +msgstr "Unable to delete document indexing node; %s" + +#: filesystem.py:51 +#, python-format +msgid "Unable to create indexing directory; %s" +msgstr "Nie można utworzyć katalogu indeksowania;%s" + +#: filesystem.py:69 +#, python-format +msgid "" +"Unable to create symbolic link, file exists and could not be deleted: " +"%(filepath)s; %(exc)s" +msgstr "Nie można utworzyć dowiązania symbolicznego, plik istnieje i nie może zostać usunięty: %(filepath)s ; %(exc)s " + +#: filesystem.py:71 +#, python-format +msgid "Unable to create symbolic link: %(filepath)s; %(exc)s" +msgstr "Nie można utworzyć dowiązania symbolicznego: %(filepath)s; %(exc)s " + +#: filesystem.py:84 +#, python-format +msgid "Unable to delete document symbolic link; %s" +msgstr "Nie można usunąć dowiązania symbolicznego dokumentu;%s" + +#: filesystem.py:96 +#, python-format +msgid "Unable to delete indexing directory; %s" +msgstr "Nie można usunąć katalogu indeksowania;%s" + +#: models.py:13 +#, python-format +msgid "Available functions: %s" +msgstr "Dostępne funkcje:%s" + +#: models.py:17 views.py:40 +msgid "name" +msgstr "nazwa" + +#: models.py:17 +msgid "Internal name used to reference this index." +msgstr "Wewnętrzna nazwa używana do odniesienia tego indeksu." + +#: models.py:18 views.py:41 +msgid "title" +msgstr "tytuł" + +#: models.py:18 +msgid "The name that will be visible to users." +msgstr "Nazwa, która będzie widoczna dla użytkowników." + +#: models.py:19 models.py:50 +msgid "enabled" +msgstr "włączony" + +#: models.py:19 +msgid "" +"Causes this index to be visible and updated when document data changes." +msgstr "Powoduje że ten wskaźnik będzie widoczny i zaktualizowany podczas zmiany danych dokumentów." + +#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 +#: views.py:195 views.py:225 views.py:265 +msgid "index" +msgstr "index" + +#: models.py:48 +msgid "indexing expression" +msgstr "indexing expression" + +#: models.py:48 +msgid "Enter a python string expression to be evaluated." +msgstr "Enter a python string expression to be evaluated." + +#: models.py:50 +msgid "Causes this node to be visible and updated when document data changes." +msgstr "Causes this node to be visible and updated when document data changes." + +#: models.py:51 +msgid "link documents" +msgstr "link documents" + +#: models.py:51 +msgid "" +"Check this option to have this node act as a container for documents and not" +" as a parent for further nodes." +msgstr "Check this option to have this node act as a container for documents and not as a parent for further nodes." + +#: models.py:57 models.py:63 +msgid "index template node" +msgstr "index template node" + +#: models.py:58 +msgid "indexes template nodes" +msgstr "indexes template nodes" + +#: models.py:64 +msgid "value" +msgstr "wartość" + +#: models.py:65 +msgid "documents" +msgstr "dokumenty" + +#: models.py:75 +msgid "index instance node" +msgstr "index instance node" + +#: models.py:76 +msgid "indexes instance nodes" +msgstr "indexes instance nodes" + +#: models.py:80 +msgid "index instance" +msgstr "index instance" + +#: models.py:81 +msgid "document" +msgstr "dokument" + +#: models.py:88 +msgid "document rename count" +msgstr "document rename count" + +#: models.py:89 +msgid "documents rename count" +msgstr "documents rename count" + +#: permissions.py:7 +msgid "Indexing" +msgstr "Indeksowanie" + +#: permissions.py:9 +msgid "Configure document indexes" +msgstr "Skonfiguruj indeksy dokumentów" + +#: permissions.py:10 +msgid "Create new document indexes" +msgstr "Tworzenie nowych indeksów dokumentów" + +#: permissions.py:11 +msgid "Edit document indexes" +msgstr "Edytuj indeksy dokumentów" + +#: permissions.py:12 +msgid "Delete document indexes" +msgstr "Usuń indeksy dokumentów" + +#: permissions.py:14 +msgid "View document indexes" +msgstr "Zobacz indeksy dokumentów" + +#: permissions.py:15 +msgid "Rebuild document indexes" +msgstr "Odbuduj indeksy dokumentów" + +#: utils.py:19 +msgid "document indexes" +msgstr "Indeksy dokumentów" + +#: views.py:68 +msgid "Index created successfully." +msgstr "Indeks został utworzony pomyślnie." + +#: views.py:92 +msgid "Index edited successfully" +msgstr "Index edited successfully" + +#: views.py:98 +#, python-format +msgid "edit index: %s" +msgstr "edycja indeksu:%s" + +#: views.py:123 +#, python-format +msgid "Index: %s deleted successfully." +msgstr "Index:%s został usunięty." + +#: views.py:125 +#, python-format +msgid "Index: %(index)s delete error: %(error)s" +msgstr "Index: %(index)s błąd usuwania: %(error)s " + +#: views.py:137 +#, python-format +msgid "Are you sure you with to delete the index: %s?" +msgstr "Czy na pewno usunąć indeks:%s ?" + +#: views.py:162 +#, python-format +msgid "tree template nodes for index: %s" +msgstr "tree template nodes for index: %s" + +#: views.py:165 +msgid "level" +msgstr "level" + +#: views.py:186 +msgid "Index template node created successfully." +msgstr "Index template node created successfully." + +#: views.py:192 +msgid "create child node" +msgstr "create child node" + +#: views.py:213 +msgid "Index template node edited successfully" +msgstr "Index template node edited successfully" + +#: views.py:219 +#, python-format +msgid "edit index template node: %s" +msgstr "" + +#: views.py:226 views.py:266 views.py:334 +msgid "node" +msgstr "node" + +#: views.py:248 +#, python-format +msgid "Node: %s deleted successfully." +msgstr "" + +#: views.py:250 +#, python-format +msgid "Node: %(node)s delete error: %(error)s" +msgstr "" + +#: views.py:259 +#, python-format +msgid "Are you sure you with to delete the index template node: %s?" +msgstr "" + +#: views.py:283 +msgid "nodes" +msgstr "" + +#: views.py:316 +#, python-format +msgid "contents for index: %s" +msgstr "Zawartość dla indeksu:%s" + +#: views.py:338 +msgid "items" +msgstr "pozycji" + +#: views.py:363 +msgid "Are you sure you wish to rebuild all indexes?" +msgstr "Czy na pewno chcesz odbudować wszystkie indeksy?" + +#: views.py:364 +msgid "On large databases this operation may take some time to execute." +msgstr "Na dużych bazach danych operacja może chwilę potrwać." + +#: views.py:370 +msgid "Index rebuild completed successfully." +msgstr "Główna odbudowa zakończyła się pomyślnie." + +#: views.py:375 +#, python-format +msgid "Index rebuild error: %s" +msgstr "Index rebuild error: %s" + +#: views.py:397 +#, python-format +msgid "indexes containing: %s" +msgstr "indeksy zawierające:%s" + +#: conf/settings.py:22 +msgid "" +"A dictionary that maps the index name and where on the filesystem that index" +" will be mirrored." +msgstr "" + +#: templates/indexing_help.html:3 +msgid "What are indexes?" +msgstr "Jakie są indeksy?" + +#: templates/indexing_help.html:4 +msgid "Indexes group documents into a tree like hierarchical structure." +msgstr "Indexes group documents into a tree like hierarchical structure." diff --git a/apps/document_signatures/locale/pl/LC_MESSAGES/django.po b/apps/document_signatures/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..48ad7c7e0a --- /dev/null +++ b/apps/document_signatures/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,123 @@ +# 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:53+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:83 +msgid "upload signature" +msgstr "upload signature" + +#: __init__.py:84 +msgid "download signature" +msgstr "download signature" + +#: __init__.py:85 +msgid "signatures" +msgstr "signatures" + +#: forms.py:11 +msgid "Signature file" +msgstr "Signature file" + +#: models.py:20 +msgid "document version" +msgstr "document version" + +#: models.py:21 +msgid "signature file" +msgstr "signature file" + +#: models.py:22 +msgid "has embedded signature" +msgstr "has embedded signature" + +#: models.py:35 +msgid "document version signature" +msgstr "document version signature" + +#: models.py:36 +msgid "document version signatures" +msgstr "document version signatures" + +#: permissions.py:7 +msgid "Document signatures" +msgstr "Document signatures" + +#: permissions.py:8 +msgid "Verify document signatures" +msgstr "Verify document signatures" + +#: permissions.py:9 +msgid "Upload detached signatures" +msgstr "Upload detached signatures" + +#: permissions.py:10 +msgid "Download detached signatures" +msgstr "Download detached signatures" + +#: views.py:47 +#, python-format +msgid "Signature status: %(widget)s %(text)s" +msgstr "Signature status: %(widget)s %(text)s" + +#: views.py:54 +msgid "embedded" +msgstr "embedded" + +#: views.py:56 +msgid "detached" +msgstr "detached" + +#: views.py:61 +#, python-format +msgid "Signature ID: %s" +msgstr "Signature ID: %s" + +#: views.py:62 +#, python-format +msgid "Signature type: %s" +msgstr "Signature type: %s" + +#: views.py:63 +#, python-format +msgid "Key ID: %s" +msgstr "Key ID: %s" + +#: views.py:64 +#, python-format +msgid "Timestamp: %s" +msgstr "Timestamp: %s" + +#: views.py:65 +#, python-format +msgid "Signee: %s" +msgstr "Signee: %s" + +#: views.py:70 +#, python-format +msgid "signature properties for: %s" +msgstr "signature properties for: %s" + +#: views.py:96 +msgid "Detached signature uploaded successfully." +msgstr "Detached signature uploaded successfully." + +#: views.py:105 +#, python-format +msgid "Upload detached signature for: %s" +msgstr "Upload detached signature for: %s" diff --git a/apps/documents/locale/pl/LC_MESSAGES/django.po b/apps/documents/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..df45fa6674 --- /dev/null +++ b/apps/documents/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,1096 @@ +# 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-21 21:09+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:63 +msgid "all documents" +msgstr "wszystkie dokumenty" + +#: __init__.py:64 models.py:653 views.py:871 +msgid "recent documents" +msgstr "ostatnie dokumenty" + +#: __init__.py:65 +msgid "upload new documents" +msgstr "wgrać nowe dokumenty" + +#: __init__.py:66 +msgid "clone metadata" +msgstr "clone metadata" + +#: __init__.py:67 +msgid "details" +msgstr "szczegóły" + +#: __init__.py:68 +msgid "properties" +msgstr "właściwości" + +#: __init__.py:69 __init__.py:70 __init__.py:92 __init__.py:116 +#: __init__.py:122 +msgid "delete" +msgstr "usunąć" + +#: __init__.py:71 __init__.py:91 __init__.py:115 __init__.py:121 +msgid "edit" +msgstr "edit" + +#: __init__.py:72 +msgid "preview" +msgstr "podgląd" + +#: __init__.py:73 __init__.py:74 __init__.py:75 +msgid "download" +msgstr "pobierz" + +#: __init__.py:76 +msgid "find duplicates" +msgstr "znaleźć duplikaty" + +#: __init__.py:77 +msgid "find all duplicates" +msgstr "znaleźć wszystkie duplikaty" + +#: __init__.py:77 +msgid "" +"Search all the documents' checksums and return a list of the exact matches." +msgstr "Search all the documents' checksums and return a list of the exact matches." + +#: __init__.py:78 +msgid "update office documents' page count" +msgstr "" + +#: __init__.py:78 +msgid "" +"Update the page count of the office type documents. This is useful when " +"enabling office document support after there were already office type " +"documents in the database." +msgstr "" + +#: __init__.py:79 __init__.py:80 +msgid "clear transformations" +msgstr "" + +#: __init__.py:81 +msgid "print" +msgstr "drukuj" + +#: __init__.py:82 +msgid "history" +msgstr "historia" + +#: __init__.py:83 +msgid "Find missing document files" +msgstr "" + +#: __init__.py:86 +msgid "Clear the document image cache" +msgstr "" + +#: __init__.py:86 +msgid "" +"Clear the graphics representations used to speed up the documents' display " +"and interactive transformations results." +msgstr "" + +#: __init__.py:89 +msgid "page transformations" +msgstr "" + +#: __init__.py:90 +msgid "create new transformation" +msgstr "" + +#: __init__.py:94 +msgid "page image" +msgstr "obraz strony" + +#: __init__.py:95 +msgid "page text" +msgstr "page text" + +#: __init__.py:96 +msgid "edit page text" +msgstr "" + +#: __init__.py:97 +msgid "next page" +msgstr "następna strona" + +#: __init__.py:98 +msgid "previous page" +msgstr "poprzednia strona" + +#: __init__.py:99 +msgid "first page" +msgstr "pierwsza strona" + +#: __init__.py:100 +msgid "last page" +msgstr "ostatnia strona" + +#: __init__.py:101 +msgid "zoom in" +msgstr "powiększ" + +#: __init__.py:102 +msgid "zoom out" +msgstr "pomniejszyć" + +#: __init__.py:103 +msgid "rotate right" +msgstr "obrót w prawo" + +#: __init__.py:104 +msgid "rotate left" +msgstr "obrót w lewo" + +#: __init__.py:105 +msgid "reset view" +msgstr "resetuj widok" + +#: __init__.py:108 +msgid "versions" +msgstr "wersje" + +#: __init__.py:109 +msgid "revert" +msgstr "przywróć" + +#: __init__.py:112 +msgid "document type list" +msgstr "" + +#: __init__.py:113 views.py:1050 +msgid "document types" +msgstr "typy dokumentów" + +#: __init__.py:114 +msgid "documents of this type" +msgstr "" + +#: __init__.py:117 views.py:1161 +msgid "create document type" +msgstr "" + +#: __init__.py:119 +msgid "filenames" +msgstr "nazwy plików" + +#: __init__.py:120 +msgid "add filename to document type" +msgstr "" + +#: __init__.py:164 permissions.py:7 +msgid "Documents" +msgstr "Dokumenty" + +#: __init__.py:166 __init__.py:179 models.py:90 views.py:79 +msgid "documents" +msgstr "dokumenty" + +#: __init__.py:169 +msgid "thumbnail" +msgstr "miniatura" + +#: __init__.py:172 +msgid "metadata" +msgstr "metadane" + +#: forms.py:63 +msgid "Page image" +msgstr "Obraz strony" + +#: forms.py:73 forms.py:270 +msgid "Contents" +msgstr "Zawartość" + +#: forms.py:109 +msgid "Page" +msgstr "Strona" + +#: forms.py:121 +msgid "Details" +msgstr "Szczegóły" + +#: forms.py:126 +msgid "Click on the image for full size preview" +msgstr "" + +#: forms.py:136 +#, python-format +msgid "Document pages (%s)" +msgstr "" + +#: forms.py:162 +msgid "Use the new version filename as the document filename" +msgstr "" + +#: forms.py:178 +msgid "Quick document rename" +msgstr "" + +#: forms.py:185 +msgid "Version update" +msgstr "Version update" + +#: forms.py:190 +msgid "Release level" +msgstr "Release level" + +#: forms.py:196 +msgid "Release level serial" +msgstr "Release level serial" + +#: forms.py:204 +msgid "Comment" +msgstr "Komentarz" + +#: forms.py:210 +msgid "New document filename" +msgstr "Nowa nazwa dokumentu" + +#: forms.py:288 +msgid "Page range" +msgstr "Zakres strony" + +#: forms.py:318 +msgid "Compress" +msgstr "Kompresuj" + +#: forms.py:318 +msgid "" +"Download the document in the original format or in a compressed manner. " +"This option is selectable only when downloading one document, for multiple " +"documents, the bundle will always be downloads as a compressed file." +msgstr "" + +#: literals.py:10 +msgid "Document creation" +msgstr "" + +#: literals.py:11 +#, python-format +msgid "Document \"%(content_object)s\" created by %(fullname)s." +msgstr "" + +#: literals.py:12 +#, python-format +msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "" + +#: literals.py:18 +msgid "Document edited" +msgstr "Dokument edytowany" + +#: literals.py:19 +#, python-format +msgid "Document \"%(content_object)s\" edited by %(fullname)s." +msgstr "" + +#: literals.py:20 +#, python-format +msgid "" +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." +" The following changes took place: %(changes)s." +msgstr "" + +#: literals.py:29 +msgid "Document deleted" +msgstr "Dokument usunięty" + +#: literals.py:30 +#, python-format +msgid "Document \"%(document)s\" deleted by %(fullname)s." +msgstr "" + +#: literals.py:31 +#, python-format +msgid "Document \"%(document)s\" deleted on %(datetime)s by %(fullname)s." +msgstr "" + +#: literals.py:42 +msgid "final" +msgstr "final" + +#: literals.py:43 +msgid "alpha" +msgstr "alpha" + +#: literals.py:44 +msgid "beta" +msgstr "beta" + +#: literals.py:45 +msgid "release candidate" +msgstr "release candidate" + +#: literals.py:46 +msgid "hotfix" +msgstr "hotfix" + +#: models.py:61 +msgid "name" +msgstr "nazwa" + +#: models.py:67 models.py:77 models.py:524 views.py:1068 views.py:1097 +#: views.py:1126 views.py:1131 views.py:1174 views.py:1220 views.py:1254 +msgid "document type" +msgstr "typ dokumentu" + +#: models.py:68 +msgid "documents types" +msgstr "typy dokumentów" + +#: models.py:78 +msgid "description" +msgstr "opis" + +#: models.py:79 +msgid "added" +msgstr "dodana" + +#: models.py:89 models.py:300 models.py:642 models.py:657 views.py:227 +#: views.py:351 +msgid "document" +msgstr "dokument" + +#: models.py:287 +#, python-format +msgid "Major %(major)i.%(minor)i, (new release)" +msgstr "Major %(major)i.%(minor)i, (new release)" + +#: models.py:288 +#, python-format +msgid "Minor %(major)i.%(minor)i, (some updates)" +msgstr "Minor %(major)i.%(minor)i, (some updates)" + +#: models.py:289 +#, python-format +msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" +msgstr "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" + +#: models.py:301 +msgid "mayor" +msgstr "mayor" + +#: models.py:302 +msgid "minor" +msgstr "minor" + +#: models.py:303 +msgid "micro" +msgstr "micro" + +#: models.py:304 +msgid "release level" +msgstr "release level" + +#: models.py:305 +msgid "serial" +msgstr "serial" + +#: models.py:306 +msgid "timestamp" +msgstr "timestamp" + +#: models.py:307 views.py:1357 +msgid "comment" +msgstr "komentarz" + +#: models.py:310 +msgid "file" +msgstr "plik" + +#: models.py:314 +msgid "checksum" +msgstr "suma kontrolna" + +#: models.py:318 models.py:319 models.py:542 +msgid "document version" +msgstr "wersja dokumentu" + +#: models.py:411 +msgid "" +"This document's file format is not known, the page count has therefore " +"defaulted to 1." +msgstr "" + +#: models.py:525 views.py:1353 +msgid "filename" +msgstr "nazwa_pliku" + +#: models.py:526 views.py:1181 +msgid "enabled" +msgstr "włączony" + +#: models.py:533 +msgid "document type quick rename filename" +msgstr "" + +#: models.py:534 +msgid "document types quick rename filenames" +msgstr "" + +#: models.py:545 +msgid "content" +msgstr "zawartość" + +#: models.py:546 +msgid "page label" +msgstr "etykieta strony" + +#: models.py:547 +msgid "page number" +msgstr "numer strony" + +#: models.py:550 +#, python-format +msgid "Page %(page_num)d out of %(total_pages)d of %(document)s" +msgstr "" + +#: models.py:558 models.py:604 +msgid "document page" +msgstr "" + +#: models.py:559 +msgid "document pages" +msgstr "" + +#: models.py:579 +msgid "Enter a valid value." +msgstr "Wprowadź poprawną wartość." + +#: models.py:605 views.py:449 +msgid "order" +msgstr "kolejność" + +#: models.py:606 views.py:450 views.py:511 views.py:542 +msgid "transformation" +msgstr "transformacja" + +#: models.py:607 views.py:451 +msgid "arguments" +msgstr "argumenty" + +#: models.py:607 +#, python-format +msgid "Use dictionaries to indentify arguments, example: %s" +msgstr "" + +#: models.py:615 +msgid "document page transformation" +msgstr "" + +#: models.py:616 +msgid "document page transformations" +msgstr "" + +#: models.py:641 +msgid "user" +msgstr "użytkownik" + +#: models.py:643 +msgid "accessed" +msgstr "dostępne" + +#: models.py:652 +msgid "recent document" +msgstr "ostatni dokument" + +#: models.py:658 +msgid "Document type" +msgstr "Typ dokumentu" + +#: models.py:659 +msgid "MIME type" +msgstr "typ MIME" + +#: models.py:660 views.py:132 +msgid "Filename" +msgstr "Nazwa pliku" + +#: models.py:661 +msgid "Metadata value" +msgstr "" + +#: models.py:662 +msgid "Content" +msgstr "Zawartość" + +#: models.py:663 +msgid "Description" +msgstr "Opis" + +#: models.py:664 +msgid "Tags" +msgstr "Tagi" + +#: models.py:665 +msgid "Comments" +msgstr "Komentarze" + +#: permissions.py:9 +msgid "Create documents" +msgstr "Tworzenie dokumentów" + +#: permissions.py:10 +msgid "Edit document properties" +msgstr "Edytuj właściwości dokumentu" + +#: permissions.py:11 +msgid "Edit documents" +msgstr "Edycja dokumentów" + +#: permissions.py:12 +msgid "View documents" +msgstr "Zobacz dokumenty" + +#: permissions.py:13 +msgid "Delete documents" +msgstr "Usuwanie dokumentów" + +#: permissions.py:14 views.py:408 +msgid "Download documents" +msgstr "Pobierz dokumenty" + +#: permissions.py:15 +msgid "Transform documents" +msgstr "Przekształcać dokumenty" + +#: permissions.py:16 +msgid "Execute document modifying tools" +msgstr "" + +#: permissions.py:17 +msgid "Revert documents to a previous version" +msgstr "Przywróć dokumenty do poprzedniej wersji" + +#: permissions.py:18 +msgid "Create new document versions" +msgstr "Tworzenie nowych wersji dokumentów" + +#: permissions.py:20 +msgid "Documents setup" +msgstr "" + +#: permissions.py:22 +msgid "View document types" +msgstr "Zobacz typy dokumentów" + +#: permissions.py:23 +msgid "Edit document types" +msgstr "Edytuj typy dokumentów" + +#: permissions.py:24 +msgid "Delete document types" +msgstr "Usuń typy dokumentów" + +#: permissions.py:25 +msgid "Create document types" +msgstr "Tworzenie typów dokumentu" + +#: statistics.py:40 +#, python-format +msgid "Document types: %d" +msgstr "" + +#: statistics.py:41 +#, python-format +msgid "Documents in database: %d" +msgstr "" + +#: statistics.py:46 +#, python-format +msgid "Documents in storage: %d" +msgstr "" + +#: statistics.py:48 +#, python-format +msgid "" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" +" bytes" +msgstr "" + +#: statistics.py:58 +#, python-format +msgid "Document pages in database: %d" +msgstr "" + +#: statistics.py:59 +#, python-format +msgid "Minimum amount of pages per document: %(page_count__min)d" +msgstr "" + +#: statistics.py:60 +#, python-format +msgid "Maximum amount of pages per document: %(page_count__max)d" +msgstr "" + +#: statistics.py:61 +#, python-format +msgid "Average amount of pages per document: %(page_count__avg)f" +msgstr "" + +#: statistics.py:67 +msgid "Document statistics" +msgstr "" + +#: views.py:133 +msgid "File mimetype" +msgstr "" + +#: views.py:134 +msgid "File mime encoding" +msgstr "" + +#: views.py:135 +msgid "File size" +msgstr "Rozmiar pliku" + +#: views.py:136 +msgid "Exists in storage" +msgstr "" + +#: views.py:137 +msgid "File path in storage" +msgstr "" + +#: views.py:138 +msgid "Date added" +msgstr "" + +#: views.py:139 +msgid "Time added" +msgstr "" + +#: views.py:140 +msgid "Checksum" +msgstr "" + +#: views.py:141 +msgid "UUID" +msgstr "" + +#: views.py:142 +msgid "Pages" +msgstr "" + +#: views.py:151 +#, python-format +msgid "document properties for: %s" +msgstr "" + +#: views.py:173 +msgid "document data" +msgstr "" + +#: views.py:197 views.py:646 +msgid "Must provide at least one document." +msgstr "Musisz podać co najmniej jeden dokument." + +#: views.py:218 +msgid "Document deleted successfully." +msgstr "Dokument usunięty." + +#: views.py:220 +#, python-format +msgid "Document: %(document)s delete error: %(error)s" +msgstr "" + +#: views.py:235 +#, python-format +msgid "Are you sure you wish to delete the document: %s?" +msgstr "Czy na pewno chcesz usunąć dokument:%s?" + +#: views.py:237 +#, python-format +msgid "Are you sure you wish to delete the documents: %s?" +msgstr "Czy na pewno chcesz usunąć dokumenty:%s?" + +#: views.py:276 +#, python-format +msgid "Document \"%s\" edited successfully." +msgstr "" + +#: views.py:342 +msgid "documents to be downloaded" +msgstr "dokumenty do pobrania" + +#: views.py:352 views.py:1337 +msgid "version" +msgstr "wersja" + +#: views.py:409 +msgid "Download" +msgstr "Pobierz" + +#: views.py:411 +msgid "Return" +msgstr "Powrót" + +#: views.py:445 +#, python-format +msgid "transformations for: %s" +msgstr "" + +#: views.py:472 +msgid "Document page transformation created successfully." +msgstr "" + +#: views.py:481 +#, python-format +msgid "Create new transformation for page: %(page)s of document: %(document)s" +msgstr "" + +#: views.py:500 +msgid "Document page transformation edited successfully." +msgstr "" + +#: views.py:513 +#, python-format +msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" +msgstr "" + +#: views.py:533 +msgid "Document page transformation deleted successfully." +msgstr "" + +#: views.py:544 +#, python-format +msgid "" +"Are you sure you wish to delete transformation \"%(transformation)s\" for: " +"%(document_page)s" +msgstr "" + +#: views.py:562 +#, python-format +msgid "duplicates of: %s" +msgstr "duplikaty:%s" + +#: views.py:574 +msgid "Are you sure you wish to find all duplicates?" +msgstr "Czy na pewno chcesz znaleźć wszystkie duplikaty?" + +#: views.py:575 views.py:633 views.py:701 +msgid "On large databases this operation may take some time to execute." +msgstr "Na dużych bazach danych operacja może chwilę potrwać. " + +#: views.py:598 +msgid "duplicated documents" +msgstr "" + +#: views.py:624 +#, python-format +msgid "" +"Page count update complete. Documents processed: %(total)d, documents with " +"changed page count: %(change)d" +msgstr "" + +#: views.py:632 +#, python-format +msgid "" +"Are you sure you wish to update the page count for the office documents " +"(%d)?" +msgstr "" + +#: views.py:664 +#, python-format +msgid "" +"All the page transformations for document: %s, have been deleted " +"successfully." +msgstr "" + +#: views.py:666 +#, python-format +msgid "" +"Error deleting the page transformations for document: %(document)s; " +"%(error)s." +msgstr "" + +#: views.py:672 +msgid "document transformation" +msgstr "" + +#: views.py:681 +#, python-format +msgid "" +"Are you sure you wish to clear all the page transformations for document: " +"%s?" +msgstr "" + +#: views.py:683 +#, python-format +msgid "" +"Are you sure you wish to clear all the page transformations for documents: " +"%s?" +msgstr "" + +#: views.py:711 +msgid "missing documents" +msgstr "brakujących dokumentów" + +#: views.py:727 views.py:769 +#, python-format +msgid "details for: %s" +msgstr "" + +#: views.py:788 +msgid "Document page edited successfully." +msgstr "" + +#: views.py:797 +#, python-format +msgid "edit: %s" +msgstr "" + +#: views.py:814 +msgid "There are no more pages in this document" +msgstr "" + +#: views.py:832 +msgid "You are already at the first page of this document" +msgstr "Jesteś już na pierwszej stronie tego dokumentu" + +#: views.py:993 +#, python-format +msgid "print: %s" +msgstr "drukuj:%s" + +#: views.py:1066 +#, python-format +msgid "documents of type \"%s\"" +msgstr "" + +#: views.py:1086 +msgid "Document type edited successfully" +msgstr "" + +#: views.py:1089 +#, python-format +msgid "Error editing document type; %s" +msgstr "" + +#: views.py:1094 +#, python-format +msgid "edit document type: %s" +msgstr "" + +#: views.py:1118 +#, python-format +msgid "Document type: %s deleted successfully." +msgstr "" + +#: views.py:1120 +#, python-format +msgid "Document type: %(document_type)s delete error: %(error)s" +msgstr "" + +#: views.py:1135 +#, python-format +msgid "Are you sure you wish to delete the document type: %s?" +msgstr "" + +#: views.py:1136 +msgid "" +"The document type of all documents using this document type will be set to " +"none." +msgstr "" + +#: views.py:1152 +msgid "Document type created successfully" +msgstr "" + +#: views.py:1155 +#, python-format +msgid "Error creating document type; %(error)s" +msgstr "" + +#: views.py:1173 +#, python-format +msgid "filenames for document type: %s" +msgstr "" + +#: views.py:1204 +msgid "Document type filename edited successfully" +msgstr "" + +#: views.py:1207 +#, python-format +msgid "Error editing document type filename; %s" +msgstr "" + +#: views.py:1212 +#, python-format +msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" +msgstr "" + +#: views.py:1221 views.py:1247 views.py:1255 +msgid "document type filename" +msgstr "" + +#: views.py:1239 +#, python-format +msgid "Document type filename: %s deleted successfully." +msgstr "" + +#: views.py:1241 +#, python-format +msgid "" +"Document type filename: %(document_type_filename)s delete error: %(error)s" +msgstr "" + +#: views.py:1257 +#, python-format +msgid "" +"Are you sure you wish to delete the filename: %(filename)s, from document " +"type \"%(document_type)s\"?" +msgstr "" + +#: views.py:1282 +msgid "Document type filename created successfully" +msgstr "" + +#: views.py:1285 +#, python-format +msgid "Error creating document type filename; %(error)s" +msgstr "" + +#: views.py:1291 +#, python-format +msgid "create filename for document type: %s" +msgstr "" + +#: views.py:1306 +msgid "Document image cache cleared successfully" +msgstr "" + +#: views.py:1308 +#, python-format +msgid "Error clearing document image cache; %s" +msgstr "" + +#: views.py:1314 +msgid "Are you sure you wish to clear the document image cache?" +msgstr "" + +#: views.py:1331 +#, python-format +msgid "versions for document: %s" +msgstr "" + +#: views.py:1341 +msgid "time and date" +msgstr "data i godzina" + +#: views.py:1345 +msgid "mimetype" +msgstr "mimetype" + +#: views.py:1349 +msgid "encoding" +msgstr "kodowanie" + +#: views.py:1380 +msgid "Document version reverted successfully" +msgstr "" + +#: views.py:1382 +#, python-format +msgid "Error reverting document version; %s" +msgstr "" + +#: views.py:1389 +msgid "Are you sure you wish to revert to this version?" +msgstr "Czy na pewno chcesz, powrócić do tej wersji?" + +#: views.py:1390 +msgid "All later version after this one will be deleted too." +msgstr "" + +#: widgets.py:25 +msgid "document page image" +msgstr "" + +#: wizards.py:36 +msgid "step 1 of 3: Document type" +msgstr "" + +#: wizards.py:37 +msgid "step 2 of 3: Metadata selection" +msgstr "" + +#: wizards.py:38 +msgid "step 3 of 3: Document metadata" +msgstr "" + +#: wizards.py:46 +msgid "Next step" +msgstr "" + +#: conf/settings.py:38 +msgid "" +"Maximum number of recent (created, edited, viewed) documents to remember per" +" user." +msgstr "" + +#: conf/settings.py:39 +msgid "Amount in percent zoom in or out a document page per user interaction." +msgstr "" + +#: conf/settings.py:40 +msgid "" +"Maximum amount in percent (%) to allow user to zoom in a document page " +"interactively." +msgstr "" + +#: conf/settings.py:41 +msgid "" +"Minimum amount in percent (%) to allow user to zoom out a document page " +"interactively." +msgstr "" + +#: conf/settings.py:42 +msgid "Amount in degrees to rotate a document page per user interaction." +msgstr "" + +#: templates/document_types_help.html:3 +msgid "What are document types?" +msgstr "Jakie są typy dokumentów?" + +#: templates/document_types_help.html:4 +msgid "" +"Document types define a class that represents a broard group of documents, " +"such as: invoices, regulations or manuals. The advantage of using document " +"types are: assigning a list of typical filenames for quick renaming during " +"creation, as well as assigning default metadata types and sets to it." +msgstr "" + +#: templates/recent_document_list_help.html:3 +msgid "What are recent documents?" +msgstr "Jakie są najnowsze dokumenty?" + +#: templates/recent_document_list_help.html:4 +#, python-format +msgid "" +"Here you will find the latest %(recent_count)s documents you have either " +"created or edited in any way." +msgstr "" diff --git a/apps/dynamic_search/locale/pl/LC_MESSAGES/django.po b/apps/dynamic_search/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..0e7ca3ed5d --- /dev/null +++ b/apps/dynamic_search/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,117 @@ +# 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-21 15:21+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:5 +msgid "search" +msgstr "szukaj" + +#: __init__.py:6 views.py:72 +msgid "advanced search" +msgstr "zaawansowane wyszukiwanie" + +#: __init__.py:7 +msgid "search again" +msgstr "wyszukaj ponownie" + +#: forms.py:8 +msgid "Search terms" +msgstr "Słowa do wyszukania" + +#: models.py:20 +msgid "user" +msgstr "użytkownik" + +#: models.py:21 +msgid "query" +msgstr "zapytanie" + +#: models.py:22 +msgid "datetime created" +msgstr "" + +#: models.py:23 +msgid "hits" +msgstr "trafienia" + +#: models.py:61 +msgid "recent search" +msgstr "ostatnie wyszukiwanie" + +#: models.py:62 +msgid "recent searches" +msgstr "ostatnie wyszukiwania" + +#: views.py:33 +#, python-format +msgid "results, (showing only %(shown_result_count)s out of %(result_count)s)" +msgstr "wyniki, (showing only %(shown_result_count)s z %(result_count)s)" + +#: views.py:37 +msgid "results" +msgstr "wyniki" + +#: views.py:56 +#, python-format +msgid "Search error: %s" +msgstr "Search error: %s" + +#: views.py:60 +msgid "type" +msgstr "typ" + +#: views.py:76 views.py:86 views.py:88 templatetags/search_tags.py:19 +#: templatetags/search_tags.py:20 +msgid "Search" +msgstr "Szukaj" + +#: conf/settings.py:12 +msgid "Maximum amount search hits to fetch and display." +msgstr "" + +#: conf/settings.py:13 +msgid "Maximum number of search queries to remember per user." +msgstr "" + +#: templates/search_help.html:3 +msgid "Help" +msgstr "Pomoc" + +#: templates/search_help.html:4 +#, python-format +msgid "" +"Enter the desired search keywords separated by space. Only the top " +"%(search_results_limit)s results will be available." +msgstr "" + +#: templates/search_results.html:3 +msgid "Search results" +msgstr "Wynik wyszukiwania" + +#: templates/search_results.html:19 +#, python-format +msgid "Elapsed time: %(time_delta)s seconds" +msgstr "Upływający czas: %(time_delta)s seconds" + +#: templatetags/search_tags.py:33 +#, python-format +msgid "recent searches (maximum of %d)" +msgstr "ostatnie wyszukiwanie (maximum of %d)" diff --git a/apps/feedback/locale/pl/LC_MESSAGES/django.po b/apps/feedback/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..c75a5f625a --- /dev/null +++ b/apps/feedback/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,103 @@ +# 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: 2012-02-02 18:21+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:9 +msgid "Feedback" +msgstr "" + +#: forms.py:16 +msgid "" +"What features of Mayan EDMS attracted you to start using it or consider " +"using it?" +msgstr "" + +#: forms.py:24 +msgid "What features would you like to see implemented in Mayan EDMS?" +msgstr "" + +#: forms.py:32 +msgid "" +"Could you tell us a bit about how you are deploying or plan to deploy Mayan " +"EDMS (OS, webserver, cloud/local, hardware specs)?" +msgstr "" + +#: forms.py:40 +msgid "" +"What features of Mayan EDMS did you find hardest to understand or implement?" +msgstr "" + +#: forms.py:45 +msgid "Would you be interested in purchasing paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:50 +msgid "" +"Are currently providing or planning to provide paid support for Mayan EDMS?" +msgstr "" + +#: forms.py:55 +msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" +msgstr "" + +#: forms.py:60 +msgid "" +"Would you be interested in a turn-key solution for Mayan EDMS that included " +"a physical server appliance?" +msgstr "" + +#: forms.py:65 +msgid "Your name:" +msgstr "" + +#: forms.py:70 +msgid "Your email:" +msgstr "" + +#: forms.py:75 +msgid "Company name:" +msgstr "" + +#: forms.py:80 +msgid "Company website:" +msgstr "" + +#: forms.py:85 +msgid "" +"May we display your company name & logo in our website as a user of Mayan " +"EDMS with a link back to your website?" +msgstr "" + +#: forms.py:90 +msgid "" +"May we keep your contact information to keep you up to date with " +"developments or oferings related to Mayan EDMS?" +msgstr "" + +#: views.py:20 +msgid "Thank you for submiting your feedback." +msgstr "" + +#: views.py:23 +#, python-format +msgid "Error submiting form; %s." +msgstr "" + +#: views.py:28 +msgid "feedback form" +msgstr "" diff --git a/apps/folders/locale/pl/LC_MESSAGES/django.po b/apps/folders/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..eb44816842 --- /dev/null +++ b/apps/folders/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,230 @@ +# 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 15:38+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:18 +msgid "folder list" +msgstr "lista folderów" + +#: __init__.py:19 views.py:77 +msgid "create folder" +msgstr "stworzyć folder" + +#: __init__.py:20 +msgid "edit" +msgstr "edytuj" + +#: __init__.py:21 +msgid "delete" +msgstr "usuń" + +#: __init__.py:22 +msgid "remove from folder" +msgstr "usuń z folderu" + +#: __init__.py:23 +msgid "folder documents" +msgstr "" + +#: __init__.py:24 +msgid "add to a folder" +msgstr "dodać do folderu" + +#: __init__.py:25 __init__.py:35 models.py:43 views.py:34 +msgid "folders" +msgstr "katalogi" + +#: __init__.py:27 +msgid "ACLs" +msgstr "" + +#: forms.py:38 +msgid "Folder" +msgstr "" + +#: models.py:11 +msgid "title" +msgstr "tytuł" + +#: models.py:12 +msgid "user" +msgstr "użytkownik" + +#: models.py:13 +msgid "datetime created" +msgstr "" + +#: models.py:42 models.py:47 views.py:108 views.py:137 views.py:162 +msgid "folder" +msgstr "folder" + +#: models.py:48 +msgid "document" +msgstr "dokument" + +#: models.py:54 views.py:261 +msgid "folder document" +msgstr "dokument folderu" + +#: models.py:55 +msgid "folders documents" +msgstr "" + +#: permissions.py:7 +msgid "Folders" +msgstr "Foldery" + +#: permissions.py:9 +msgid "Create new folders" +msgstr "" + +#: permissions.py:10 +msgid "Edit new folders" +msgstr "Edytuj nowe foldery" + +#: permissions.py:11 +msgid "Delete new folders" +msgstr "Usuń nowe foldery" + +#: permissions.py:12 +msgid "Remove documents from folders" +msgstr "" + +#: permissions.py:13 +msgid "View existing folders" +msgstr "" + +#: permissions.py:14 +msgid "Add documents to existing folders" +msgstr "Dodaj dokumenty do istniejących folderów" + +#: views.py:37 +msgid "created" +msgstr "" + +#: views.py:38 +msgid "documents" +msgstr "dokumenty" + +#: views.py:69 +msgid "Folder created successfully" +msgstr "Katalog został pomyślnie utworzony" + +#: views.py:72 +#, python-format +msgid "A folder named: %s, already exists." +msgstr "Katalog o nazwie:%s już istnieje." + +#: views.py:97 +msgid "Folder edited successfully" +msgstr "" + +#: views.py:100 +#, python-format +msgid "Error editing folder; %s" +msgstr "" + +#: views.py:105 +#, python-format +msgid "edit folder: %s" +msgstr "" + +#: views.py:129 +#, python-format +msgid "Folder: %s deleted successfully." +msgstr "" + +#: views.py:131 +#, python-format +msgid "Folder: %(folder)s delete error: %(error)s" +msgstr "" + +#: views.py:142 +#, python-format +msgid "Are you sure you with to delete the folder: %s?" +msgstr "" + +#: views.py:168 +#, python-format +msgid "documents in folder: %s" +msgstr "" + +#: views.py:188 +#, python-format +msgid "Document: %(document)s added to folder: %(folder)s successfully." +msgstr "" + +#: views.py:191 +#, python-format +msgid "Document: %(document)s is already in folder: %(folder)s." +msgstr "" + +#: views.py:199 +#, python-format +msgid "add document \"%s\" to a folder" +msgstr "" + +#: views.py:219 +#, python-format +msgid "folders containing: %s" +msgstr "" + +#: views.py:235 +msgid "Must provide at least one folder document." +msgstr "" + +#: views.py:253 +#, python-format +msgid "Document: %s removed successfully." +msgstr "" + +#: views.py:255 +#, python-format +msgid "Document: %(document)s delete error: %(error)s" +msgstr "" + +#: views.py:269 +#, python-format +msgid "" +"Are you sure you wish to remove the document: %(document)s from the folder " +"\"%(folder)s\"?" +msgstr "" + +#: views.py:272 +#, python-format +msgid "" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" +msgstr "" + +#: templates/folders_help.html:3 +msgid "What are folders?" +msgstr "" + +#: templates/folders_help.html:4 +msgid "" +"These folders can also be described as user folders. They are a way to let " +"individual users create their own document organization methods. Folders " +"created by one user and the documents contained by them don't affect any " +"other user folders or documents." +msgstr "" + +#: templatetags/folder_tags.py:17 +msgid "Add document to a folder" +msgstr "" diff --git a/apps/history/locale/pl/LC_MESSAGES/django.po b/apps/history/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..51627cb161 --- /dev/null +++ b/apps/history/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,107 @@ +# 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-21 14:46+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:10 models.py:71 +msgid "history" +msgstr "historia" + +#: models.py:18 +msgid "namespace" +msgstr "przestrzeń nazw" + +#: models.py:19 +msgid "name" +msgstr "nazwa" + +#: models.py:27 models.py:36 +msgid "history type" +msgstr "typ historii" + +#: models.py:28 +msgid "history types" +msgstr "typy historii" + +#: models.py:32 +msgid "date time" +msgstr "data i godzina" + +#: models.py:37 +msgid "dictionary" +msgstr "słownik" + +#: models.py:72 +msgid "histories" +msgstr "historie" + +#: permissions.py:7 +msgid "History" +msgstr "Historia" + +#: permissions.py:8 +msgid "Access the history of an object" +msgstr "Dostęp do historii obiektu" + +#: views.py:27 +msgid "history events" +msgstr "historia wydarzeń" + +#: views.py:30 views.py:67 +msgid "date and time" +msgstr "data i godzina" + +#: views.py:34 +msgid "object" +msgstr "obiekt" + +#: views.py:38 views.py:71 +msgid "summary" +msgstr "streszczenie" + +#: views.py:63 +#, python-format +msgid "history events for: %s" +msgstr "zdarzenia historii dla:%s" + +#: views.py:91 +msgid "Date" +msgstr "Data" + +#: views.py:92 +msgid "Time" +msgstr "Czas" + +#: views.py:93 +msgid "Object" +msgstr "Obiekt" + +#: views.py:94 +msgid "Event type" +msgstr "Typ zdarzenia" + +#: views.py:95 +msgid "Event details" +msgstr "Szczegóły wydarzenia" + +#: views.py:99 +#, python-format +msgid "details for: %s" +msgstr "szczegóły dla %s" diff --git a/apps/linking/locale/pl/LC_MESSAGES/django.po b/apps/linking/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..e24d50d2f7 --- /dev/null +++ b/apps/linking/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,334 @@ +# 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:14+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 +msgid "smart links actions" +msgstr "" + +#: __init__.py:18 __init__.py:20 models.py:23 views.py:132 +msgid "smart links" +msgstr "" + +#: __init__.py:21 +msgid "smart links list" +msgstr "" + +#: __init__.py:22 +msgid "create new smart link" +msgstr "" + +#: __init__.py:23 __init__.py:28 +msgid "edit" +msgstr "edycja" + +#: __init__.py:24 __init__.py:29 +msgid "delete" +msgstr "kasuj" + +#: __init__.py:26 +msgid "conditions" +msgstr "" + +#: __init__.py:27 +msgid "create condition" +msgstr "" + +#: __init__.py:31 +msgid "ACLs" +msgstr "" + +#: forms.py:50 +msgid "Pages" +msgstr "Strony" + +#: forms.py:56 +msgid "Select" +msgstr "Wybierz" + +#: forms.py:63 +msgid "Click on the image for full size view of the first page." +msgstr "" + +#: literals.py:7 +msgid "and" +msgstr "i" + +#: literals.py:8 +msgid "or" +msgstr "lub" + +#: literals.py:12 +msgid "is equal to" +msgstr "jest równy" + +#: literals.py:13 +msgid "is equal to (case insensitive)" +msgstr "jest równa (wielkość liter ma znaczenie)" + +#: literals.py:14 +msgid "contains" +msgstr "zawiera" + +#: literals.py:15 +msgid "contains (case insensitive)" +msgstr "zawiera (wielkość liter ma znaczenie)" + +#: literals.py:16 +msgid "is in" +msgstr "jest" + +#: literals.py:17 +msgid "is greater than" +msgstr "jest większa niż" + +#: literals.py:18 +msgid "is greater than or equal to" +msgstr "jest większa lub równa" + +#: literals.py:19 +msgid "is less than" +msgstr "jest mniejsza niż" + +#: literals.py:20 +msgid "is less than or equal to" +msgstr "jest mniejsza lub równa" + +#: literals.py:21 +msgid "starts with" +msgstr "zaczyna się" + +#: literals.py:22 +msgid "starts with (case insensitive)" +msgstr "rozpoczyna się (wielkość liter ma znaczenie)" + +#: literals.py:23 +msgid "ends with" +msgstr "kończy" + +#: literals.py:24 +msgid "ends with (case insensitive)" +msgstr "kończy (wielkość liter ma znaczenie)" + +#: literals.py:25 +msgid "is in regular expression" +msgstr "" + +#: literals.py:26 +msgid "is in regular expression (case insensitive)" +msgstr "" + +#: models.py:12 +msgid "title" +msgstr "tytuł" + +#: models.py:13 views.py:135 +msgid "dynamic title" +msgstr "dynamiczny tytuł" + +#: models.py:13 models.py:31 +msgid "" +"This expression will be evaluated against the current selected document. " +"The document metadata is available as variables `metadata` and document " +"properties under the variable `document`." +msgstr "" + +#: models.py:14 models.py:33 views.py:136 views.py:232 +msgid "enabled" +msgstr "włączony" + +#: models.py:22 models.py:27 views.py:296 views.py:330 +msgid "smart link" +msgstr "" + +#: models.py:28 +msgid "The inclusion is ignored for the first item." +msgstr "" + +#: models.py:29 +msgid "foreign document data" +msgstr "" + +#: models.py:29 +msgid "" +"This represents the metadata of all other documents. Available objects: " +"`document.` and `metadata.`." +msgstr "" + +#: models.py:31 +msgid "expression" +msgstr "" + +#: models.py:32 +msgid "negated" +msgstr "" + +#: models.py:32 +msgid "Inverts the logic of the operator." +msgstr "" + +#: models.py:36 +msgid "not" +msgstr "nie" + +#: models.py:39 +msgid "link condition" +msgstr "" + +#: models.py:40 +msgid "link conditions" +msgstr "" + +#: permissions.py:7 +msgid "Smart links" +msgstr "" + +#: permissions.py:9 +msgid "View existing smart links" +msgstr "" + +#: permissions.py:10 +msgid "Create new smart links" +msgstr "" + +#: permissions.py:11 +msgid "Delete smart links" +msgstr "" + +#: permissions.py:12 +msgid "Edit smart links" +msgstr "" + +#: views.py:40 +msgid "No action selected." +msgstr "Żadne działanie nie wybrane." + +#: views.py:59 +#, python-format +msgid "documents in smart link: %(group)s" +msgstr "" + +#: views.py:75 +#, python-format +msgid "Smart link query error: %s" +msgstr "" + +#: views.py:97 +#, python-format +msgid "smart links (%s)" +msgstr "" + +#: views.py:111 +msgid "There no defined smart links for the current document." +msgstr "" + +#: views.py:152 +#, python-format +msgid "Smart link: %s created successfully." +msgstr "" + +#: views.py:159 +msgid "Create new smart link" +msgstr "" + +#: views.py:175 +#, python-format +msgid "Smart link: %s edited successfully." +msgstr "" + +#: views.py:184 +#, python-format +msgid "Edit smart link: %s" +msgstr "" + +#: views.py:202 +#, python-format +msgid "Smart link: %s deleted successfully." +msgstr "" + +#: views.py:204 +#, python-format +msgid "Error deleting smart link: %(smart_link)s; %(error)s." +msgstr "" + +#: views.py:213 +#, python-format +msgid "Are you sure you wish to delete smart link: %s?" +msgstr "" + +#: views.py:229 +#, python-format +msgid "conditions for smart link: %s" +msgstr "" + +#: views.py:254 +#, python-format +msgid "Smart link condition: \"%s\" created successfully." +msgstr "" + +#: views.py:261 +#, python-format +msgid "Add new conditions to smart link: \"%s\"" +msgstr "" + +#: views.py:283 +#, python-format +msgid "Smart link condition: \"%s\" edited successfully." +msgstr "" + +#: views.py:290 +msgid "Edit smart link condition" +msgstr "" + +#: views.py:297 views.py:331 +msgid "condition" +msgstr "" + +#: views.py:317 +#, python-format +msgid "Smart link condition: \"%s\" deleted successfully." +msgstr "" + +#: views.py:319 +#, python-format +msgid "" +"Error deleting smart link condition: %(smart_link_condition)s; %(error)s." +msgstr "" + +#: views.py:333 +#, python-format +msgid "Are you sure you wish to delete smart link condition: \"%s\"?" +msgstr "" + +#: conf/settings.py:11 +msgid "Show smart link that don't return any documents." +msgstr "" + +#: templates/smart_links_help.html:3 +msgid "What are smart links?" +msgstr "" + +#: templates/smart_links_help.html:4 +msgid "" +"Smart links are a set of conditional statements that are used to query the " +"database using the current document the user is accessing as the data " +"source, the results of these queries are a list of documents that relate in " +"some manner to the document being displayed and allow users the ability to " +"jump to and from linked documents very easily." +msgstr "" diff --git a/apps/main/locale/pl/LC_MESSAGES/django.po b/apps/main/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..64265937de --- /dev/null +++ b/apps/main/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,146 @@ +# 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 15:36+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:33 +msgid "maintenance" +msgstr "utrzymanie" + +#: __init__.py:34 +msgid "statistics" +msgstr "statystyka" + +#: __init__.py:35 +msgid "diagnostics" +msgstr "diagnostyka" + +#: __init__.py:36 +msgid "sentry" +msgstr "" + +#: __init__.py:37 +msgid "admin site" +msgstr "strona administracyjna" + +#: __init__.py:40 +msgid "home" +msgstr "home" + +#: __init__.py:42 +msgid "search" +msgstr "szukaj" + +#: views.py:43 +msgid "maintenance menu" +msgstr "" + +#: views.py:56 +msgid "Statistics" +msgstr "Statystyka" + +#: views.py:66 +msgid "Diagnostics" +msgstr "Diagnostyka" + +#: conf/settings.py:12 +msgid "" +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." +msgstr "" + +#: templates/about.html:5 +msgid "About this program" +msgstr "O programie" + +#: templates/about.html:9 templates/verbose_login.html:4 +msgid "Version" +msgstr "Wersja" + +#: templates/base.html:28 +msgid "(DEBUG)" +msgstr "(DEBUG)" + +#: templates/base.html:183 +msgid "User" +msgstr "Użytkownik" + +#: templates/base.html:185 +msgid "Anonymous" +msgstr "Anonimowy" + +#: templates/base.html:188 +msgid "User details" +msgstr "Dane użytkownika" + +#: templates/base.html:205 +msgid "Login" +msgstr "Login" + +#: templates/base.html:205 +msgid "Logout" +msgstr "Wyloguj się" + +#: templates/base.html:285 +msgid "Secondary menu" +msgstr "" + +#: templates/base.html:301 +#, python-format +msgid "Actions for %(name)s: %(navigation_object)s" +msgstr "" + +#: templates/base.html:303 templates/base.html.py:346 +#, python-format +msgid "Actions for: %(navigation_object)s" +msgstr "" + +#: templates/base.html:306 +msgid "Available actions" +msgstr "" + +#: templates/base.html:318 templates/base.html.py:361 +msgid "Related actions" +msgstr "" + +#: templates/base.html:329 templates/base.html.py:374 +msgid "Other available actions" +msgstr "" + +#: templates/base.html:344 +#, python-format +msgid "Actions for %(object_name)s: %(navigation_object)s" +msgstr "" + +#: templates/base.html:349 +msgid "Actions" +msgstr "" + +#: templates/home.html:8 +msgid "Django based open source document management system" +msgstr "Django based open source document management system" + +#: templates/project_description.html:6 +msgid "" +"Open source, Django based electronic document manager with custom metadata, " +"indexing, tagging, file serving integration and OCR capabilities" +msgstr "" + +#: templates/project_description.html:18 +msgid "Released under the GPL V3 License" +msgstr "Released under the GPL V3 License" 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/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/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/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/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_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/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/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/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/user_management/locale/pl/LC_MESSAGES/django.po b/apps/user_management/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..541da70147 --- /dev/null +++ b/apps/user_management/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,257 @@ +# 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 15:33+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:13 +msgid "user list" +msgstr "lista użytkowników" + +#: __init__.py:14 views.py:31 +msgid "users" +msgstr "użytkownicy" + +#: __init__.py:15 __init__.py:24 +msgid "edit" +msgstr "edytuj" + +#: __init__.py:16 views.py:97 +msgid "create new user" +msgstr "rejestracja nowego użytkownika" + +#: __init__.py:17 __init__.py:18 __init__.py:26 __init__.py:27 +msgid "delete" +msgstr "usunąć" + +#: __init__.py:19 __init__.py:20 +msgid "reset password" +msgstr "zresetować hasło" + +#: __init__.py:22 +msgid "group list" +msgstr "lista grupa" + +#: __init__.py:23 views.py:228 +msgid "groups" +msgstr "grupy" + +#: __init__.py:25 views.py:276 +msgid "create new group" +msgstr "utwórz nową grupę" + +#: __init__.py:28 views.py:232 +msgid "members" +msgstr "członkowie" + +#: forms.py:13 +msgid "New password" +msgstr "Nowe hasło" + +#: forms.py:14 +msgid "Confirm password" +msgstr "Potwierdź hasło" + +#: permissions.py:7 +msgid "User management" +msgstr "Zarządzanie użytkownikami" + +#: permissions.py:9 +msgid "Create new users" +msgstr "Tworzenie nowych użytkowników" + +#: permissions.py:10 +msgid "Edit existing users" +msgstr "Edycja istniejących użytkowników" + +#: permissions.py:11 +msgid "View existing users" +msgstr "Zobacz istniejących użytkowników" + +#: permissions.py:12 +msgid "Delete existing users" +msgstr "Usuwanie istniejących użytkowników" + +#: permissions.py:14 +msgid "Create new groups" +msgstr "Tworzyć nowe grupy" + +#: permissions.py:15 +msgid "Edit existing groups" +msgstr "Edytować istniejące grupy" + +#: permissions.py:16 +msgid "View existing groups" +msgstr "Zobacz istniejących grup" + +#: permissions.py:17 +msgid "Delete existing groups" +msgstr "Usunąć istniejące grupy" + +#: views.py:35 +msgid "full name" +msgstr "pełne imię i nazwisko" + +#: views.py:39 +msgid "email" +msgstr "e-mail" + +#: views.py:43 +msgid "active" +msgstr "aktywny" + +#: views.py:47 +msgid "has usable password?" +msgstr "posiada hasło?" + +#: views.py:61 +msgid "" +"Super user and staff user editing is not allowed, use the admin interface " +"for these cases." +msgstr "Super user oraz staff user edycja nie jest możliwa , należy użyć interfejsu administratora w takich przypadkach." + +#: views.py:68 +#, python-format +msgid "User \"%s\" updated successfully." +msgstr "Użytkownik \"%s\" został zaktualizowany." + +#: views.py:74 +#, python-format +msgid "edit user: %s" +msgstr "edytuj użytkownika: %s" + +#: views.py:77 views.py:135 views.py:198 +msgid "user" +msgstr "użytkownik" + +#: views.py:91 +#, python-format +msgid "User \"%s\" created successfully." +msgstr "Użytkownik \"%s\" został utworzony pomyślnie." + +#: views.py:113 views.py:167 +msgid "Must provide at least one user." +msgstr "Musi podać co najmniej jednego użytkownika." + +#: views.py:123 +msgid "" +"Super user and staff user deleting is not allowed, use the admin interface " +"for these cases." +msgstr "Super user oraz staff user usuwanie nie jest możliwa , należy użyć interfejsu administratora w takich przypadkach." + +#: views.py:126 +#, python-format +msgid "User \"%s\" deleted successfully." +msgstr "Użytkownik \"%s\" został usunięta." + +#: views.py:128 +#, python-format +msgid "Error deleting user \"%(user)s\": %(error)s" +msgstr "Błąd podczas usuwania użytkownika \" %(user)s \": %(error)s " + +#: views.py:143 +#, python-format +msgid "Are you sure you wish to delete the user: %s?" +msgstr "Czy na pewno chcesz usunąć użytkownika:%s.?" + +#: views.py:145 +#, python-format +msgid "Are you sure you wish to delete the users: %s?" +msgstr "Czy na pewno chcesz usunąć użytkowników:%s?" + +#: views.py:178 +msgid "Passwords do not match, try again." +msgstr "Hasła nie pasują, spróbuj ponownie." + +#: views.py:183 +msgid "" +"Super user and staff user password reseting is not allowed, use the admin " +"interface for these cases." +msgstr "Super user oraz staff user reset nie jest możliwa , należy użyć interfejsu administratora w takich przypadkach." + +#: views.py:187 +#, python-format +msgid "Successfull password reset for user: %s." +msgstr "Pomyślne resetowania hasła użytkownika:%s." + +#: views.py:189 +#, python-format +msgid "Error reseting password for user \"%(user)s\": %(error)s" +msgstr "Błąd podczas resetowania hasło użytkownika \" %(user)s \": %(error)s " + +#: views.py:205 +#, python-format +msgid "Reseting password for user: %s" +msgstr "Resetowanie hasła użytkownika:%s" + +#: views.py:207 +#, python-format +msgid "Reseting password for users: %s" +msgstr "Resetowanie hasła dla użytkowników:%s" + +#: views.py:249 +#, python-format +msgid "Group \"%s\" updated successfully." +msgstr "Grupa \"%s\" została zaktualizowany." + +#: views.py:255 +#, python-format +msgid "edit group: %s" +msgstr "edycja grupy:%s" + +#: views.py:258 views.py:311 views.py:356 +msgid "group" +msgstr "grupa" + +#: views.py:270 +#, python-format +msgid "Group \"%s\" created successfully." +msgstr "Grupa \"%s\" została utworzona pomyślnie." + +#: views.py:292 +msgid "Must provide at least one group." +msgstr "Musi podać co najmniej jedną grupę." + +#: views.py:302 +#, python-format +msgid "Group \"%s\" deleted successfully." +msgstr "Grupa \"%s\" została usunięta." + +#: views.py:304 +#, python-format +msgid "Error deleting group \"%(group)s\": %(error)s" +msgstr "Błąd podczas usuwania grupy \" %(group)s \": %(error)s " + +#: views.py:319 +#, python-format +msgid "Are you sure you wish to delete the group: %s?" +msgstr "Czy na pewno chcesz usunąć grupę:%s?" + +#: views.py:321 +#, python-format +msgid "Are you sure you wish to delete the groups: %s?" +msgstr "" + +#: views.py:351 +#, python-format +msgid "non members of group: %s" +msgstr "niebędących członkami grupy:%s" + +#: views.py:352 +#, python-format +msgid "members of group: %s" +msgstr "Członkowie grupy:%s" diff --git a/apps/web_theme/locale/pl/LC_MESSAGES/django.po b/apps/web_theme/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000000..71e1e38ae1 --- /dev/null +++ b/apps/web_theme/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,75 @@ +# 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:16+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" + +#: conf/settings.py:10 +msgid "" +"CSS theme to apply, options are: amro, bec, bec-green, blue, default, djime-" +"cerulean, drastic-dark, kathleene, olive, orange, red, reidb-greenish and " +"warehouse." +msgstr "" + +#: conf/settings.py:12 +msgid "Display extra information in the login screen." +msgstr "" + +#: templates/web_theme_base.html:101 +msgid "dismiss all notifications" +msgstr "" + +#: templates/web_theme_base.html:101 +msgid "close all" +msgstr "" + +#: templates/web_theme_base.html:102 +msgid "dismiss this notification" +msgstr "" + +#: templates/web_theme_base.html:102 +msgid "close" +msgstr "" + +#: templates/web_theme_login.html:12 templates/web_theme_login.html.py:34 +msgid "Login" +msgstr "" + +#: templates/web_theme_login.html:18 +msgid "You are already logged in" +msgstr "Użytkownik jest już zalogowany" + +#: templates/web_theme_login.html:21 +msgid "Redirecting you to the website entry point in 5 seconds." +msgstr "" + +#: templates/web_theme_login.html:24 +#, python-format +msgid "" +"Or click here if redirection doesn't " +"work." +msgstr "" + +#: templates/pagination/pagination.html:6 +#: templates/pagination/pagination.html:8 +msgid "Previous" +msgstr "Poprzedni" + +#: templates/pagination/pagination.html:26 +#: templates/pagination/pagination.html:28 +msgid "Next" +msgstr "Następny" diff --git a/settings.py b/settings.py index ccd6d21270..a0da8da709 100644 --- a/settings.py +++ b/settings.py @@ -53,6 +53,7 @@ LANGUAGES = ( ('pt', ugettext('Portuguese')), ('ru', ugettext('Russian')), ('it', ugettext('Italian')), + ('pl', ugettext('Polish')), ) SITE_ID = 1 From 1f2b25152fd170c984263a64d750696cf9b21d2b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 16:07:07 -0400 Subject: [PATCH 466/484] Italian translation strings update --- apps/acls/locale/it/LC_MESSAGES/django.po | 54 +++--- apps/common/locale/it/LC_MESSAGES/django.po | 43 ++--- .../documents/locale/it/LC_MESSAGES/django.po | 161 +++++++----------- apps/feedback/locale/it/LC_MESSAGES/django.po | 48 +++--- apps/folders/locale/it/LC_MESSAGES/django.po | 50 +++--- apps/main/locale/it/LC_MESSAGES/django.po | 27 ++- .../locale/it/LC_MESSAGES/django.po | 30 ++-- 7 files changed, 169 insertions(+), 244 deletions(-) diff --git a/apps/acls/locale/it/LC_MESSAGES/django.po b/apps/acls/locale/it/LC_MESSAGES/django.po index 9418fd899d..232cf6fbab 100644 --- a/apps/acls/locale/it/LC_MESSAGES/django.po +++ b/apps/acls/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,21 @@ # 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" +"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-02 18:20+0000\n" +"PO-Revision-Date: 2012-02-21 00:41+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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:14 @@ -24,15 +24,15 @@ msgstr "" #: __init__.py:15 __init__.py:23 msgid "details" -msgstr "" +msgstr "dettagli" #: __init__.py:16 __init__.py:25 msgid "grant" -msgstr "" +msgstr "concedere" #: __init__.py:17 __init__.py:26 msgid "revoke" -msgstr "" +msgstr "revocare" #: __init__.py:18 __init__.py:24 forms.py:21 msgid "New holder" @@ -52,11 +52,11 @@ msgstr "" #: forms.py:38 msgid "Users" -msgstr "" +msgstr "Utenti" #: forms.py:41 msgid "Groups" -msgstr "" +msgstr "Gruppi" #: forms.py:44 msgid "Roles" @@ -64,7 +64,7 @@ msgstr "" #: forms.py:47 msgid "Special" -msgstr "" +msgstr "Speciale" #: managers.py:116 managers.py:128 msgid "Insufficient access." @@ -72,7 +72,7 @@ msgstr "" #: models.py:27 models.py:69 msgid "permission" -msgstr "" +msgstr "autorizzazione" #: models.py:53 msgid "access entry" @@ -92,11 +92,11 @@ msgstr "" #: models.py:109 msgid "Creator" -msgstr "" +msgstr "Creatore" #: models.py:112 models.py:113 msgid "creator" -msgstr "" +msgstr "creatore" #: permissions.py:7 permissions.py:8 msgid "Access control lists" @@ -129,12 +129,12 @@ msgstr "" #: views.py:50 views.py:412 msgid "permissions" -msgstr "" +msgstr "le autorizzazioni" #: views.py:97 #, python-format msgid "permissions available to: %(actor)s for %(obj)s" -msgstr "" +msgstr "autorizzazioni disponibili per: %(actor)s per %(obj)s " #: views.py:104 views.py:444 msgid "namespace" @@ -146,31 +146,31 @@ msgstr "" #: views.py:107 views.py:447 msgid "has permission" -msgstr "" +msgstr "ha l'autorizzazione" #: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " -msgstr "" +msgstr ", " #: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format msgid " for %s" -msgstr "" +msgstr "per %s" #: views.py:187 views.py:530 #, python-format msgid " to %s" -msgstr "" +msgstr "a %s" #: views.py:190 views.py:533 #, python-format msgid "Are you sure you wish to grant the permission %(title_suffix)s?" -msgstr "" +msgstr "Sei sicuro di voler concedere l'autorizzazione %(title_suffix)s?" #: views.py:192 views.py:535 #, python-format msgid "Are you sure you wish to grant the permissions %(title_suffix)s?" -msgstr "" +msgstr "Sei sicuro di voler concedere permessi %(title_suffix)s?" #: views.py:199 views.py:542 #, python-format @@ -187,17 +187,17 @@ msgstr "" #: views.py:281 views.py:610 #, python-format msgid " from %s" -msgstr "" +msgstr "da %s" #: views.py:284 views.py:613 #, python-format msgid "Are you sure you wish to revoke the permission %(title_suffix)s?" -msgstr "" +msgstr "Sei sicuro di voler revocare l'autorizzazione %(title_suffix)s?" #: views.py:286 views.py:615 #, python-format msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?" -msgstr "" +msgstr "Sei sicuro di voler revocare permessi %(title_suffix)s?" #: views.py:293 views.py:622 #, python-format @@ -216,7 +216,7 @@ msgstr "" #: views.py:356 views.py:488 msgid "Select" -msgstr "" +msgstr "Selezionare" #: views.py:388 msgid "classes" diff --git a/apps/common/locale/it/LC_MESSAGES/django.po b/apps/common/locale/it/LC_MESSAGES/django.po index b29dd785f0..365d59fa16 100644 --- a/apps/common/locale/it/LC_MESSAGES/django.po +++ b/apps/common/locale/it/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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-02 18:18+0000\n" +"PO-Revision-Date: 2012-02-21 16:35+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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 @@ -51,9 +51,7 @@ msgstr "Email" msgid "" "Please enter a correct email and password. Note that the password fields is " "case-sensitive." -msgstr "" -"Inserisci un'indirizzo mail valido e una password. Ricorda che il campo " -"password è case-sensitive" +msgstr "Inserisci un'indirizzo mail valido e una password. Ricorda che il campo password è case-sensitive" #: forms.py:146 msgid "This account is inactive." @@ -105,11 +103,11 @@ msgstr "" #: models.py:43 msgid "Anonymous user" -msgstr "" +msgstr "Utente anonimo" #: models.py:46 models.py:47 msgid "anonymous user" -msgstr "" +msgstr "utente anonimo" #: utils.py:295 msgid "function found" @@ -152,7 +150,7 @@ msgstr "dettagli dell'utente corrente" #: views.py:187 msgid "E-mail conflict, another user has that same email." -msgstr "" +msgstr "E-mail conflitto, un altro utente ha quella stessa email." #: views.py:190 msgid "Current user's details updated." @@ -168,7 +166,7 @@ msgstr "Licenza" #: views.py:239 msgid "Current user password change" -msgstr "" +msgstr "Modifica della password dell'utente corrente" #: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." @@ -181,24 +179,19 @@ msgstr "Nessuno" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using tempfile." -"mkdtemp()" -msgstr "" -"Directory temporanea utilizzata a livello di sito per thumbnails, anteprime " -"e file temporanei. Se non viene specificato, ne verrà creata utilizzando " +"temporary files. If none is specified, one will be created using " "tempfile.mkdtemp()" +msgstr "Directory temporanea utilizzata a livello di sito per thumbnails, anteprime e file temporanei. Se non viene specificato, ne verrà creata utilizzando tempfile.mkdtemp()" #: conf/settings.py:65 msgid "" "Controls the mechanism used to authenticated user. Options are: username, " "email" -msgstr "" -"Controllo del meccanismo di autenticazione. Le opzioni possibili sono:" -"username,email" +msgstr "Controllo del meccanismo di autenticazione. Le opzioni possibili sono:username,email" #: conf/settings.py:74 msgid "Allow non authenticated users, access to all views" -msgstr "" +msgstr "Consentire agli utenti non autenticati, l'accesso a tutte le viste" #: templates/403.html:3 templates/403.html.py:7 msgid "Insufficient permissions" @@ -304,7 +297,7 @@ msgstr "Sottometti" #: templates/generic_form_subtemplate.html:87 msgid "Cancel" -msgstr "" +msgstr "Annullare" #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format @@ -317,9 +310,7 @@ msgstr "Lista di %(stripped_title)s" msgid "" "List of %(title)s (%(start)s - %(end)s out of %(total)s) (Page " "%(page_number)s of %(total_pages)s)" -msgstr "" -"Lista di %(title)s (%(start)s - %(end)s fuori %(total)s) (Page " -"%(page_number)s of %(total_pages)s)" +msgstr "Lista di %(title)s (%(start)s - %(end)s fuori %(total)s) (Page %(page_number)s of %(total_pages)s)" #: templates/generic_list_horizontal_subtemplate.html:25 #: templates/generic_list_subtemplate.html:26 diff --git a/apps/documents/locale/it/LC_MESSAGES/django.po b/apps/documents/locale/it/LC_MESSAGES/django.po index d2fce3d972..e8312c5918 100644 --- a/apps/documents/locale/it/LC_MESSAGES/django.po +++ b/apps/documents/locale/it/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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 08:43+0000\n" +"PO-Revision-Date: 2012-02-21 00:37+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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:63 @@ -71,9 +71,7 @@ msgstr "trova tutti i duplicati" #: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." -msgstr "" -"Cerca tutti i documenti con il checksum e restituisci una lista delle " -"corrispondenze esatte." +msgstr "Cerca tutti i documenti con il checksum e restituisci una lista delle corrispondenze esatte." #: __init__.py:78 msgid "update office documents' page count" @@ -84,10 +82,7 @@ msgid "" "Update the page count of the office type documents. This is useful when " "enabling office document support after there were already office type " "documents in the database." -msgstr "" -"Update the page count of the office type documents. This is useful when " -"enabling office document support after there were already office type " -"documents in the database." +msgstr "Update the page count of the office type documents. This is useful when enabling office document support after there were already office type documents in the database." #: __init__.py:79 __init__.py:80 msgid "clear transformations" @@ -173,11 +168,11 @@ msgstr "ripristino della vista" #: __init__.py:108 msgid "versions" -msgstr "" +msgstr "versioni" #: __init__.py:109 msgid "revert" -msgstr "" +msgstr "ripristinare" #: __init__.py:112 msgid "document type list" @@ -229,7 +224,7 @@ msgstr "Contenuti" #: forms.py:109 msgid "Page" -msgstr "" +msgstr "Pagina" #: forms.py:121 msgid "Details" @@ -254,7 +249,7 @@ msgstr "Rinomina del documento veloce" #: forms.py:185 msgid "Version update" -msgstr "" +msgstr "Versione aggiornamento" #: forms.py:190 msgid "Release level" @@ -266,7 +261,7 @@ msgstr "" #: forms.py:204 msgid "Comment" -msgstr "" +msgstr "Commento" #: forms.py:210 msgid "New document filename" @@ -278,7 +273,7 @@ msgstr "Intervallo pagina" #: forms.py:318 msgid "Compress" -msgstr "" +msgstr "Comprimere" #: forms.py:318 msgid "" @@ -298,10 +293,8 @@ msgstr "Documento \"%(content_object)s\" creato da by %(fullname)s." #: literals.py:12 #, python-format -msgid "" -"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." -msgstr "" -"Documento \"%(content_object)s\" creato il %(datetime)s da %(fullname)s." +msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "Documento \"%(content_object)s\" creato il %(datetime)s da %(fullname)s." #: literals.py:18 msgid "Document edited" @@ -315,11 +308,9 @@ msgstr "Documento \"%(content_object)s\" modificato da %(fullname)s." #: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " -"The following changes took place: %(changes)s." -msgstr "" -"Documento \"%(content_object)s\" è stato modificato il %(datetime)s da " -"%(fullname)s. Queste le seguenti modifiche: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." +" The following changes took place: %(changes)s." +msgstr "Documento \"%(content_object)s\" è stato modificato il %(datetime)s da %(fullname)s. Queste le seguenti modifiche: %(changes)s." #: literals.py:29 msgid "Document deleted" @@ -418,11 +409,11 @@ msgstr "" #: models.py:306 msgid "timestamp" -msgstr "" +msgstr "timestamp" #: models.py:307 views.py:1357 msgid "comment" -msgstr "" +msgstr "commento" #: models.py:310 msgid "file" @@ -434,14 +425,13 @@ msgstr "checksum" #: models.py:318 models.py:319 models.py:542 msgid "document version" -msgstr "" +msgstr "versione del documento" #: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." -msgstr "" -"Questo tipo di formato file è sconosciuto, per cui il numero di pagine sarà 1" +msgstr "Questo tipo di formato file è sconosciuto, per cui il numero di pagine sarà 1" #: models.py:525 views.py:1353 msgid "filename" @@ -591,11 +581,11 @@ msgstr "Esegui i tools per la modifica dei documenti" #: permissions.py:17 msgid "Revert documents to a previous version" -msgstr "" +msgstr "Ripristinare i documenti ad una versione precedente" #: permissions.py:18 msgid "Create new document versions" -msgstr "" +msgstr "Creazione di nuove versioni dei documenti" #: permissions.py:20 msgid "Documents setup" @@ -603,7 +593,7 @@ msgstr "Setup Documenti" #: permissions.py:22 msgid "View document types" -msgstr "" +msgstr "Visualizza i tipi di documento" #: permissions.py:23 msgid "Edit document types" @@ -635,11 +625,9 @@ msgstr "Documenti nello storage:%d" #: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " -"bytes" -msgstr "" -"Spazio usato nello storage: %(base_2)s (base 2), %(base_10)s (base 10), " -"%(bytes)d bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" +" bytes" +msgstr "Spazio usato nello storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d bytes" #: statistics.py:58 #, python-format @@ -720,7 +708,7 @@ msgstr "Devi indicare almeno un documento" #: views.py:218 msgid "Document deleted successfully." -msgstr "" +msgstr "Documento eliminato correttamente." #: views.py:220 #, python-format @@ -748,7 +736,7 @@ msgstr "" #: views.py:352 views.py:1337 msgid "version" -msgstr "" +msgstr "versione" #: views.py:409 msgid "Download" @@ -770,9 +758,7 @@ msgstr "Trasformazioni per la pagina del documento creata con successo" #: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" -msgstr "" -"Crea una nuova trasformazione per la pagina: %(page)s del documento: " -"%(document)s" +msgstr "Crea una nuova trasformazione per la pagina: %(page)s del documento: %(document)s" #: views.py:500 msgid "Document page transformation edited successfully." @@ -781,8 +767,7 @@ msgstr "Document page trasformation edited successfully." #: views.py:513 #, python-format msgid "Edit transformation \"%(transformation)s\" for: %(document_page)s" -msgstr "" -"Modifica la trasformazione \"%(transformation)s\" per: %(document_page)s" +msgstr "Modifica la trasformazione \"%(transformation)s\" per: %(document_page)s" #: views.py:533 msgid "Document page transformation deleted successfully." @@ -793,9 +778,7 @@ msgstr "Trasformazione della pagina di documento cancellata con successo." msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " "%(document_page)s" -msgstr "" -"Sei sicuro di voler cancellare la trasformazione \"%(transformation)s\" per: " -"%(document_page)s" +msgstr "Sei sicuro di voler cancellare la trasformazione \"%(transformation)s\" per: %(document_page)s" #: views.py:562 #, python-format @@ -819,34 +802,28 @@ msgstr "documenti duplicati" msgid "" "Page count update complete. Documents processed: %(total)d, documents with " "changed page count: %(change)d" -msgstr "" -"Update del numero di pagine completato. Il documenti processati " -"%(total)d, con il numero di pagine cambiate: %(change)d" +msgstr "Update del numero di pagine completato. Il documenti processati %(total)d, con il numero di pagine cambiate: %(change)d" #: views.py:632 #, python-format msgid "" -"Are you sure you wish to update the page count for the office documents (%d)?" -msgstr "" -"Sei sicuro di voler cambiare il numero di pagine deil documenti office (%d)?" +"Are you sure you wish to update the page count for the office documents " +"(%d)?" +msgstr "Sei sicuro di voler cambiare il numero di pagine deil documenti office (%d)?" #: views.py:664 #, python-format msgid "" "All the page transformations for document: %s, have been deleted " "successfully." -msgstr "" -"Tutte le trasformazioni alle pagine del documento:%s, sono state cancellate " -"con successo." +msgstr "Tutte le trasformazioni alle pagine del documento:%s, sono state cancellate con successo." #: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " "%(error)s." -msgstr "" -"Errore nella cancellazione della trasformazione della pagina per il " -"documento:%(document)s; %(error)s." +msgstr "Errore nella cancellazione della trasformazione della pagina per il documento:%(document)s; %(error)s." #: views.py:672 msgid "document transformation" @@ -855,7 +832,8 @@ msgstr "trasformazione del documento" #: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: %s?" +"Are you sure you wish to clear all the page transformations for document: " +"%s?" msgstr "Sei sicuro di voler cancellare le trasformazioni per il documento:%s?" #: views.py:683 @@ -923,8 +901,7 @@ msgstr "Tipo di documento: %s cancellata ." #: views.py:1120 #, python-format msgid "Document type: %(document_type)s delete error: %(error)s" -msgstr "" -"Tipo di documento: %(document_type)s errore di cancellazione: %(error)s" +msgstr "Tipo di documento: %(document_type)s errore di cancellazione: %(error)s" #: views.py:1135 #, python-format @@ -963,9 +940,7 @@ msgstr "Errore nella modifica del tipo di nome file;%s" #: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" -msgstr "" -"modifica il nome file \"%(filename)s\" per il tipo di documento " -"\"%(document_type)s\"" +msgstr "modifica il nome file \"%(filename)s\" per il tipo di documento \"%(document_type)s\"" #: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" @@ -980,18 +955,14 @@ msgstr "Tipo di nome file per il documento: %s cancellato con successo." #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" -msgstr "" -"Tipo di nome file per il documento:%(document_type_filename)s errore di " -"cancellazione: %(error)s" +msgstr "Tipo di nome file per il documento:%(document_type_filename)s errore di cancellazione: %(error)s" #: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " "type \"%(document_type)s\"?" -msgstr "" -"Sei sicuro che vuoi cancellare il nome file:%(filename)s, per il tipo di " -"documento\"%(document_type)s\"?" +msgstr "Sei sicuro che vuoi cancellare il nome file:%(filename)s, per il tipo di documento\"%(document_type)s\"?" #: views.py:1282 msgid "Document type filename created successfully" @@ -1023,7 +994,7 @@ msgstr "" #: views.py:1331 #, python-format msgid "versions for document: %s" -msgstr "" +msgstr "versioni per documento: %s" #: views.py:1341 msgid "time and date" @@ -1039,20 +1010,20 @@ msgstr "" #: views.py:1380 msgid "Document version reverted successfully" -msgstr "" +msgstr "Versione del documento ripristinato con successo" #: views.py:1382 #, python-format msgid "Error reverting document version; %s" -msgstr "" +msgstr "Errore restituito, quando ripristino documento; %s" #: views.py:1389 msgid "Are you sure you wish to revert to this version?" -msgstr "" +msgstr "Sei sicuro di voler tornare a questa versione?" #: views.py:1390 msgid "All later version after this one will be deleted too." -msgstr "" +msgstr "Tutte le versioni più tardi verrà cancellato." #: widgets.py:25 msgid "document page image" @@ -1076,33 +1047,25 @@ msgstr "Next step" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per " -"user." -msgstr "" -"Massimo numero recente (creazione, modifica, visualizzazione) di documenti " -"da ricordare per utente" +"Maximum number of recent (created, edited, viewed) documents to remember per" +" user." +msgstr "Massimo numero recente (creazione, modifica, visualizzazione) di documenti da ricordare per utente" #: conf/settings.py:39 msgid "Amount in percent zoom in or out a document page per user interaction." -msgstr "" -"Importo in percentuale dello zoom o rimpicciolire una pagina del documento " -"per l'interazione dell'utente." +msgstr "Importo in percentuale dello zoom o rimpicciolire una pagina del documento per l'interazione dell'utente." #: conf/settings.py:40 msgid "" "Maximum amount in percent (%) to allow user to zoom in a document page " "interactively." -msgstr "" -"Importo massimo in percentuale (%) per consentire all'utente di ingrandire " -"una pagina del documento in modo interattivo." +msgstr "Importo massimo in percentuale (%) per consentire all'utente di ingrandire una pagina del documento in modo interattivo." #: conf/settings.py:41 msgid "" "Minimum amount in percent (%) to allow user to zoom out a document page " "interactively." -msgstr "" -"Quantità minima in percentuale (%) per consentire all'utente di ingrandire " -"una pagina di documento in modo interattivo." +msgstr "Quantità minima in percentuale (%) per consentire all'utente di ingrandire una pagina di documento in modo interattivo." #: conf/settings.py:42 msgid "Amount in degrees to rotate a document page per user interaction." @@ -1118,11 +1081,7 @@ msgid "" "such as: invoices, regulations or manuals. The advantage of using document " "types are: assigning a list of typical filenames for quick renaming during " "creation, as well as assigning default metadata types and sets to it." -msgstr "" -"Il tipo di documento definisce una raggruppamento di documenti, come : " -"fatture, regolamenti, manuali. Il vantaggio dell'uso di tale classificazione " -"permette di rinominare,aggiungere metadati e rinominare i file più " -"velocemente." +msgstr "Il tipo di documento definisce una raggruppamento di documenti, come : fatture, regolamenti, manuali. Il vantaggio dell'uso di tale classificazione permette di rinominare,aggiungere metadati e rinominare i file più velocemente." #: templates/recent_document_list_help.html:3 msgid "What are recent documents?" @@ -1133,6 +1092,4 @@ msgstr "Quali sono i documenti recenti ?" msgid "" "Here you will find the latest %(recent_count)s documents you have either " "created or edited in any way." -msgstr "" -"qui troverete gli ultimi %(recent_count)s documenti da voi creati o " -"modificati" +msgstr "qui troverete gli ultimi %(recent_count)s documenti da voi creati o modificati" diff --git a/apps/feedback/locale/it/LC_MESSAGES/django.po b/apps/feedback/locale/it/LC_MESSAGES/django.po index 7a3901a9eb..d49175a6fa 100644 --- a/apps/feedback/locale/it/LC_MESSAGES/django.po +++ b/apps/feedback/locale/it/LC_MESSAGES/django.po @@ -1,104 +1,104 @@ # 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" +"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-02 18:21+0000\n" +"PO-Revision-Date: 2012-02-21 00:51+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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:9 msgid "Feedback" -msgstr "" +msgstr "Commenti" #: forms.py:16 msgid "" "What features of Mayan EDMS attracted you to start using it or consider " "using it?" -msgstr "" +msgstr "Quali caratteristiche di Mayan EDMS ti ha attratto per iniziare ad usarlo o considerare l'utilizzo di esso?" #: forms.py:24 msgid "What features would you like to see implemented in Mayan EDMS?" -msgstr "" +msgstr "Quali caratteristiche vorreste vedere implementata in Mayan EDMS?" #: forms.py:32 msgid "" "Could you tell us a bit about how you are deploying or plan to deploy Mayan " "EDMS (OS, webserver, cloud/local, hardware specs)?" -msgstr "" +msgstr "Puoi dirci un po 'su come si distribuisce o si prevede di distribuire Mayan EDMS (webserver, nuvola / locali, specifiche hardware)?" #: forms.py:40 msgid "" "What features of Mayan EDMS did you find hardest to understand or implement?" -msgstr "" +msgstr "Quali caratteristiche di Mayan EDMS ha trovato più difficile da comprendere o implementare?" #: forms.py:45 msgid "Would you be interested in purchasing paid support for Mayan EDMS?" -msgstr "" +msgstr "Sareste interessati ad acquistare il supporto a pagamento per Mayan EDMS?" #: forms.py:50 msgid "" "Are currently providing or planning to provide paid support for Mayan EDMS?" -msgstr "" +msgstr "Stanno fornendo o progettando di fornire supporto a pagamento per Mayan EDMS?" #: forms.py:55 msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" -msgstr "" +msgstr "Sareste interessati ad una soluzione nuvola automatica per Mayan EDMS?" #: forms.py:60 msgid "" "Would you be interested in a turn-key solution for Mayan EDMS that included " "a physical server appliance?" -msgstr "" +msgstr "Saresti interessato ad una soluzione automatica per Mayan EDMS che hanno incluso un apparecchio fisico server?" #: forms.py:65 msgid "Your name:" -msgstr "" +msgstr "Il tuo nome:" #: forms.py:70 msgid "Your email:" -msgstr "" +msgstr "Il tuo indirizzo email:" #: forms.py:75 msgid "Company name:" -msgstr "" +msgstr "Ragione Sociale:" #: forms.py:80 msgid "Company website:" -msgstr "" +msgstr "Sito internet della Società:" #: forms.py:85 msgid "" "May we display your company name & logo in our website as a user of Mayan " "EDMS with a link back to your website?" -msgstr "" +msgstr "Possiamo visualizzare il nome della società e il logo del nostro sito come utente di Mayan EDMS con un link al tuo sito web?" #: forms.py:90 msgid "" "May we keep your contact information to keep you up to date with " "developments or oferings related to Mayan EDMS?" -msgstr "" +msgstr "Possiamo mantenere le informazioni di contatto per tenervi aggiornati sugli sviluppi o oferings relativi al Mayan EDMS?" #: views.py:20 msgid "Thank you for submiting your feedback." -msgstr "" +msgstr "Grazie per l'invio i vostri commenti." #: views.py:23 #, python-format msgid "Error submiting form; %s." -msgstr "" +msgstr "Errore l'invio di forma; %s." #: views.py:28 msgid "feedback form" -msgstr "" +msgstr "forma di commenti" diff --git a/apps/folders/locale/it/LC_MESSAGES/django.po b/apps/folders/locale/it/LC_MESSAGES/django.po index 7ff1574396..882101fe06 100644 --- a/apps/folders/locale/it/LC_MESSAGES/django.po +++ b/apps/folders/locale/it/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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-02 18:19+0000\n" +"PO-Revision-Date: 2012-02-21 00:25+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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:18 @@ -57,7 +57,7 @@ msgstr "" #: forms.py:38 msgid "Folder" -msgstr "" +msgstr "Cartella" #: models.py:11 msgid "title" @@ -89,31 +89,31 @@ msgstr "cartelle documento" #: permissions.py:7 msgid "Folders" -msgstr "" +msgstr "Cartelle" #: permissions.py:9 msgid "Create new folders" -msgstr "" +msgstr "Creare nuove cartelle" #: permissions.py:10 msgid "Edit new folders" -msgstr "" +msgstr "Modifica nuove cartelle" #: permissions.py:11 msgid "Delete new folders" -msgstr "" +msgstr "Eliminare nuove cartelle" #: permissions.py:12 msgid "Remove documents from folders" -msgstr "" +msgstr "Rimuovere i documenti da cartelle" #: permissions.py:13 msgid "View existing folders" -msgstr "" +msgstr "Visualizza cartelle esistenti" #: permissions.py:14 msgid "Add documents to existing folders" -msgstr "" +msgstr "Aggiungere documenti a cartelle esistenti" #: views.py:37 msgid "created" @@ -169,8 +169,7 @@ msgstr "documenti nella cartella: %s" #: views.py:188 #, python-format msgid "Document: %(document)s added to folder: %(folder)s successfully." -msgstr "" -"Documento: %(document)s aggiunto alla cartella: %(folder)s successfully." +msgstr "Documento: %(document)s aggiunto alla cartella: %(folder)s successfully." #: views.py:191 #, python-format @@ -206,18 +205,14 @@ msgstr "Documento: %(document)s errore di cancellazione: %(error)s" msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " "\"%(folder)s\"?" -msgstr "" -"Sei sicuro di voler rimuovere il documento: %(document)s dalla cartella " -"\"%(folder)s\"?" +msgstr "Sei sicuro di voler rimuovere il documento: %(document)s dalla cartella \"%(folder)s\"?" #: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder " -"\"%(folder)s\"?" -msgstr "" -"Sei sicuro di voler rimuovere i documenti: %(documents)s dalla cartella " -"\"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" +msgstr "Sei sicuro di voler rimuovere i documenti: %(documents)s dalla cartella \"%(folder)s\"?" #: templates/folders_help.html:3 msgid "What are folders?" @@ -229,12 +224,7 @@ msgid "" "individual users create their own document organization methods. Folders " "created by one user and the documents contained by them don't affect any " "other user folders or documents." -msgstr "" -"Queste cartelle possono anche essere considerate come cartelle utente. Sono " -"un modo per consentire agli utenti singoli per creare i propri metodi di " -"organizzazione dei documenti. Cartelle create da un utente e dei documenti " -"contenuti da loro non riguardano tutte le cartelle di altri utenti o " -"documenti." +msgstr "Queste cartelle possono anche essere considerate come cartelle utente. Sono un modo per consentire agli utenti singoli per creare i propri metodi di organizzazione dei documenti. Cartelle create da un utente e dei documenti contenuti da loro non riguardano tutte le cartelle di altri utenti o documenti." #: templatetags/folder_tags.py:17 msgid "Add document to a folder" diff --git a/apps/main/locale/it/LC_MESSAGES/django.po b/apps/main/locale/it/LC_MESSAGES/django.po index 9efd77430f..19e9f80487 100644 --- a/apps/main/locale/it/LC_MESSAGES/django.po +++ b/apps/main/locale/it/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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-01-02 04:46+0000\n" +"PO-Revision-Date: 2012-02-21 16:42+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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:33 @@ -61,11 +61,9 @@ msgstr "Diagnostica" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or " -"by a menu entry." -msgstr "" -"Controlla se la funzionalità di ricerca è fornita da un widget sidebar o da " -"una voce di menu." +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." +msgstr "Controlla se la funzionalità di ricerca è fornita da un widget sidebar o da una voce di menu." #: templates/about.html:5 msgid "About this program" @@ -136,16 +134,13 @@ msgstr "Azioni" #: templates/home.html:8 msgid "Django based open source document management system" -msgstr "" +msgstr "Sistema open source di gestione dei documenti basato su Django" #: templates/project_description.html:6 msgid "" "Open source, Django based electronic document manager with custom metadata, " "indexing, tagging, file serving integration and OCR capabilities" -msgstr "" -"Open Source, Django programma per la gestione documentale con la possibilità " -"di metadati personalizabili, tagging, indicizzazione, integrazione con file " -"server e con possibilità di OCR" +msgstr "Open Source, Django programma per la gestione documentale con la possibilità di metadati personalizabili, tagging, indicizzazione, integrazione con file server e con possibilità di OCR" #: templates/project_description.html:18 msgid "Released under the GPL V3 License" diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.po b/apps/user_management/locale/it/LC_MESSAGES/django.po index 21982b6118..26a11e096d 100644 --- a/apps/user_management/locale/it/LC_MESSAGES/django.po +++ b/apps/user_management/locale/it/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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-02 18:18+0000\n" +"PO-Revision-Date: 2012-02-21 16:36+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/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:13 @@ -117,15 +117,13 @@ msgstr "attivo" #: views.py:47 msgid "has usable password?" -msgstr "" +msgstr "la password è utilizzabile?" #: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." -msgstr "" -"Super utente e utente modifica il personale non è consentito, utilizzare " -"l'interfaccia di amministrazione per questi casi." +msgstr "Super utente e utente modifica il personale non è consentito, utilizzare l'interfaccia di amministrazione per questi casi." #: views.py:68 #, python-format @@ -154,9 +152,7 @@ msgstr "Devi fornire almeno un utente." msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." -msgstr "" -"Al super utente e utente non è consentito la cancellazione del personale, " -"utilizzare l'interfaccia di amministrazione per questi casi." +msgstr "Al super utente e utente non è consentito la cancellazione del personale, utilizzare l'interfaccia di amministrazione per questi casi." #: views.py:126 #, python-format @@ -186,9 +182,7 @@ msgstr "La password non corrisponde, riprova." msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." -msgstr "" -"Al super utente e utente non è consentito di reimpostare la password " -"personale, utilizzare l'interfaccia di amministrazione per questi casi." +msgstr "Al super utente e utente non è consentito di reimpostare la password personale, utilizzare l'interfaccia di amministrazione per questi casi." #: views.py:187 #, python-format @@ -198,9 +192,7 @@ msgstr "Password reimpostata per l'utente: %s." #: views.py:189 #, python-format msgid "Error reseting password for user \"%(user)s\": %(error)s" -msgstr "" -"Errore per il reimpostamento della password per l'utente \"%(user)s\": " -"%(error)s" +msgstr "Errore per il reimpostamento della password per l'utente \"%(user)s\": %(error)s" #: views.py:205 #, python-format From a888b11deca2628ed3446bb5b04fd774c30712a4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 16:07:29 -0400 Subject: [PATCH 467/484] Portuguese translation strings update --- apps/common/locale/pt/LC_MESSAGES/django.po | 43 ++--- .../documents/locale/pt/LC_MESSAGES/django.po | 160 +++++++----------- apps/folders/locale/pt/LC_MESSAGES/django.po | 47 +++-- apps/main/locale/pt/LC_MESSAGES/django.po | 27 ++- apps/tags/locale/pt/LC_MESSAGES/django.po | 15 +- .../locale/pt/LC_MESSAGES/django.po | 26 ++- 6 files changed, 122 insertions(+), 196 deletions(-) diff --git a/apps/common/locale/pt/LC_MESSAGES/django.po b/apps/common/locale/pt/LC_MESSAGES/django.po index 5d6f9ae30d..b20060cac8 100644 --- a/apps/common/locale/pt/LC_MESSAGES/django.po +++ b/apps/common/locale/pt/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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-02 18:18+0000\n" +"PO-Revision-Date: 2012-02-21 15:07+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\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:20 @@ -51,9 +51,7 @@ msgstr "E-mail" msgid "" "Please enter a correct email and password. Note that the password fields is " "case-sensitive." -msgstr "" -"Por favor insira o e-mail e senha corretos. Note que os campos de senha são " -"case-sensitive." +msgstr "Por favor insira o e-mail e senha corretos. Note que os campos de senha são case-sensitive." #: forms.py:146 msgid "This account is inactive." @@ -105,11 +103,11 @@ msgstr "" #: models.py:43 msgid "Anonymous user" -msgstr "" +msgstr "Usuário anônimo" #: models.py:46 models.py:47 msgid "anonymous user" -msgstr "" +msgstr "usuário anônimo" #: utils.py:295 msgid "function found" @@ -152,7 +150,7 @@ msgstr "detalhes atuais do usuário" #: views.py:187 msgid "E-mail conflict, another user has that same email." -msgstr "" +msgstr "E-mail conflito, outro usuário que tem mesmo e-mail." #: views.py:190 msgid "Current user's details updated." @@ -168,7 +166,7 @@ msgstr "Licença" #: views.py:239 msgid "Current user password change" -msgstr "" +msgstr "Alteração de senha do usuário atual" #: views.py:254 templates/password_change_done.html:5 msgid "Your password has been successfully changed." @@ -181,20 +179,15 @@ msgstr "Nenhum" #: conf/settings.py:15 msgid "" "Temporary directory used site wide to store thumbnails, previews and " -"temporary files. If none is specified, one will be created using tempfile." -"mkdtemp()" -msgstr "" -"Diretório temporário usado para armazenar miniaturas, previews e arquivos " -"temporários. Se nenhum for especificado, um será criado usando tempfile." -"mkdtemp()" +"temporary files. If none is specified, one will be created using " +"tempfile.mkdtemp()" +msgstr "Diretório temporário usado para armazenar miniaturas, previews e arquivos temporários. Se nenhum for especificado, um será criado usando tempfile.mkdtemp()" #: conf/settings.py:65 msgid "" "Controls the mechanism used to authenticated user. Options are: username, " "email" -msgstr "" -"Controla o mecanismo usado para usuário autenticado. As opções são: e-mail, " -"nome de usuário," +msgstr "Controla o mecanismo usado para usuário autenticado. As opções são: e-mail, nome de usuário," #: conf/settings.py:74 msgid "Allow non authenticated users, access to all views" @@ -304,7 +297,7 @@ msgstr "Submeter" #: templates/generic_form_subtemplate.html:87 msgid "Cancel" -msgstr "" +msgstr "Cancelar" #: templates/generic_list.html:6 templates/generic_list_horizontal.html:6 #, python-format @@ -317,9 +310,7 @@ msgstr "Lista de %(stripped_title)s " msgid "" "List of %(title)s (%(start)s - %(end)s out of %(total)s) (Page " "%(page_number)s of %(total_pages)s)" -msgstr "" -"Lista de %(title)s (%(start)s - %(end)s de %(total)s) (Page %(page_number)s " -"of %(total_pages)s)" +msgstr "Lista de %(title)s (%(start)s - %(end)s de %(total)s) (Page %(page_number)s of %(total_pages)s)" #: templates/generic_list_horizontal_subtemplate.html:25 #: templates/generic_list_subtemplate.html:26 diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.po b/apps/documents/locale/pt/LC_MESSAGES/django.po index 6c35f3b702..937c0bd8c6 100644 --- a/apps/documents/locale/pt/LC_MESSAGES/django.po +++ b/apps/documents/locale/pt/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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 08:43+0000\n" +"PO-Revision-Date: 2012-02-21 15:13+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\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:63 @@ -71,9 +71,7 @@ msgstr "encontrar todas as duplicatas" #: __init__.py:77 msgid "" "Search all the documents' checksums and return a list of the exact matches." -msgstr "" -"Pesquisar todas as somas de verificação de documentos e retornar uma lista " -"de correspondências exatas." +msgstr "Pesquisar todas as somas de verificação de documentos e retornar uma lista de correspondências exatas." #: __init__.py:78 msgid "update office documents' page count" @@ -170,11 +168,11 @@ msgstr "redefinir visão" #: __init__.py:108 msgid "versions" -msgstr "" +msgstr "versões" #: __init__.py:109 msgid "revert" -msgstr "" +msgstr "reverter" #: __init__.py:112 msgid "document type list" @@ -226,7 +224,7 @@ msgstr "Conteúdos" #: forms.py:109 msgid "Page" -msgstr "" +msgstr "Página" #: forms.py:121 msgid "Details" @@ -251,7 +249,7 @@ msgstr "Renomear documento rápido" #: forms.py:185 msgid "Version update" -msgstr "" +msgstr "Versão de atualização" #: forms.py:190 msgid "Release level" @@ -263,7 +261,7 @@ msgstr "" #: forms.py:204 msgid "Comment" -msgstr "" +msgstr "Comentário" #: forms.py:210 msgid "New document filename" @@ -295,10 +293,8 @@ msgstr "Documento \"%(content_object)s\" criado por %(fullname)s." #: literals.py:12 #, python-format -msgid "" -"Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." -msgstr "" -"Documento \"%(content_object)s\" criado em %(datetime)s por %(fullname)s." +msgid "Document \"%(content_object)s\" created on %(datetime)s by %(fullname)s." +msgstr "Documento \"%(content_object)s\" criado em %(datetime)s por %(fullname)s." #: literals.py:18 msgid "Document edited" @@ -312,11 +308,9 @@ msgstr "Documento \"%(content_object)s\" editado por %(fullname)s." #: literals.py:20 #, python-format msgid "" -"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s. " -"The following changes took place: %(changes)s." -msgstr "" -"Documento \"%(content_object)s\" foi editado em %(datetime)s por " -"%(fullname)s. As seguintes alterações foram realizadas: %(changes)s." +"Document \"%(content_object)s\" was edited on %(datetime)s by %(fullname)s." +" The following changes took place: %(changes)s." +msgstr "Documento \"%(content_object)s\" foi editado em %(datetime)s por %(fullname)s. As seguintes alterações foram realizadas: %(changes)s." #: literals.py:29 msgid "Document deleted" @@ -419,7 +413,7 @@ msgstr "" #: models.py:307 views.py:1357 msgid "comment" -msgstr "" +msgstr "comentário" #: models.py:310 msgid "file" @@ -431,15 +425,13 @@ msgstr "verificações" #: models.py:318 models.py:319 models.py:542 msgid "document version" -msgstr "" +msgstr "versão do documento" #: models.py:411 msgid "" "This document's file format is not known, the page count has therefore " "defaulted to 1." -msgstr "" -"Este formato de arquivo não é conhecida, a contagem de página, portanto, tem " -"o padrão 1." +msgstr "Este formato de arquivo não é conhecida, a contagem de página, portanto, tem o padrão 1." #: models.py:525 views.py:1353 msgid "filename" @@ -589,11 +581,11 @@ msgstr "Execute as ferramentas de modificação de documento" #: permissions.py:17 msgid "Revert documents to a previous version" -msgstr "" +msgstr "Reverter documentos para uma versão anterior" #: permissions.py:18 msgid "Create new document versions" -msgstr "" +msgstr "Criar novas versões de documentos" #: permissions.py:20 msgid "Documents setup" @@ -601,7 +593,7 @@ msgstr "Configuração de documentos" #: permissions.py:22 msgid "View document types" -msgstr "" +msgstr "Ver tipos de documentos" #: permissions.py:23 msgid "Edit document types" @@ -633,11 +625,9 @@ msgstr "Documentos no armazenamento: %d" #: statistics.py:48 #, python-format msgid "" -"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d " -"bytes" -msgstr "" -"Espaço usado no armazenamento: %(base_2)s (base 2), %(base_10)s (base 10), " -"%(bytes)d bytes" +"Space used in storage: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d" +" bytes" +msgstr "Espaço usado no armazenamento: %(base_2)s (base 2), %(base_10)s (base 10), %(bytes)d bytes" #: statistics.py:58 #, python-format @@ -718,7 +708,7 @@ msgstr "Deve fornecer pelo menos um documento." #: views.py:218 msgid "Document deleted successfully." -msgstr "" +msgstr "Documento removido com sucesso." #: views.py:220 #, python-format @@ -742,19 +732,19 @@ msgstr "Documento \"%s\", editado com sucesso." #: views.py:342 msgid "documents to be downloaded" -msgstr "" +msgstr "documentos a serem baixados" #: views.py:352 views.py:1337 msgid "version" -msgstr "" +msgstr "versão" #: views.py:409 msgid "Download" -msgstr "" +msgstr "Baixar" #: views.py:411 msgid "Return" -msgstr "" +msgstr "Voltar" #: views.py:445 #, python-format @@ -768,8 +758,7 @@ msgstr "Transformação para página do documento criada com sucesso." #: views.py:481 #, python-format msgid "Create new transformation for page: %(page)s of document: %(document)s" -msgstr "" -"Criar nova transformação para página: %(page)s do documento: %(document)s" +msgstr "Criar nova transformação para página: %(page)s do documento: %(document)s" #: views.py:500 msgid "Document page transformation edited successfully." @@ -789,9 +778,7 @@ msgstr "Transformação para página do documento excluida com sucesso." msgid "" "Are you sure you wish to delete transformation \"%(transformation)s\" for: " "%(document_page)s" -msgstr "" -"Tem certeza de que deseja excluir \"%(transformation)s\" para: " -"%(document_page)s " +msgstr "Tem certeza de que deseja excluir \"%(transformation)s\" para: %(document_page)s " #: views.py:562 #, python-format @@ -804,8 +791,7 @@ msgstr "Tem certeza de que deseja encontrar todas as duplicatas?" #: views.py:575 views.py:633 views.py:701 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." +msgstr "Em grandes bases de dados esta operação pode levar algum tempo para executar." #: views.py:598 msgid "duplicated documents" @@ -821,7 +807,8 @@ msgstr "" #: views.py:632 #, python-format msgid "" -"Are you sure you wish to update the page count for the office documents (%d)?" +"Are you sure you wish to update the page count for the office documents " +"(%d)?" msgstr "" #: views.py:664 @@ -829,18 +816,14 @@ msgstr "" msgid "" "All the page transformations for document: %s, have been deleted " "successfully." -msgstr "" -"Todas as transformações de página para o documento: %s, foram excluídas com " -"sucesso." +msgstr "Todas as transformações de página para o documento: %s, foram excluídas com sucesso." #: views.py:666 #, python-format msgid "" "Error deleting the page transformations for document: %(document)s; " "%(error)s." -msgstr "" -"Erro ao excluir as transformações de página para o documento: %(document)s; " -"%(error)s ." +msgstr "Erro ao excluir as transformações de página para o documento: %(document)s; %(error)s ." #: views.py:672 msgid "document transformation" @@ -849,19 +832,16 @@ msgstr "transformação de documento" #: views.py:681 #, python-format msgid "" -"Are you sure you wish to clear all the page transformations for document: %s?" -msgstr "" -"Tem certeza de que deseja limpar todas as transformações de página para o " -"documento: %s?" +"Are you sure you wish to clear all the page transformations for document: " +"%s?" +msgstr "Tem certeza de que deseja limpar todas as transformações de página para o documento: %s?" #: views.py:683 #, python-format msgid "" "Are you sure you wish to clear all the page transformations for documents: " "%s?" -msgstr "" -"Tem certeza de que deseja limpar todas as transformações de página para os " -"documentos: %s?" +msgstr "Tem certeza de que deseja limpar todas as transformações de página para os documentos: %s?" #: views.py:711 msgid "missing documents" @@ -932,9 +912,7 @@ msgstr "Tem certeza de que deseja excluir o tipo de documento: %s?" msgid "" "The document type of all documents using this document type will be set to " "none." -msgstr "" -"O tipo de documento de todos os documentos usando este tipo de documento " -"será definido como \"nenhum\"." +msgstr "O tipo de documento de todos os documentos usando este tipo de documento será definido como \"nenhum\"." #: views.py:1152 msgid "Document type created successfully" @@ -962,9 +940,7 @@ msgstr "Erro ao editar nome de arquivo do tipo de documento: %s" #: views.py:1212 #, python-format msgid "edit filename \"%(filename)s\" from document type \"%(document_type)s\"" -msgstr "" -"Editar nome de arquivo \"%(filename)s\" do tipo de documento " -"\"%(document_type)s\"" +msgstr "Editar nome de arquivo \"%(filename)s\" do tipo de documento \"%(document_type)s\"" #: views.py:1221 views.py:1247 views.py:1255 msgid "document type filename" @@ -979,18 +955,14 @@ msgstr "Nome de arquivo do tipo de documento: %s excluido com sucesso." #, python-format msgid "" "Document type filename: %(document_type_filename)s delete error: %(error)s" -msgstr "" -"Nome de arquivo do tipo de documento: %(document_type_filename)s erro ao " -"excluir: %(error)s" +msgstr "Nome de arquivo do tipo de documento: %(document_type_filename)s erro ao excluir: %(error)s" #: views.py:1257 #, python-format msgid "" "Are you sure you wish to delete the filename: %(filename)s, from document " "type \"%(document_type)s\"?" -msgstr "" -"Tem certeza de que deseja excluir o nome do arquivo: %(filename)s , do tipo " -"de documento \" %(document_type)s \"?" +msgstr "Tem certeza de que deseja excluir o nome do arquivo: %(filename)s , do tipo de documento \" %(document_type)s \"?" #: views.py:1282 msgid "Document type filename created successfully" @@ -1022,7 +994,7 @@ msgstr "" #: views.py:1331 #, python-format msgid "versions for document: %s" -msgstr "" +msgstr "versões para o documento: %s" #: views.py:1341 msgid "time and date" @@ -1038,12 +1010,12 @@ msgstr "" #: views.py:1380 msgid "Document version reverted successfully" -msgstr "" +msgstr "Versão do documento revertidos com sucesso" #: views.py:1382 #, python-format msgid "Error reverting document version; %s" -msgstr "" +msgstr "Erro ao reverter versão do documento; %s" #: views.py:1389 msgid "Are you sure you wish to revert to this version?" @@ -1075,38 +1047,29 @@ msgstr "Próximo passo" #: conf/settings.py:38 msgid "" -"Maximum number of recent (created, edited, viewed) documents to remember per " -"user." -msgstr "" -"Número máximo de documentos recentes (criado, editado, visualizado) à ser " -"lembrado, por usuário." +"Maximum number of recent (created, edited, viewed) documents to remember per" +" user." +msgstr "Número máximo de documentos recentes (criado, editado, visualizado) à ser lembrado, por usuário." #: conf/settings.py:39 msgid "Amount in percent zoom in or out a document page per user interaction." -msgstr "" -"Quantidade em porcentagem de zoom em uma página ou documento por interação " -"do usuário." +msgstr "Quantidade em porcentagem de zoom em uma página ou documento por interação do usuário." #: conf/settings.py:40 msgid "" "Maximum amount in percent (%) to allow user to zoom in a document page " "interactively." -msgstr "" -"Valor máximo em porcentagem (%) para permitir ao usuário aumentar o zoom em " -"uma página do documento de forma interativa." +msgstr "Valor máximo em porcentagem (%) para permitir ao usuário aumentar o zoom em uma página do documento de forma interativa." #: conf/settings.py:41 msgid "" "Minimum amount in percent (%) to allow user to zoom out a document page " "interactively." -msgstr "" -"Valor mínimo em porcentagem (%) para permitir ao usuário diminuir o zoom em " -"uma página do documento de forma interativa." +msgstr "Valor mínimo em porcentagem (%) para permitir ao usuário diminuir o zoom em uma página do documento de forma interativa." #: conf/settings.py:42 msgid "Amount in degrees to rotate a document page per user interaction." -msgstr "" -"Valor em graus para girar uma página do documento por interação do usuário." +msgstr "Valor em graus para girar uma página do documento por interação do usuário." #: templates/document_types_help.html:3 msgid "What are document types?" @@ -1118,12 +1081,7 @@ msgid "" "such as: invoices, regulations or manuals. The advantage of using document " "types are: assigning a list of typical filenames for quick renaming during " "creation, as well as assigning default metadata types and sets to it." -msgstr "" -"Tipos de documentos definir uma classe que representa um grupo de " -"documentos, tais como: notas fiscais, regulamentos ou manuais. A vantagem de " -"usar os tipos de documentos são: a atribuição de uma lista de nomes típicos " -"para renomear rápidamente durante a criação, bem como atribuir tipos de " -"padrão de metadados e conjuntos para ele." +msgstr "Tipos de documentos definir uma classe que representa um grupo de documentos, tais como: notas fiscais, regulamentos ou manuais. A vantagem de usar os tipos de documentos são: a atribuição de uma lista de nomes típicos para renomear rápidamente durante a criação, bem como atribuir tipos de padrão de metadados e conjuntos para ele." #: templates/recent_document_list_help.html:3 msgid "What are recent documents?" @@ -1134,6 +1092,4 @@ msgstr "O que são os documentos recentes?" msgid "" "Here you will find the latest %(recent_count)s documents you have either " "created or edited in any way." -msgstr "" -"Aqui você encontrará os últimos %(recent_count)s documentos que você tenha " -"criado ou editado de alguma maneira." +msgstr "Aqui você encontrará os últimos %(recent_count)s documentos que você tenha criado ou editado de alguma maneira." diff --git a/apps/folders/locale/pt/LC_MESSAGES/django.po b/apps/folders/locale/pt/LC_MESSAGES/django.po index 800226640a..356c2a7fc1 100644 --- a/apps/folders/locale/pt/LC_MESSAGES/django.po +++ b/apps/folders/locale/pt/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Renata Oliveira , 2011. +# Roberto Rosario , 2012. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: \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-02 18:19+0000\n" +"PO-Revision-Date: 2012-02-21 16:47+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\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:18 @@ -57,7 +57,7 @@ msgstr "" #: forms.py:38 msgid "Folder" -msgstr "" +msgstr "Pasta" #: models.py:11 msgid "title" @@ -89,31 +89,31 @@ msgstr "pastas de documentos" #: permissions.py:7 msgid "Folders" -msgstr "" +msgstr "Pastas" #: permissions.py:9 msgid "Create new folders" -msgstr "" +msgstr "Crie novas pastas" #: permissions.py:10 msgid "Edit new folders" -msgstr "" +msgstr "Editar novas pastas" #: permissions.py:11 msgid "Delete new folders" -msgstr "" +msgstr "Excluir novas pastas" #: permissions.py:12 msgid "Remove documents from folders" -msgstr "" +msgstr "Remover documentos das pastas" #: permissions.py:13 msgid "View existing folders" -msgstr "" +msgstr "Ver as pastas existentes" #: permissions.py:14 msgid "Add documents to existing folders" -msgstr "" +msgstr "Adicionar documentos para as pastas existentes" #: views.py:37 msgid "created" @@ -205,18 +205,14 @@ msgstr "Documento: %(document)s erro ao deletar: %(error)s " msgid "" "Are you sure you wish to remove the document: %(document)s from the folder " "\"%(folder)s\"?" -msgstr "" -"Tem certeza de que deseja remover o documento: %(document)s da pasta " -"\"%(folder)s\"?" +msgstr "Tem certeza de que deseja remover o documento: %(document)s da pasta \"%(folder)s\"?" #: views.py:272 #, python-format msgid "" -"Are you sure you wish to remove the documents: %(documents)s from the folder " -"\"%(folder)s\"?" -msgstr "" -"Tem certeza de que deseja remover os documentos: %(documents)s da pasta " -"\"%(folder)s\"?" +"Are you sure you wish to remove the documents: %(documents)s from the folder" +" \"%(folder)s\"?" +msgstr "Tem certeza de que deseja remover os documentos: %(documents)s da pasta \"%(folder)s\"?" #: templates/folders_help.html:3 msgid "What are folders?" @@ -228,12 +224,7 @@ msgid "" "individual users create their own document organization methods. Folders " "created by one user and the documents contained by them don't affect any " "other user folders or documents." -msgstr "" -"Estas pastas também podem ser descritas como pastas de usuário. Elas são uma " -"maneira de permitir que os usuários individuais criem os seus próprios " -"métodos de organização do documento. Pastas criadas por um usuário e os " -"documentos contidos nelas não afetam todas as pastas de outros usuários ou " -"documentos." +msgstr "Estas pastas também podem ser descritas como pastas de usuário. Elas são uma maneira de permitir que os usuários individuais criem os seus próprios métodos de organização do documento. Pastas criadas por um usuário e os documentos contidos nelas não afetam todas as pastas de outros usuários ou documentos." #: templatetags/folder_tags.py:17 msgid "Add document to a folder" diff --git a/apps/main/locale/pt/LC_MESSAGES/django.po b/apps/main/locale/pt/LC_MESSAGES/django.po index afe2cb2f60..b60110fbf9 100644 --- a/apps/main/locale/pt/LC_MESSAGES/django.po +++ b/apps/main/locale/pt/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # 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" +"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-01-02 04:46+0000\n" +"PO-Revision-Date: 2012-02-21 16:38+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\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:33 @@ -61,11 +61,9 @@ msgstr "Diagnósticos" #: conf/settings.py:12 msgid "" -"Controls whether the search functionality is provided by a sidebar widget or " -"by a menu entry." -msgstr "" -"Controla-se a funcionalidade de pesquisa é fornecido por um widget da barra " -"lateral ou por uma entrada de menu." +"Controls whether the search functionality is provided by a sidebar widget or" +" by a menu entry." +msgstr "Controla-se a funcionalidade de pesquisa é fornecido por um widget da barra lateral ou por uma entrada de menu." #: templates/about.html:5 msgid "About this program" @@ -136,16 +134,13 @@ msgstr "Ações" #: templates/home.html:8 msgid "Django based open source document management system" -msgstr "" +msgstr "Sistema aberto de gerenciamento de documentos baseado em Django " #: templates/project_description.html:6 msgid "" "Open source, Django based electronic document manager with custom metadata, " "indexing, tagging, file serving integration and OCR capabilities" -msgstr "" -"Código Aberto, Django gestão de documentos eletrônicos com metadados " -"personalizados, indexação, etiquetagem, a integração do serviço de arquivos " -"e recursos de OCR" +msgstr "Código Aberto, Django gestão de documentos eletrônicos com metadados personalizados, indexação, etiquetagem, a integração do serviço de arquivos e recursos de OCR" #: templates/project_description.html:18 msgid "Released under the GPL V3 License" diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.po b/apps/tags/locale/pt/LC_MESSAGES/django.po index 9cb59e63b0..72632ba281 100644 --- a/apps/tags/locale/pt/LC_MESSAGES/django.po +++ b/apps/tags/locale/pt/LC_MESSAGES/django.po @@ -4,14 +4,15 @@ # # Translators: # , 2011. +# Roberto Rosario , 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-12 19:23+0000\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/team/pt/)\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" @@ -136,19 +137,19 @@ msgstr "Criar novas etiquetas" #: permissions.py:10 msgid "Delete tags" -msgstr "" +msgstr "Excluir etiquetas" #: permissions.py:11 msgid "Edit tags" -msgstr "" +msgstr "Editar as etiquetas" #: permissions.py:12 msgid "View tags" -msgstr "" +msgstr "Ver etiquetas" #: permissions.py:13 msgid "Attach tags to documents" -msgstr "" +msgstr "Anexar etiquetas para documentos" #: permissions.py:14 msgid "Remove tags from documents" @@ -246,5 +247,3 @@ msgstr "Tem certeza de que deseja remover as etiquetas: %s?" #: templatetags/tags_tags.py:17 msgid "Add tag to document" msgstr "Adicionar etiquetas para o documento" - - diff --git a/apps/user_management/locale/pt/LC_MESSAGES/django.po b/apps/user_management/locale/pt/LC_MESSAGES/django.po index 2203e31166..98a9cfcddf 100644 --- a/apps/user_management/locale/pt/LC_MESSAGES/django.po +++ b/apps/user_management/locale/pt/LC_MESSAGES/django.po @@ -1,22 +1,22 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Renata Oliveira , 2011. +# Roberto Rosario , 2012. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: \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-02 18:18+0000\n" +"PO-Revision-Date: 2012-02-21 15:07+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" -"team/pt/)\n" -"Language: pt\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 @@ -117,15 +117,13 @@ msgstr "ativo" #: views.py:47 msgid "has usable password?" -msgstr "" +msgstr "tem senha usável?" #: views.py:61 msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." -msgstr "" -"Edição de super usuário e usuário pessoal não é permitida, use a interface " -"de administração para esses casos." +msgstr "Edição de super usuário e usuário pessoal não é permitida, use a interface de administração para esses casos." #: views.py:68 #, python-format @@ -154,9 +152,7 @@ msgstr "Deve fornecer pelo menos um usuário." msgid "" "Super user and staff user deleting is not allowed, use the admin interface " "for these cases." -msgstr "" -"Excluir super usuário e usuário pessoal não é permitido, use a interface de " -"administração para esses casos." +msgstr "Excluir super usuário e usuário pessoal não é permitido, use a interface de administração para esses casos." #: views.py:126 #, python-format @@ -186,9 +182,7 @@ msgstr "Senhas não coincidem, tente novamente." msgid "" "Super user and staff user password reseting is not allowed, use the admin " "interface for these cases." -msgstr "" -"Redefinir senha de super usuário e usuário pessoal não é permitido, use a " -"interface de administração para esses casos." +msgstr "Redefinir senha de super usuário e usuário pessoal não é permitido, use a interface de administração para esses casos." #: views.py:187 #, python-format From da6d1c474b6f8bce88380c2bb17e500897a10dac Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 16:14:40 -0400 Subject: [PATCH 468/484] Update compiled translation files --- apps/acls/locale/it/LC_MESSAGES/django.mo | Bin 489 -> 1862 bytes apps/acls/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 562 bytes apps/common/locale/it/LC_MESSAGES/django.mo | Bin 5097 -> 5646 bytes apps/common/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 5427 bytes apps/common/locale/pt/LC_MESSAGES/django.mo | Bin 5151 -> 5561 bytes .../converter/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 8156 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 3792 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1793 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 6544 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 2101 bytes .../documents/locale/it/LC_MESSAGES/django.mo | Bin 17995 -> 19387 bytes .../documents/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 7333 bytes .../documents/locale/pt/LC_MESSAGES/django.mo | Bin 17559 -> 18726 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1602 bytes apps/feedback/locale/it/LC_MESSAGES/django.mo | Bin 489 -> 3115 bytes apps/feedback/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 562 bytes apps/folders/locale/it/LC_MESSAGES/django.mo | Bin 3984 -> 4562 bytes apps/folders/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1562 bytes apps/folders/locale/pt/LC_MESSAGES/django.mo | Bin 3923 -> 4480 bytes apps/history/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1533 bytes apps/linking/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1830 bytes apps/main/locale/it/LC_MESSAGES/django.mo | Bin 2499 -> 2673 bytes apps/main/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1464 bytes apps/main/locale/pt/LC_MESSAGES/django.mo | Bin 2540 -> 2716 bytes apps/metadata/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 924 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 714 bytes apps/ocr/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 562 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1161 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 656 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 606 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 710 bytes apps/sources/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 2678 bytes apps/tags/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1393 bytes apps/tags/locale/pt/LC_MESSAGES/django.mo | Bin 3457 -> 3683 bytes .../locale/it/LC_MESSAGES/django.mo | Bin 4714 -> 4831 bytes .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 4850 bytes .../locale/pt/LC_MESSAGES/django.mo | Bin 4698 -> 4805 bytes .../web_theme/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 714 bytes 38 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/acls/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/common/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/converter/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/django_gpg/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/document_comments/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/document_indexing/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/document_signatures/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/documents/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/dynamic_search/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/feedback/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/folders/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/history/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/linking/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/main/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/metadata/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/navigation/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/ocr/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/permissions/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/project_setup/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/project_tools/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/smart_settings/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/sources/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/tags/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/user_management/locale/pl/LC_MESSAGES/django.mo create mode 100644 apps/web_theme/locale/pl/LC_MESSAGES/django.mo diff --git a/apps/acls/locale/it/LC_MESSAGES/django.mo b/apps/acls/locale/it/LC_MESSAGES/django.mo index 889b3132c9e73fd5daa9cff1a3dd97941dcde83a..62329ea64c0367181f1201a15da503d613bc0a50 100644 GIT binary patch literal 1862 zcmbu8J&YVR6vs^nfh+-%@F5BirU={$W@mPFz-f{t7jhSLC@YS;JtQjRoq0R!FgqUE zp8Hr)(WO902!!Zp5FH&YEe%4VLlkuMAkonAf3tI6aEb_6dj8oS`@O%P=lyc=^rr&t z3D{Gx?_p2F-oFPO+Hc_f;P2oA;Gf_b@YE?7coyAN@Eo`d-fZ|Gcn$L(Kt6x|-ubyF z8$JW_`g7oYV5gZcHoVfTuYeEZ`x{^jd;4tI0R92K44%QI*?%8|+*%v!;#_c?bFjx?55f2xH+~z)JZS8f8(fO>u!}HUyKb!E z@n-x8$Xd8@?l`WHV`Jqd2U;_&2i`DVl;WBtxo0Zrs%EgG-9+MZW>w*(pO7rcPPKE| z6!Ox7*FL9rT{Rx--L|`Wcjw*RIIy&B-lPAa;6w)}Nw{uFd1J-v)>Nevo0L=H#b!x~ zR=L=6WSvNwJt=vmb0_Nbh>3DX(jyKtb!6y{j-}ehaW%?uF%u&lDnaD7o4?S48Qp3- zF&8e@t+@pu!CD%;4GGA9EC*^&6>@cDu-V$6(pVo1T&C0DwJLML5FRJqmvIp*XznCiWj>tL};y>%K2c3pT^~!%vf%i5n2358}s<`ik&ZX8bO`R6f>36Y&n}E zC#>~Vcqy_!$EjK<{3Oi+kFIqg?6YvP>q*I`aLk;f-MFa39AUlMPmj#H6~& zV!1TZ{y=UlFhPR*-O6krH_~#^)@xMICKVhQ&d*FlfcZk~* z9-;E8veb3u@#PS9zx+sS@k{Cb0wjS7^eW4-vY#82;Xl$Nj%Q1t;Et{6;~O+m?n+bW Wk{# tFto5TGMMboGFhx7H8EE|vqWE$%O^1}y)-dB)k-0=Wb%8K=*i)%+5mq+6zu>2 diff --git a/apps/acls/locale/pl/LC_MESSAGES/django.mo b/apps/acls/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a0ad603458116041b7422d1ac31c2307b0938fa4 GIT binary patch literal 562 zcmY*VO>Yx15G{h!9yxQE15}B?vAv{H>SkL)vymcYAxgH~-NfA(?b<8bOIoRagTL3` z(IexuYQ;!T9?yI8`SAYT-y^g)h!2R5h_{F@h-f3kBa)~1M$L;Yo&Bvgfy}q$mvUZP zBcPCX(m*~f*2zk>)&)}dN^i;cuJWX`0(K#^g3?NdU3Wd$*oHdmrPJ2YCgxJ@eW!e~ z{8^Gqr)0pgWGaIakTRYUmJ*%OgrqflvUZ11XRGq98DV1ylEN!j*4tmd{@Avybh;{Uh zx*Zr5X!~>sPur&*h}t%u*3VUFTho40%!~Z>OnktSOKXBMIMZE=%LR3dg=(qI8Ekga zc@?s&az;k4y4dqZIg*==-D*<_7+ve|GOd8NPL_4&WKCw)HC}*e4_}{sJwq}wSUONB;m>{-Ems literal 0 HcmV?d00001 diff --git a/apps/common/locale/it/LC_MESSAGES/django.mo b/apps/common/locale/it/LC_MESSAGES/django.mo index 95680511703bc58b937191c73453b90c1eab4030..6e25f2e7c5d0682b18ae60136ae2316221356ba6 100644 GIT binary patch delta 2054 zcmYk+S!f+q9LMofvo?Dht+94Fw$_{4+gy__nrN4F6Qqg(?Sn<=Xn+78#%ED~{{k1{cc_Ga$EDcTXiN@! z@MheFN~DZ>m$&dHJdSlZi%raLPIJ=5jdM5`e??7n1=aDd?D{G)m#L+b5@^9;%;92u z8P)#;F2R$iN}a<_{1TPO&!`u>gze04{^n#iHZ~DBf=Zx-dLTl&m`Uu#=d-_`!ed;| zqAIYf*_c~!AFjn$P)l+K*Wp>z68wuwG~Yt~l}R5b?Kp@x;t*<}QRHWyZNfKD zZ#aX>_#@N+-y%Qr0|$y=uAm0e&Qb-6sD35XcyV_BDJ*ckAC>4SJb@phHtCedf@`7! zsPFV`R00=qE&hZ(*u}S_iS9>LUl-_@{(o-sj@knc^;MEWz;x-ruV1J zRZiG5)rX+k205x4cN2O@3Eo9$;?0B-TTLhdwSkms;`eZ_QmZL(eF547s*09KZ@r#a zL#)&HuXXMvw9&3Lt*zclYp=!^V_FGio+J7Qm30%Ljk<-<7qFaA(w# zrc{q}^?hz5x|3(>Uft~b!GtXbW$VPzxLc0Aq7%6zHV)lNn72-`=!T(<0_*s`-RHRz zp&6w2WGRTlYNupg{dApEF1mj5di~K3yVnWBiJ&rKi{nmt%uR9)!@a9Zj_2EAP#*QY zV#KKBfVnEw=k2(|_~TAwL#O0gS6zEPc&XuVO&i^=pQx+(!`yfj?Hwo-#=K}e9_}dy zr9veLor)J!3MFUKDHpsjjNLH#s(D*uU$5<5Kd@$9vbZH_^+_gn#@vDz6;>vnwd`)% zncW$%$&%JjhPDRfP_JKctuy9(HjZ?4tuk3*yu9^uX-%kzjp8VBt?yEpFmlbKdW6SG z+badh#nyv!2g~Ky_nnHHJkfTn=fPma8>PT@#O3DyrP5`tI-yIIDisZ5wk10|7bUj+ wq5kdH*Ds2Kyp35dKdJ<2mM%54PsY_T$s-J%Yh^68e_qp?4VZPJEBakG*h$Ol^^x$hj-{092IP9FyoU=1?{xkDG-MK%q{8I^`y@pao zO;ZgvX0Ht8LOC5~OevnhE%+SiV#2}$x*Vf1gy$aIhzXdBJ8(XpM2+inyoM3R_|0`1 z9{w1@oj8j8OgR6hq8k@rHfCW3&c$P>7&|cuyO7w-07l^*oQESAiDRgFKcMhOn;U&aOMY51J0se+=*JrO;mt`sPRuR0be3h zn2)G=exkN~TYRA3Zq$7H{WR>ez&swbq9VP4xA872>2@)zUUVGwd3B)zc#X=5F#JC2=Kc=bDiz%_Srz;~#Vyqo@_UKuz%0c|M7xfLTb@z%r_e5>Wj!sR~GA zbk-}VN=6kgbv>2X%u?zi>Po5tS5O4xx6fHyp<__dD%aVqz$G8_z3UrSQt7-4samay zc8&bB6LtgY`2H6q-7@D!yR?{E;N0h6Det$7K9izA)800xX>XC*I)d4S#J0bEJ=1Z` zE+yP3`SfY3ED2yIVixVyROOKUX=^nqDc0Yx%T_`}hBXu3Vl_qdTB)v@;ajc?A=c)Y z$5y7h+?8LD=`Aes7FtK#R3&Blf(N a8rK(8ZnY()S%2cT51)%43$f~w?*9WOz>B#6 diff --git a/apps/common/locale/pl/LC_MESSAGES/django.mo b/apps/common/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..62f690afaa8a1fd0b66559de5dd3ea6b573c99b0 GIT binary patch literal 5427 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 bJ=QJnKtzRAmg=+G6Zen!lBS|8XX@QQW0s4P diff --git a/apps/converter/locale/pl/LC_MESSAGES/django.mo b/apps/converter/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..97377fe2b535800b8592dacdee9b6ad6ceee7b5c GIT binary patch literal 8156 zcmeI0TWlOx8OKkWUZ|lIQVQkPexWqkrJlXnaguG^)Lwh-NxboPckMU^LeB1vcTYV# zv&UxGZ&3%dLV5JQOwQtTzXV451Ft~+>)>lUgt!bZ z<$1mFuK4-u@iKnjZv3E&*sse+K=zMQAlttWvRxhp$H227+xs<;=Y0bPWqlj~Zv}mj z{pHIbTvt2|vL4QYyxu>8JpL=-Ztxl?2e%>(a(fYEJ1v3i&n*zI68C`YCl7*bw;zB! zkDVBdNg#paAkXI{$j?6nvOj(sNAW|T0(qP-fUKv7L5_!SfO+t{AdmBRkk`2vKkUavkoD9B(IoBzVLI_O zkp1WTAnW_LAdmYuUB45Jtk0W49_Jv)?G2Fi9fDVb4}u&QkAXbD$3gbH?||(8KLlBS z&x0H{zW{fD2!m+-fH(zV-5rA52B|`(A^aR)83^0r7-T1;4B?CYWaA^RX4n{4;Z7wh)`1SS^?5VjBNi2aqX0z^i4@eljuJcR9j6mkcIuT+f4{!{wi z0EZ#Vy3F_lgnfVWHGu+LU)%{9(+!-@*tTqUwl&+8Z8{3!>qLy`mwj(HgnjHd1Ysy< zAbhc3aLls5-40lT@| z9r}SM1J|QMHK%KrN^{h)0@;*-6ce_Re)_mPZLN5&6X?e$D@B^97EF^SJ*jNlq7~Qc z$UqbdW`)KwSsKk}^I5{UqxoDuM~Qe&u4DI;q97gDp()i;fwZY0JC-M@B70==+^DFB zYD)*Dply+7`K}!X3Qr}Jm8Yq)nWUZy+HM$dqgqo=D{;? z=fDd*%V}Dk<%uKZ=^4By=(*nNKtVnwY*p_%Ey|{HsnOhUgwbJILv>U)k{XFBM^dB7 zXb2;h$z-sECTtcU1UgjhJApj2sgd16JKLKZkCbzfS+;g?G2>X5P+DZX=`&r+3w+Gg z4ZC!tXcqO7DPbO&p=dp0xuiJSc0JdpMdgRmR%@YfjORWAyxRI;%Cb-5J-BMRuglqSaIvR+) zEknmnt7CaX$3lB^+46ii9sCrb-xzq@`upRjs|`==pfqY`D&*+9~B>&?(kNHS|_w120=2bxYrP zS)6HH-|{F?G7HH#vNs+XBp+nqj_m4)x^y$0X00HJJrt=lHlw=sSMjXZP_%?n?o?59~i!BAyq3RyTGXT1J0zLA7FDq#)zKW?4nUc-3~4C zWe1D)*DHpp1;seS#5vtVI=yHIZsbnV?zZIxx}iNDB^vO&4vjui^7_EMHCdt(Atfqq zAOlNO7miT{>$1Eku~r+>mUX0}EuKvY-iULl{i(5Gs&KN*rABh8Oj2C@iDk2l?QF0M zCNDLFLdvFDtg_mctC*DQ^x@6QaqU3H`_@JT$E_2QHm2C*Z`!P*$GKK--doCW>)L#I zeh%l4XjD;?t=3>eJ1@^B#zy({f~n7$lQpwg9EM)v&=^S_7h2JV9fir8 z!lQOxGfo3GvO#p#*cwRO^E6Hd2!NXOT2hDhLLl2z3E5qpR?sHPX<*-J>efZGFi}CO z9TTXD_4Vw^Y-Z3|qcYbMw>=f^I&Y#$mD@)>H8QH1-4O zDc4JP_}R4b{m}A<%JVg&fRg~5)|f&d<|&uS=8R0v$mS@!FQ3a8nbAxJ9gT`M^Ok6~eXrL`VK;Sr95v6R94kn7V_o>^ZoCY`YIgjztw%|B?R0XeWR|8kG?h(d zhWHc#oz)26|5DhydhyG7KT9!LXI+8qht+}QwyRqgz_eeuw`Q4QMY^hsow8p*q+zU5e zxc%j_{pFI{{&Ly=a^Ww-?Jt+@FPHW22OOyRQ|7<_<+8DlMLU$(Qcj8aI==no+55J? zX7I0xi+_@Af6eIsD{Xwa{Lg*Ol--^>`_QVtCfu&_MZBOs&c15(N8jp+Uf*|Dam+(3 UIC8Bg1y1hKH;un$d4raJ0dnGdr~m)} literal 0 HcmV?d00001 diff --git a/apps/django_gpg/locale/pl/LC_MESSAGES/django.mo b/apps/django_gpg/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..ba04420b9dd315bfc52cc64dc34350c16fc72df6 GIT binary patch literal 3792 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 literal 0 HcmV?d00001 diff --git a/apps/document_indexing/locale/pl/LC_MESSAGES/django.mo b/apps/document_indexing/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..be1ea792f55a59501b6fdb71fb1c833552427ce6 GIT binary patch literal 6544 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 Bkb3|C literal 0 HcmV?d00001 diff --git a/apps/document_signatures/locale/pl/LC_MESSAGES/django.mo b/apps/document_signatures/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d7269c5a2936b0eabd036b21241262c2d6e754d8 GIT binary patch literal 2101 zcmeH`y^kC<7{(1bzBYU%d>&9Z5*OVHyz_AvDa_r5K=vY?VBwT(()(t-vxfP?_GGgt z5(OnKbO<_VC@2vP5)Bn4l&PRhiG&0N&pSK2d*Y(}17OMf8{3cH_kHa3?bB8` zm(YJh-$4K7KK!6vyq~cy_y+hC_&!LwkH8N2Irt>_HTXFA9Z36s0#Ac?K+>@jj6DXN z1kZr$;0xeR%j@977=Hj#ybs&?Prw&3{tBdcKZ2zD1$-8~4N~4eK&oqPZJzH8NO4{T z|ALo3NIqVBaPA`pNk0XtzE45Ye+g2&Z$a|$14wy)2TAuQNIp(HH1}}|Bp+KX-vOyU z4N^SQ&VLM&k1s%q_dQ6upF#5RD@b|ofK=DtAmv+!h~m5q(v{F1JcIrSI<+U}V9$Zr z(zFNgOR*OX*4fE+Krt!*qS3umUR+btaEwhokG5mV4a@9lbn<-)o!awrFg8$5#uJrr ztJ6Zd+9+OESt%2ms^eH$JFc^A)?IaIGTR+q)GiPbsXW65HzJ;LP$FqI#w1Q)<2((=XNNVuhvH;1%jKeF^LsrK=fITjso07AM8Gkbi1<*>WWo0a!>gSusw#~WL!0VEyjiDK zjLL{loU0Zj9b&rv8nRyTWvavqM3&cb@t+=fs|ZoRCH z;#HZ~?F{#ad#jTQdVc3piR=Z+YW|P(H-%E_Vu!~QX{>VnYop8J{7OeT$I6JkA}$kM zq!B-VsNJ&Kh*w$XAghhc#O2cDcnC$+3~hgF2aB}Q-z@t5fWOXtj^&NOzt9i)*|W{( oZhxCTH)-164Sas+i zxT3WdrCPzO3M^8*%i)D5i1I*drPaPZ-$SwX^&!=^-`~!Ef%iHuzkL4l-<|oNGs!#6 zSuZ`1mH50}&L+cglyoCUS{Tze%b4c2sx`)GXUqufg_q%#I1#tvH2gcx!t(b1=Qra> z&fmqMnBBpcN*sYTxD>C^=QzZegy~;wOa&G5Q8!wLqwxslVL?Y@24E*_i4#!uGpuuM z{WbP{F>H8dPY;#ky$Q5=CU;%YpF z>iDwGbP6BB-uM|7;eSybDC%NN5A2N>;6&8-=3*u7o0tl?4K-!Qk=ZkCy80J7sPplt zRk<8>gCO?8wKxd3;y^r%m*7vR4$ipHm?~V2{c)#ciH~D~z!tW<6>IPoS>bW9#2Rb?{3pz|%M$TQY2x*-S@uWFe{pccb>w^F5egL+z8v9PiTwKQFj zKA1Ap9=ZZsU>Nn3#j&NH|Jx{NQ{9Pb;6YTwk6O2*M)E4^IX;Z)=(ng2v}KyK=G~Ad z(o~_YpMyN&W)W)d#F0rhcc89&2K(yye~CgN6(>+5{Ris8AFb_6{SFSqJnE}aBbc%ywj?|-We2e{j4QeUx#(Yd#A4V;~lbFzro~NJ@y@qPw2xAOS$KmT`%)d(^hfk+s z*t!cxaDE0Wu!3I{O%RvhMqG%ek$ai>ytn0AoQWyqC;g16gOxmM8ps&b`SsSN2@0CJ z6{s1w$+`};nKobnZo^XCjdSq}EX2xT{?jlS+i@Pm))+%IbSvtGb|+55{aB6p!`Ua8 zm`Z^kbAVq{@CWRV;~0K>T!J0233<7h_4a%xGOOlI)KvZxC*rV?{*1*@YrYjV^1Y}f z`U*9m|03^)gee&1k8C*7IkO1W!+Y@td=JNC8SmNY7)EtuH-3r7up_?8Fj)=rF>-Iy zf}3bYFG4ju9lK%>FTk6yNY8&W1-(!nw!Vy-%HyahJBeL!_!xf=%tkekK<$OysI~7t z)^{edI_5^y3_XjQ!B0{5J%xI@vM-{Z_DvB5O?5w1kE^i+r{HDi+WI~CGtT!ReKKR1 z_rX#FiV&={(hM)s1EEy-Tx?RU?(uqg2I3a{H4NjybdC{e4=PY!9F5vElTmAU9ctuvp}zM7s(~H${1w!udINR+C#aErf$I48*a!2N_fi~e zU67!lskjw2()&;&Orai=53x7?*&5&x(3JK?jchKegEgob+koo8HtdW$Z2dvh{Z3#@ zJcVjEahig9-e!jXuJ4B0?Y&Vinu|~!TaOy?v#17M#2h?e&)>Fwg#D=h6L!L!i~aj| z!#11`#ylL2JOv3e$yUrkP1)6`8`q;oxB^??8q}t|3)S;2sK;m*>biZXHT@V{;diL( z|Bbr7?InJF2h8WZ2d1C@(sY5x2{nbYP(7_h-FOA+Rl63|z$Prg9jG<^1l8afYtE(q zR2QH++#LtuFx368M|Ef=rvLumtO6D5P*cAiwMI|b`kk1?`Ge#NqQ>;N^&*SO$E2A& zLo!F)7Q#5smU(TYkKz1QJ1>#MZRsjTYt3*Ag&W9+Bt@2zKa%%}W-U+dNTZj_HU#VAotoTp>IhsY$-MD8c!$N{xKkQ^cRk<780!t3N_Tk#~mZOi4>8P*U!O`a#a z$UQ{IugC|akZdLAAMH4~lO#IX+K2EJ(%znnM{Kz*UQQk*zbBWGMdY_6eN3#ccj|+& zP{dgoibP#6>;#wSEVk5*I$k*BtaACr;*e7tst?6NwNA|Q%8af`#)?W)TMNGqbc%$y zHpVCZRrW^XlXHr?CO5QyqR3448X7|3SX70^NGO`D>M*si)~kuDHq&sbvBNEaaHh{_k$Dck7y+Jl^wY zzj=P|GGB=eWsYnc+WzzwZBcjMUV#!#|SC-m8 zuq?Yv%!`DBkq{HJg2rOO%)mm)*+V)fzaO%>*vqV<>#rh1jD(UK%f?^W#I9j~xK23k ztqf(ZblEX(YH!(rK<7}s+u(+2%&GArkx-18VckPzsivVNITZ{1Nl)*vv$O3v5w|ho zMp;|`y08Cjd_FVcraXh-gVx&n~iZ&g;i^^Q_W)n zS(Wq7-k2NEOS=tSCs^ym!{Em9MzrKhRpvCVR6m`dJG0& z?iF(zx#78cdZ~`%3$t3JH;k9+GvTU0o?Vnss(#XYf!61BB{^#9rgQt|;MB%(nXjhz f3v=wAEjW!lp_z_*)lT22Y4W@V#|`^>@tFA^99ufz delta 4471 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 literal 0 HcmV?d00001 diff --git a/apps/documents/locale/pt/LC_MESSAGES/django.mo b/apps/documents/locale/pt/LC_MESSAGES/django.mo index 2f39bc5b394590f7d2d92f49004fba110081b2b7..4b98fb49f1b2227ee464c158daebbf7581a8f0ce 100644 GIT binary patch delta 5287 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 DY;Vhk diff --git a/apps/dynamic_search/locale/pl/LC_MESSAGES/django.mo b/apps/dynamic_search/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0f097a581d0fdfcaa393a81dbaf7e2b424d5cc72 GIT binary patch literal 1602 zcma)*&x;&I6vs;we@*0~5;{9EnCy~32FL6~y)BjQnwi?^u4=2Q z)7wKp3HT@Eukh;8gMy1U!J8n69`xePs~5l3-IL9l2tKI!^!rh--g`Cm%i76%1o9Hr zYgk`ly^eMLG5kQj0p9?>1y6#1fKP&df-i!9fzN{{9w+2ka1DF`JPW#bAAADb1fK)r z&VLm=3;h%DDewT?0Y3*_{_jDT?+4K3`MKk-;NLj&cW?mvZ*aQ&r|{$Uod#W9uYzmf z0DKwT0?&XSg3o}9jwSdC^v^op1J|K{3A%hgf|tObI{gfcr=e5u1Q>y*z;{8E)riww zuWqI*aWy&VVIfu1v)hk0nsZ#OPF&9}|AXS@`!trDtDD72TpwgRV};=Y zr9882V5s4VlBpqAc~+2J&U7;GK)KdRV}n^4G&f~t@2i&U+z^)DW->u~({7#%M0{Fu zT@%d{F73*3OylObmmAv8*@4K*oT@2ZPY3X~r*(Xb_RU;XLe8j?S&crND)(CVUZP5A z(T^%^lc0axJ|JCrEhw8YA&IREPD;Zy8EduA6YE_|y^pvyLdlqpSj{BezB1bF-Qb1N z)*G3bNWJ&VneiqnrgLkH*!O3`&dXaHiOPMg4AVksKX-e5VNA(QZ~Vc;yR130Nb6l; z7Pk-uVdMpo7e+LECyoLy*bD*$dN=rO;g0`TTog8O;hO=ZcbysQO*E4xW7geKE)u$h z+2Bg1EX$(JOS7Db%++)e(Q;O@8TTff$Sv0B{zI_2s=Nb0pa2V3}Xh7j! z4}*)th@Lywd~OXl-DlsKgRL;2ckVQH7ZVJyC&Zp;&?7gC!@G6G_P_fgscEugIO#tg z$yntoA-l_R!S+{=;^>upTuZT_Rc+uG6_bLI-NU=8Vl-8qxiKyogV(?z`Get{;2x%e zyNyd$)E3d4C}Ww$$MMKVS=pmwA9`4ot5c8`|MOWbF_MQ~R6B>ZVYW{TCGj9pGM*JF M55KPM!s!e04+)c}wEzGB literal 0 HcmV?d00001 diff --git a/apps/feedback/locale/it/LC_MESSAGES/django.mo b/apps/feedback/locale/it/LC_MESSAGES/django.mo index e458604c200c031ce99e5413e9225cafaeeab391..79cce4965d59798b76e1c619c10fe7abc5de1eda 100644 GIT binary patch literal 3115 zcma)8J#QRE7+y&DG6^4{KoKClDUvwCdv~^o6m4*h#IcbfRvg<9A<@k3j_(G~%`7vs zcR5Q?@fYYR5Ct?rf&$S15d{*WMWUdl1`0}^clOSAvE(Q#?>^p{+4tjlzwXad$3IPQ zy@2~=+~44S1^10d@WAy0@NM9az>~m}k0!};z?Xm@0~dg&fnNci1pW*xfxnHheJn}N z;r%Y~7VvlA4d8|2Npb}^0A2%r3+w^^8^4RklH_T;e-4}j-UYJ$?}2~7mS2Dyy#GXP z&)-0{`xuP)1b7C>{(J$%UvdwRkAS}dhrqX@Q!SB!PMH0LlfrbJ7GoqSD!cDwOGxbyR9$4F4bOctcVtR6)KfOX~vd z;?RZ|2}7&bH@4f!itU%ejL3+-%nsg$vg1{V3zaTtWGf0%YpOg6>Zm}XW2--(4KtZyW1QWhPN?-O5j#g%mSU!6ZWsW~=PZaJ+Sx&T>Ao2hWY@P_p8vbf>fT}W5A%dhRy^sT`ZP`co zJjcxLN(bjWIjM1|;M21q+UW@x!!h9CP05I6?T&e9B)5A4;gup(PD1W|UWpJKOoVI} z1NlA(BtzwyRD=_9b8EaRz{g~<{XmHYaw?jnOcCQIePF?rfec8;Duk+jsUdK`u#Ub7_JKKP)6b0$bQ$^PJ&sFMiU7+1X2RgA&mRDYldux8RdIie#z zr@-_olk2L0T0v!RP#k4mRbpuOSpQpt!3r%o`|$Ruq@x>T$O#Hbe6>b>-wBT zI~GE+>FftG59xZ5z6;Wkci9YQb6b)tKHczLRixLdu1|MtM!gWqtl8`$&#O)YmC|(9 z3#Y7W_PH-KmG_nObDKAJ(iMkvg4pyr@-m~P*5XpyT1pp}Xz^mU)Jj{gwOTlsZpndS z^@q+aEmEtMU0i&%g=_AH@FCrC!gyr4bs25hj&w+wty(|5?&^ic*q}z&nth?={u^B; zf^EG5DW+SAu1t5N=x4MZ1hY=_W4DIGVFRg-RNj?$8b*dD+9Q+Xn`P}^DvQ2vqD@9I zO%<9K<~G(hR;Ls$Hd=El7Aa<6@2G_1LEeENEtI)T2%qyZEWfj}mR_2kW1Xnubk*dR zn{h^$&?gVf%}`}?o4RsBr)%gEJ|k1cSHHY;8Eu<)mgfzfS*FDcbICR;$XE`uk*2T| zyLndzE-bWF6?YVO%DS&x&PdTk6E|SAL>bQ(&z9&SI+C_+u0Uv(Y%83KRRoIArL`7u zQ-*t=Wyxk`6?C{H%DW6N2g_Y8wp%vVMr<<^B#sZq3>G-A^ zSg32FEu(zYLTvVGSLHo3&s*+9Xy%K#(NWcox_V;;w zC{2dVtsV35njNFK5r+XbZ~~671E3;0S8>Fn8&mGMEiwsl9-!DmHU0t)wWr$qg3|>( zi8Oa7gsm_3K{+$RA_5w49hP`(ph$EP5@%3e2w_*_IZzt0RN(affuQ)bo?)|{yy+kv zgB@X>@S|wJ{;;;1nnrSq387p#D942HAyN#3X554No}f4$CKf8A_7$@z3d{oGG-uyr zI`FzakN(P3$EZl}ZTq2gK@kWap!lg&_r3!)yNJ31V+C3`MmB!XV0ds=9n1~rJ4*P# z;ujD)K5_EltLZmE@K~67*-o}0hmVd2hiBT^JtJbj=TJ!+C#I-^nv4_Us8Hku>D;*X;v%@+BGC_hZ_n9vW^0oLo( Z#jsW`Ms7S?#_L=ySrXH>&e(Bz{SOVL)c*hg delta 112 zcmZ22@sio%o)F7a1|VPrVi_P-0b*t#)&XJ=umIxqKuJp=4N?OGlTWakO;%-dVK*>R sFto5Tnq0s(MXV$>F;_pcL|>E3CowO*G%-EZN+GjkvLJi(jEi!r8ne9S9wxe0oxE-L20GKw!0pzZ9|>)(rN2x6LYEdzEeI~ z{3^+%Q!-##GLb=o@uA zFe=dY=@6c_PdgB`X*{i;tI)Ql{iK)``RkeZfF+mK1Z8lhyB3!V>J|&tQkyeaZ>94p zWLM>s3}1Dz=Z$hCH*34mrV=o`*5PGZ0d1Wu>dwiUOs#9Y0MqWjKKpuxWMs0Q$ubTX ozyRq_oSkPW93Su9QFapDUJSDlXK;VNk4FvbV-Clhw4WUO2UBdI<^TWy literal 0 HcmV?d00001 diff --git a/apps/folders/locale/it/LC_MESSAGES/django.mo b/apps/folders/locale/it/LC_MESSAGES/django.mo index 4b5095132dfdfe1ff6f7e87498d7c68a1723030e..a1af93bc035fc42622a9433fbd4ef1215f435aa9 100644 GIT binary patch delta 1561 zcmZY8UuYCZ9Ki9pW&XK!Y+1=Bq zg+uW@!c=G#`tE~17_b#85iBScsue`+gV_3{s1H8)RH)zIW@FS2H~X2Lotv58Z)eYR z-kV>2)S5i2C^mI2_4|ZU{g|ocLYb9RYCdLh7OulC9KanojJxnplsS6plxoF2u^xWT z{VB}h4P1k-@FS(FYS|Q}TIkq9J=SoM{xo*rO8gJE z;S4dQ)HKv6&rje~{1Ka2UtOTVSoJf?M#hl2)m`ML9&l;E$Jma~kYH5}oib59%J}y9 zejds^Ic&twQ0D&%XW}-L4IRQ()>q%rARB4~W#Y5=7q8(Qk|I@M77KsCZoG=$;*;1< zGUKTqL5X+_C6o7Y6TZYgT-~J9TJ&)dUc#zGbf1PS^a2S^wKR{Pg)Ca!ufo;19p#TB zDC4eR4~}6MK1Z94Hb#1E0+)jzS% zQ4Z(p`1y1OOQdsA#`mHey0x)eu#I~setrby3{~Uj=TJ6saT@uT4g5xj_&X9n6b(et zO9T@|qM9Dxu$O3(kC8VKWkME}BCl~FbslvYRf=r1CTfje6gonlEh!AA#2 z&Vqc)%IvLOZ{_n=-W#lx+;SLLp=Y_nItX>SU=4Z2yz2+%n`E0wC$r{u?Jo=aeb)(H ztLz?~c&s+KMfd$Kb29nI)VvPg9cDJyS!Ss2bp4m{tWWEDI<~qc?}+=(@d;O|J1y`(`h%hxDNH z!5_`PjXkC_^HZunUeWxT$#rejC7GUO^xKrtn%vju)69xQ$AAthPEj8}KKWpB!=u^e Gqlq^Xh5mAh0;siNJT?Z}z`G zgIgGvuuG&WQ*`$7U>+TOAB`5!Y1(iS`9vOI45zRK zr*SjRAu-7-OtHQ+=;#NF-UE>js1q$?EB-)!vPP4^b<}_|%-)W>kyvFIb>gG=nk=3` z-T5l3JJ@LxEEWQ1&}Du3PUj?MSgnB9a2TKBF8qQz(O=Xfa^n7kBY2qcRn-5@;XYhI zmjG5!ciffq-w&W};38_~?qF4S{)mq5sE!0JPf%0#Ebt}j!f%52pE1pNIT-&!&BUL; zIOns8aTayHgUDIS2D(df;U0RcN-+VpTS4L-$7dU2Y3%&{sLb`|4$5_1XmD5 z@jmz*couveyaZCdPrzrv&p`5j1H{L^!;k!Z50bwhK=OUN;ZGpN{{oWFyCB8?-Sqzj zDgFq4a)%mzuP{7Am$@X;3~Yq`xSTt9(-bk!Fy5 zu`_&Rl2~S3i&VxTU$t*?kz`WDC6@=vI@@Mv;+V%K%2TPG<<8U-N{^ehmhH$yI?1&x zmP7qmxd#SzYn=$Wos7B7qexmi%9EsI^_*n_O2{voEUXS*^x{f|EvzgXmPv@QdLs>% zh8O(=duiI1WimBaBp+oa<;^muTq0R+Wybb0GnJ9^&d1&*nOS9Y$Oobnn)i1GAG9vW znaP|tuwxZ_XY;Z3h9=|_=VqbrkCmI`m)ns^{mfXADUHj zc5oCS?*^T&7j(T&mv`O@yMY&M1OWoQ3-XF0`TxarI}~?n^Nj$d^`5ZK8)ib=L^zX$ zJXI0jE|hjM8;K<8ZoD&2g-XcNX+-OBF2>RuN|AzskQhOKgj{W*DnM2S#(i$@cYS?PKg zhr8b9{W#Jb$;|8P$i%o=A>X{L+|q5xXGv=>$up67yCzF*$n~u1+TN)xOwvqmP4{{o z{x%OdrdK<`>0XzgI8imXdmGeTqv2q?6Y#57t8t16*0H98HQn_VdsjG-m@zka5Ql}5 z;i~1+e141L`e-Gmvdwl(ET*_$`_+Re(OOL2`8+D4Npquqyjie|HlJVT+7!5J)%7n~ zKQ3K9eQ<0cdT6W@^J{!&(sKTF0zIC)!eoa=FWyLrTOW%%Uyy2@GH14mDKXgG<(y;@ xSUX%cO1u*iXHD25V3~;C$l~ph{r&nd6rKg`<8T@1kY;|3;ap0$ZwjsU*?$K>o;&~m literal 0 HcmV?d00001 diff --git a/apps/folders/locale/pt/LC_MESSAGES/django.mo b/apps/folders/locale/pt/LC_MESSAGES/django.mo index 1f45e305ebd3124048b67fd64015c24839eaa01a..be537735a8291d09380de2d8eb4111dcef4759b5 100644 GIT binary patch delta 1543 zcmZwGTWB0r9LMqhCY#${Y`dm5QJapvq}Ik=qpg=FC!3M%PMDc( zS1ZJpKIwzVSjEee^rhg71X>Y_s8B(~3qE)Or9LVOULMpZ{r)DKkcfvl^Eq?&?Ejqe zKQmtrJ-cQ8`%?C-Q7Y8ysV`;B#<9@JjWUom+k%5QfP3%;oWw`5g@^GARE&`>vl2em zHo$#6pT;tNh(EF2eiGNo{uwG>ku>NChH)F--F`lXtle5`$-e@fp+kRo9+j$d$mZ=W z%;5!8>fc9={|3423O6nIH`Gh_Cu&1E(x9UmLX9t@`gfx;a}f3aqwC1OCJgA%S)V{Q zkiOxNrd<;+741@iR1`qxsmy3MBUA-f(J^YrL)4vA6~*sJTZ=c%tM@N0+Qkm4&ZV68 zEbd%QPQkWPIY#TG>TTDtkmdBt*p4bnwRWqbFK0MyEoP?OOh0k8b&NMswV^asN;jKN zkAd$pJy%N}@4VNkR-I}v)vSAsICA2^@mhWq`;D429n4m}FiIZI_9waQVDfS2JKM%X z&y78&;hk9e+4g(0-s-O8RQA&~RX<)iEP0^INv6Bb^c-kM{jqCg<0D=@IPR^OemV^5 zOMw^qyEB>flRi`ZcS#HVJ+;jCnK+&st5j-!JkvZ@o(k%fFo@jH55h{_eadZA{3vRA zQF5|(fA6iM&gku9yY5In>V3I5>o#glx8_ym;>wOB>N}FZzuhzD%q5@nh2?vy{*)gy z+;DkqLFCN2q3gIZiXmMTNn?f=b6XQPcX4<;^vO+de0h-F*P5Db`r)e1bh|AL9q7$k;h7;0QFRS1KT z$x}ua9gTw>G;uPxNJ30x)9B`)PB=(d#P9EICok{4pS#O@ch5cV-A}J3i{F|8PmPkH zwo=b~X5Bcyg%@S4$}Ej}Y{5CajEgvm>zKuJ0kc7z!46!)9{i1avAw!H|19pJKY=^V ziZ)B*5Ce;t!Vi`HPu!&695ic`HD(FSU<^-S6fYo;UFX$+lgJdC#t_b8EzaY1TtH&7 zml$JzE78z|C4azd8MV-7tixZ(W9z))xQPlV&gxBg0EyL(p%y-lugKysrs;36dkPa_ zvk@G?i})Bj*x!E87{(TMJBrt^7aeMW6;$fiDuyFwJLsqJF!tkaoJ9SKN7zpQZ?T#F z25H)lvHEhq8(GRuVNoZ)L_-@~MV<66DrH3^HhYLl-4oRJFHjjOp-%oDm5F8CieFK` zXbttfM@Qo!+=i{F`CZDtHq0?Vw(KMlxLsshjj)Me+^luxGgDFcd9DOc1gI^F-p|M!(aWl2TpCENam)FtKM{;gM< zt6Xy+=RO76-Sfa3H&eah#)3&V7rf`fHSNzvYP{0T&<)T1sT~S+9!Yie^mX;RTzDZ~ z7|-9zP8G5T!>9ANC+_4Y#`{uJ1@}FC#hs~}a)Xhyi$z|0L#{E>;)2n4?n^Y`{zj+W RgZj?W$NB-U)YdTS{R8WNW}pB7 diff --git a/apps/history/locale/pl/LC_MESSAGES/django.mo b/apps/history/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..aa615fbe2c4153deb2c9aa367765071bb29a164e GIT binary patch literal 1533 zcmZ9Lzi%8x6vqc*ARIrFKqM3pQ;^6OTJH}I2pgaIVLKucC!6G;fo8lrw>Rk#Ky;y|fbZK~ucM4^<}>fj`#CrJ``M+h7{+)z$Ng^!;C!zo(Fs2E8t_G4?YUM36kA9NOl|GRL!Xg9%giJP8<76ZJzeY0zC#yyq~_VNx$N zsOBf?T~iO;5#2v~H%X+m+)X5(DC=4SV%OdQ)3PO`0isU1(H6Dqf@8=NyD=WALb4Pd2#|8uNzJZt=VMdF{Gw&4N}MuURCCs3R?@b+W6hjP%G{}2u?ulr zab3&(f@NBu6k2R463N zdhbm$>y1pzC(f0z?`O(Qrn{?&Dg4Sc5i}_-m-9by(|cDl+Mfq$py(V{&CDe7UWDHk++F3Z=&KU{y=!m(5*Rziis@ zWLj81Z=?8S?yvNQ*M?gsHx;f1y$yrx8fD=b#N5dP1j>cdS9mfJm6dMr(depo`NWQL zj%DR->BOW;XEDFLt6W!Y%*(vDlTRy=dsj_W*qH0G7VY4*D>$T+!Ll96+ z?8YKl$n2-@k8aKRY@Uj0A+-_=o$^H|H7_6P?b?-XECil3+_~bJNf%0s2Ss~d+%y;T z4cMbwW~S9%_XQkpM7KFE;pjH&vY!-=I5Fbj1L$-l%uggO7Bj(0G+`Z;M1& literal 0 HcmV?d00001 diff --git a/apps/linking/locale/pl/LC_MESSAGES/django.mo b/apps/linking/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..8acf791a6f9d4138ef52d4110e002753b5ab643e GIT binary patch literal 1830 zcma)*yN?@19LEO|Ugi-9gok)dlW^8)y}RZ>(dK*vl8Y1xgUMY;5eaF$JLenUddAF* zHjeuEr_e0>{U7{_mC>|yX_@DA`Scqe!s+y^$nyTJ|cNzfGMm%;n7{uta3 zeh%IRegWPCegjgxAHaLTU%+R;U%><5-yr!rfFKli5xftK!N#_ zlAkt6b{~L$p_UJe{ma;-{J#PzpYK2_^~Yj;1$++cs~{fsJ6;cge}ZJU53dqf0?Gam zNcvBM6n_<51m6G;g71Ko??)i@;mczG+hYG`5UH_i1+Rlt=M69f{{Zo@XAz9@q?n}t zDC98+#iT(x4?rl!?m>4$_dvB!9fu%v*VFMxF`-}HOXF zCsB05t5IAHqG}LVdHh0Bje=+?il7*rkrxz&|Ce4h;_-_~ytEi$lwK9i2kTa7mkV!f z!s*_Y`%0sq8zRrEOUGLsp>oP;1=_mR! z*q!vkh22RRfy_EC%nL7JHxJ9D`sw=Wyi;){DxJWmCN>7=%x zYqgla#3PR5!*R4ytMVg9#?$565=|FqJ6et-e(BP9pLC)!Y+~3{%Oy6tA~G#`HdJD? zEwqxHq(5jPLs?;K-Wok%=LStB?T{%p6n)IZlzaipe9MeJ+j*boiazO%;6p9ap@gF{ z+Y+wVp8j4#J>Y)ed!udqVuQ3TSbwy=^Ikfn7;y4#I-K#Ap4-xSZm)jdhwXeW{-0f6 z?R>iBh62@&ewvuiw(?$c;#Z6hCZ`=#)81<^+uCISEruo9gHp8M4sn<@!>*aHZ<%4y GqJID-U*8A- literal 0 HcmV?d00001 diff --git a/apps/main/locale/it/LC_MESSAGES/django.mo b/apps/main/locale/it/LC_MESSAGES/django.mo index 00bd8125a4a40e0627da915a850b9cad9dfae1dd..197d7863aaa111c71a7298e231f3764e1ecf7ef6 100644 GIT binary patch delta 901 zcmY+?ziSg=9LMo*k|t?mTVoSbZH=BTZ4^C{h)9MC5;q4y)ImafO^@W%+?CuN*e={agX?(yPJcds=Ki&BYEaRKFzl%E257Zz(#6LqMoGci_oH9jYcd`=c&i3yx6GdA#2gE zN|)7@G^R$1G_icPCZL3bc0~MVVWH$=!UBo+FsA>d%o3oyuR79HZ0e4 zd_T1P;r;a0T%qFxRSY>yB^>;%l3aThyquhBlhVcMryz~4B4gH2{FIEfE%2Ip`dV|aui{Dxt(x}Edz zhK>vD!iAt&JFa6tzQs2Dh*3O5F8j(Yj%TO+Mz9ciSJQ?#3J_@ccH&9ex`p2 z)2wfoJSgK^?7;~8r}ksi2TG`kmAA diff --git a/apps/main/locale/pl/LC_MESSAGES/django.mo b/apps/main/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..5e53a249bbcceeb8e7dfca7c864ce0788880e4c7 GIT binary patch literal 1464 zcmbu8J&znU7{?8Sw*>+OLHY#CVAD7RK-iOpqVJXThJqbKo!F^Wg8`3*et%5Bv*!8eDslv1h;w;CZkIcEBlk z2K)$o5tJbLwafD(komf+?-$9w|z6U9{zLFp@GeO43h)ikEzds%;fg%~$?i*#^uAv1zXg$2D`zp& zUD2K5bL;mhkn(*6gW^#xBrjo*U-Cur@-a?ls_8_Y!-8U?^p&g+cCSvaZ?G%-ruN*= zl;f2(xfLb5qK$4!Q#&?LBG<-wm0~>?IyZb@IGJ%%NzI+9Z7O+Y(z=w|^HOM$%XaA+ z=Vi%;CRdtf#9(`}kgaj8Giec0^6TRvzun_Ql}ha-yXA#f$I+%vT1FGkq!+4i?6$N{ z8O=miD#TV^vg}{!%}gm-DU|k73!O^lq_F9Xxs}hcHFKHz;6@fKoh5uE8lm~_V05dq zCo5xpFmk!df~$4zf{97^%=;<{!(91Uy}y~7GPK4CtBegxvJI7UwRD~F%}KChB?>S) z7zi&D9!K3ch~l6d^X|Jz90k!<6hSfAlOHRp=%p0rYBeGK;GNb(uerh zbQdnHj>`ySR=TiQdI_r{+~|yMjCNNy)!mFbJBF?oX*Ct<^YR`X6}a*ar0-8B z*Mf^HJ&JiCZLq6TlPR4i{Nldyr`aaFDmvq$wxS5G8C$x9>#E(le(w?v>7>7|`~5C| zpGO?WZ+D~1{g|(p6P!(HH--+wn{&=Je+u8h>aOS{<^1(301y4}#r6=g$Q?*%~c) l+y8haR;0~bi_=Fye%eP+dwbO2EuunqR3D0Y`v#Vg{s9*Vbrb*q literal 0 HcmV?d00001 diff --git a/apps/main/locale/pt/LC_MESSAGES/django.mo b/apps/main/locale/pt/LC_MESSAGES/django.mo index 8b0b67f0e3ebacd081c959904ce2f3accb66f32e..103ebe7dc8002a6c18b89673bc9fdafe9afde6d3 100644 GIT binary patch delta 904 zcmXxiJBSlO7{Kw#^PV~55k$1I6D>q6eSp;!+S%Co|JFD#^PAb7$2X6kxrg)pZ?nmJigb{?pF9^+ zDv#4~3eqzi!{<1QuSV?;c#QUEETKv$wE|_Fz>ByWH*g(&oWhS-#xIyss;{z1rP6#@ zz&p5%i@1%u@GTy~PdJ0WaS{`ZrmALe8gnRtYLx%0C<~TR`kfxNtC*#I4%4i!OjJ>- zg)-2?ubjdylnF0U$j&!V+5trYx9|i$#l!d=$1zDUhZ*eR3TAMCYxo$MTK&Kz>#H3q z+xQEY@B!y16TH9!_zorF9h8awAYIiM(MrE8vbH*c3s^wuS4BD5^C%~D8KwVKl<`}* z%v|a=6&Y|B*?4q+GST8-BEHn$LrpG1VwPSKl3au&c{R)A99cr&OXgyuBq2+ZS0yh& zLX>6YG9=CaBRX3iQFQha=03878Ku?g@JT!$D_5@>x9RDc32Z}qUF+(=>-lx78(zKF zv2Lh4#x+eFRfEkSw4LGm#G}~JRv30Gj?-+1tzPYT-Rn5M7Z|_o`A)}d8rNwDLC*$* z>!~x7r9!Ewizh4PQ-hbO`6hnwuY2yEdw$;D&{e8&nRHu5jFBUx z=a}X3FDmvUX5DyzNj&V--(rFKd#vCMPU2LTSuZ}sL0rToe2#ti4x{)HV`dHe%*_@L zzTq8Qam@yB6DM#R`|$|lc#0G|=i=cf)C4b3?|+~Mx<-oq>C`o9g1UzcY@=-(W;t&3 zVF8a>^&G0hU$oMSf1~Oymm+#Ni&e~_k3HDJ+xP-~4DlA`cuAL5K}~2LU*mnuGQR!f zMjyKDn~ouan&~{MgGWdcdxC2B4C&kIn8poMyB*ZZUZHm85Y_$!_5BB=*cUEpe<^j$ zdN@R;o0&+qp+nGyYtHIslvH!Y|Gz~0q8KJQw|3~z6j@T!*Az9Z)~wJ}6#6UpS=xJk z7c*pvY{&FM7)J6=m~dY@&9Bi1@q5K`WxPC7otbM+#&*-ea&4{T2c>-caczCIURzzR Uj{8CLEcP@kb_Y)Qz2}Yd4{WGKfB*mh 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 0000000000000000000000000000000000000000..2a866ba86147799625dfead298993a20a3fe1f4b GIT binary patch literal 924 zcmZ9K&2H2%5XTLauW+FpIDupdQMIbPanh|QX;V~9q&7`osmOstk5dK9X4VL zZ*Fw6Zb?rkc<5Z2gkdh+usUk>brBkEnGxEAh0hIzwH3EPceh8@ z4QCF@k`3l~f@2!RgvKO_akQAkl+ZS%AS8SISorJz)5R1=&yr|yo`MChnRTRRn6i>N zZ4z9FK3=JXa@-7^+3sv!y;Rhq!McXq6|@D9nqbFIppaxjE#v->8OvRI z(Ay$QS2};^fE%)@`Z^OTPw>)_aF^XCxRgOxR)$HkrA=WItjfvOrVGmu^pSK{rD=p; zV2UC9G@`3%jAv#h%aye4m$Uwuu0#}{o=(oahR#7w1Ud0sfOgo&nxO+*jlZBb%s4$h m|8WMBQ;f#vQo$_g_kU-|3+qwAa;8QwKCT*n_EUuF%d|fs@8gaD literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d4e9505785fc479ee8224384a3d8ddc9f85a8d09 GIT binary patch literal 714 zcmb7C!EV$r5Dic+xxs-Ghq+Mg3VH2>tyJ7iL2b8EB_dYs!ikHUc(Vq_4z|O#Qg8hR zE^y!r_zS*+AK}7yx1xv}BfX3>@4fNZ^3R7`pA(EN#ACz+aUbyx5u-yqKzu|zLR=%F z_6y?Ioh12&Ir3lcZusw*qyGnHq}Oo|ztMxGBq@6x6sRCu5LHmtBxh2~D#-fpqUVXK zkefOC9!YXilef}&lyfM>r7$o(D$mkW*;yAz=^Is(gTC=(ZaFMN=s2Z~3d{a{RN0m~ z>xEO+(KdRi^1hcooxPruLnlR?f*gq;Ipi$M3Cl^AL$yK7mXxyDOwIQtCe5E z;AZ;OYBdV6m0HM)k&%IRo4fF|+Z=<)y7g4wbfKN5!?Zjpr?)qijaYhUad(4bU3PfB zATO|y7Ru~FwG__FP`sHRligcg+;brvnVQPh$}}8y&sF#{Er(90Gu=C($+2~<=U}?^ zuP>hMAsLxsV2UDx7r+4NCmGu>a@gKpFDJz~E(fv9CK-dPt93nU*bqG#dh%iVA1~#D HH6r;9;Izti literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..25c241493121d10f796f20f0b7e0644aa8b181fa GIT binary patch literal 562 zcmYLFO>Yx15G{h!9yxQE15}B?vAqpa>Sha}*+`MH5G7mgZsKl?cI}nzC9TxI(ZAQ< z!I5!VH6uNFJnzlt)BAUiCunaF9}piAZxLS*(ME`WNS@;xHLtdG_K(^GGT)Nl%6V;# zfI{9&1NpRACo9!j7f9hNy(K@o%9GLx*oDvvN-G_9-OXTQ8|ti=PFqKtm`kg?TO2Ftwhu3KZv~{wqJ11*0v##+1OndnH?Cb)`$Yec} rWgNZ%1EfE3cA2GcdU|lj*)Y1j7-nP6;NjsAj~dp;9F93@KRNjiSmL1S literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..41353099dfb89af4d302719835a3fa4e9bb15f46 GIT binary patch literal 1161 zcmZ9KJ%|)B6vyMYu3umyf=C+W4$01kryS$0ih9a{tBdZ5ZEiL@o4c80NHVuKhad=I zYoVQ;rInS9rCQn8i?twPVQJ$(d!u{!*tfsD$$S6z67u!f?iU1h6n+x^9DW>rXb1ja zBXAEW!M&gcPk`&-LGW4g{Ux{$@hi~hzi#*jJc9Ub6MqDEBmM-oz|Wx9`2u?VZ{TnE zPdI+$`>rj$AK)p(zd)aV3?c`>Qw?XpLx|%hz6|=lOW=O+0qE!Aps&vwTF~n}0)0P! z2EXrT`D;6y#o>lN-)njEXYhScKI!j!dGq)A*Dx|6l&b+HH;t}JOO}+ahC`W3p&TuR zDWtVhE88Z$X+Z9Zb-gCYy;7u-=VaLmV@YPXa%9BqwmOpY6_FFg3qhu8+m@D?Ev=r> zt0Hx5X~6D74LuXu#iuZaja`IIbc_-%(A{t=*YP;34%&zjLgO%sSs1e@rqTH%4p}%ChDc;MoAmAf%Zo!A zT}ZJsO3Vgo`sm+B%-N8DK9I?MeVY<`;Odk%$Riz?Lvsj`I5uSoZA+Ju&QtCv@X=j?_y zg-xg`C!y_}yNFG{)0t77PDC%$kYf9E6kh7Y^vs#ba-lQlmoxrzxDbW(;ls&ypA*ia zCPGa-+aeOLuPSSDTZ(aQ9XIJFUw!{16|^c1A1gdY$=hUk8jw4KvHtLwzkfP;gsVJP uHCg`fu6Ao0`Dsl`vsrH{pHT2^GJ*(KuSwxJ9_8kklW7OBZOw`P*WeEfpeA4d literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..278fc3c122def9c5e89537ce7bd8fc10128f9811 GIT binary patch literal 656 zcmZ8d&2H2%5H^38a6{t8VJ=j=Lf$wgNR_)Oh;}Pg>WWnfoN=?>tcznuw!?N&UxU}< zMYu3dD=IP4=NZp@^ZWb7(_aMT3E~x^L_9-WAd-ATq`yQwN3@7Pj|d55xZ{}sGFHpG4Jng5%T_S4XV~%$jyC~yf^tY zTb?f$50@%tEIV=7-QrmL9`}pt1`8Rf?GZFv>G9Upm->tzKJZe{jq-G18@JZB6>xZ^ zPZ3K*v@8TUeNs95O*Vm?x8#d-URlGT6gR@a>a@H}FXUidAf@kAOWu#2C$;6U31Q%rb}DSf zt65`v>Z}(|Sx5V*rONwJ`n393lM^RJz_#R61j!+1Sx#6^vK+EEJZFT>8ABqukl$4t z{~s@BkiF$>@sgpXAA}F2cEWfqf^{5v)xdJAOptCZw9e=6x?U(9cRE70=|<5>QcKZu zsH|3g1CxjCx7+P3#8zr8uV+REI^6$-r^EdjM7F)B`k@OQG@Yj9dAZvER5oMjiN)y# z*SZ<-z96r$krv7vLbDOh%TRo-&&XoWi!;~Kk(Fs|t4zmXaizk)Z8;1&t@P-GCTG_5 zo`V^7p)Xz^Vlh^Vi7AQ5%=PrwRbSE**mKlS)yInqV*c3GxYVv8C O7~yVz{cLZQNd5wW46IQA literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2ce2fce94dff8e9605596171af0ed8f530652834 GIT binary patch literal 710 zcmZ9KKW`H;6u=D>0XH%;c%e#!ob#C=DmPaUO)6F5L{tL1n{zHkKKo?*dJXChj0~`J zKnzSw?2Pnl@I_d7PAV$#q@SMO^ZVy__xtYFCj@d6xCe}ZTYv_lya%HF0oVdQ0=I$B zK+O39{JDnEH_&&0uh%#J@1PT~e}InupP(TOfm+vzxlwLx6hft3h*k$=L@kk*At+OM zbRu*s(bU;DavsQGNnT6ml{Fj}VkHcojEk4ak!-9Br0|t0$+NcdWM(;DhS2adtyEaH z$Ah`8Q)j(!%DS|UxvBELl|Grin2~)aMS!woEP~{i(TowwNXBsXh%-v)kWvUFNAg6) z_W#8(idn|l;|CNZc`ke)GbfDKB3Q?9t>$>tDHEhy2(8)hX;llQ<4k)HZK_sOlFX#2 zIi6ar{1W#rr|-IM5Mn8{kf#G9L)vV1;nQaG3?j?gr~0x=+UT^O6odU`x)KK8Q$JrA4mBx9(&PEM;XOuXKR0qp?%27 lAcyr6RN8uVajwk@{*1SsK&=m=Q_?7bI^lx7IREty{ROQF#Df3; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..77f71c4ef5efac23b5f46b24b4d619fbcfc01b38 GIT binary patch literal 2678 zcmZ9MO^g&p6vsuj*Ur>VPgkd^dYc|O zm`xB5UO0F_663+M#$ckNcwy&YJbCqC@FoZECVKGydV0U8Ox16?>b-ie-g{MlY}xoJ zLmNlmhJNxs#`b}i?#F=E+Q8U@;5%RiJP&RHKL%d{uNL25gB$VvJ@_bi3w#>4d)GkP=L_%w@GEc^_$~Mlcn5qH{0k)g5`;)@9K&XC zH%R-u2||Q5!NmN!;8pMu@Jo>7z5)M5 z?0y7kpYLGg4e)1>Ag0)sg4+s?gS2lIB)R?IbKnv13Gh5f_7sS4v1iaJF3asn{Gs!4bh1Zn zD?0g1aiBe^t|;f!o=1Nw|2G<_Y{~xX=;P?Gpp!lFf#O4r{8(;qBabuHKIMTL#h+@G z&QH0bMzN#%pNv{>hQj=L<*<=B*PqAjdsQ_A+(bU$_(kBy2PG^c6gf-i_r z1vDnIjL8KV>R7UAW3=Hu?XIFuvG+mPX2(@1^MNOkuluo)*2(~$`#%27C1IFx5d}Pn zLoEWV2+LIzs09@yBII*Wx8-7kWs$YY#aarrNIN*V#t13zUca;Bkc5s7103p{-5nB&chw`geYjv+$ z_iA-s+t;X9z3Sd-6@uProRM;Hk6gXR>ov&js-l%n3hTUCBO)6Lr%i+RmCq;AymaS8 z7}ob5>GTm1^63zyqfR0^(wmi{-{38c6LXEVrF_ZQnhlmbWG#QL~tv=UQS-bMxjvALGE{jvC=iq&K~y;tjdwi zIcdCUT$BLUsKF1km0R()!Q-&h3KJtj@3=O7+u%{0f7<4rgIJ`M=8mY@tntIV%CS6F zs~&3B`S^JLccQtM{_ddZ>O`%|FI~##Nv66JIyLCjcb3=%k=lV|#|9aX1dnAJY50u$ zI>0NEL`#>KuJGYabNfaxT+|JEU|N|I^E?^;l)0WxBh?e^tV?g-FazAm6c17suhU?Y zVjy@RqRj8IsSK}8E3pnUCg}+S?Q@8EDuUrn9_!eM6h?7#jnl*HOIOP5Ej&8L2{t)g zT)G@UCh!M%0q8alWTeE3F>w%YP%Bh0fPou5hy^@^VJP*p;q@?5k}EuO18IkgG@o*9 zb(=gxOmPywTOKJ7G+Z1mu2o!BD`aT5b_OBa8$EU-Tf0{cNHSouj*0}mjH7!;A>dX? zU+FYsr&K4v2vwfq?#&}Ex;J`|3LlV_Rqt1v5M?&C9KhiZMSe!FQlY2w1gfQL4zKsB z$ePWPJcc@wZ1`EKgkuP-K^4%WAlP#H@h)ZlydXHZc~3pCl+xl4bd)jG(~)3EP$xvD z*h<-~{1dFNkTHkqWiE5caFLC&l+3dhvVs(;d8#6+0E))aHD;+Kf&ogdc(>XLiCK2? Ee`u}K!~g&Q literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1d19aee01fd98e0ae28595c5213ef14fd928d6d6 GIT binary patch literal 1393 zcmZ9KJ!~9B6vu}UzAoV-;X?=knj%ED(BAHCOcbqs0r_I1keqWeXC$CN1wU*2Ux0r>(^nwf|0OOZJzs-o zz;8g(@jaHOz$1|SKY}grCy@01(%63mAIJU=knTBw;OD_pAWZBWNcLs$EEqTY4Upcs z1>(ncu#n#OL8{XSAf3-Z$gORphX%!wcDnazOd6C6PpZc=SgH1Op5F8`*_&2M9lR^E%#`ffRNPYRx=N=W z_KNjIDzz7EOXQN>utKMjZObucZf?su3!hk%^RXEfIYJ#9QsySz=sy>-vCO2GOpcXj zw$8wygC@_E^Yr1^z?z$K29~fU*{2r`;|^~xf}EI=j+e4 z?h1V_kvUrHM0{_rwo^>Bj58gaiI-b!OUYd&9a`{O-LN~pJUp;-u1#4tn>udU_ms?x zHo@Y%!-K_#zG~X`E#b6rb7AlA+j%M2z~sV;#r|k+%8K>o(w0V7Y{wOged=Mw=V;(t zbpszBl+?nCExv7%7rr!hULD;f85PB|!WH`HgsYB4y`d~|&ru!^Yu}MWAf%EKX&opE^fk?*n)2{f-A^nOz>}i5I54S#2pwz4R{2(%rS0?{RD2uK5WAC zsQ0gW-oqN^H!t|1$Uk~6qXrBzivlXg-55o>%ux*Eaje1tRDfr3Gp4-$an$=$SdTNP zapzGBd!T;iH&6JXh@WBzpP>eNg_ZaT^}!F+04rX56}6=SKKe@9qPR!>M4iMKQFdWJ zsy&VESVRkdVqOD=NQ45YK&_+-qgd;;TTv@*$7bwBor#Nh81q4)4^ZoXo`y=eXRvck@%25<`7CKQ|e%kX2ZlyhsI;0C|;SwrEE2sc|p(ZM)p^4j2 zJJgL@P(Ny+=THk6s$l=M)ssBX2iH)C^hXV9@n)~7cAEv&RXuMH8h&aU2;a;Y@sX= z4?7vhbxM7Oc%V5nly*yv;y|Fs7aUAG6P8G+aQ);}&j Q4Cj4;L5DYsR>b!G0sDZEB>(^b delta 1149 zcmYk*J7`l;9LMqhH8&>lwzbyASEG$>Y)l(9X+;`Eq=<`Da8M|UND-g-SUQOsBT5JB zAQuZxIw%xG5bmH$7IARM8jQ9QBcBwin9@Zj@2qY$evPj0bQFUUvOC*ME;(mPnd$S=!lw%jtKc-WRYBOIS3k z+c=Fj9!w#ZHMnJP8dG=|H{gBL055PUHc@MQh3oJ&_ToJ1`vf1!KGX)ra19=IUPPby zZJI_uFJ_R-o^e}-&v6C5M8>pt*nuD2`)|l)3*36}H)?^aS+zElL%lDd7FxkHZbyx? z8#|fb#%bsW$4~>DbNx%G&|Sd~q-6#R^iL5UrRz5Cz^3aj;0XNzRz0~N|y)c223Ie&@@eGB#7 zTlfAeYN0={3xBl{e;tZ|ZLh)tYQSBn1?@+DcnH_xX(SWzKR`QB(L^dbgj$>m`-vl@ zXq2g%V~Dz*ss#>GHGWq4SJ5O};}!=96*e6zMPsojMa9JqDs|gjU*TqLanYger0R@l z_nWEO)c=J{#;K^4XecCks)`Pn3K5DUqFt*f4LU?is2i!Nu;IT6&nJuFgJgfyO78KZ tZ0ezxt`6s`wVlHwVKY7JPo12+5FO3j@xn|n814&-(e>b}7X|GT-aqFDTOI%a diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.mo b/apps/user_management/locale/it/LC_MESSAGES/django.mo index 85c3440f847cfa8a3f2d68edbe2d035ddef73276..9ab2965f2d411622e6c153b4a457378cfc4e6eb4 100644 GIT binary patch delta 1349 zcmX}sOGs2v7{Kw*e5B(e9kr}1Z{=%B=jI~|A4nnepn`}Zl%hL2=!Madc_3LfL4*(( z#VFA(T?s-6f~yK5Ym3CcYo)cduPr$-#Ig1E7z(LtKN($ zp|lX?#B!R*NxYHHjq*4{#E;Wx<6ErP2bt^rek`PU8H;epv~S^7+7GZ4XR!pIV==zN z10o6eOvOh>an|}II?$pWGfo*7jVoBe^FNq}Wt&CzVioSj6R6Mou@=X%2j{UH^Rh+y z^f^{AzAUFIBHxU8IU-wlp$>J%?Wi+8hm0vf)D?$N-y1Xi6G(Do5)1GV=Ho1~Mp;BI zd1~6P(Zl$%OhvzV1$DqxWU}(hwEtom?LyD`7yD2LI)Xfs4%7jT<43md4C)rulAb!e zXuOTOmGh`uwT20;{G_4-r!(E1ScbZ?X55Zls4KpLZ5YOOoWryD1uZp4uW;t-*kPWZWL2DIo_=&W;zeMBvx2ah?XN&|O2cv|$F93(VL+lY-~ z{x+nMjylu11NA^_hMNifU(j^EV|FKa3|wvX32mPwc=4H z5DHquPBc0aj`VdVU*+7d8HmM(TW!1FjSa*D{@(DQ9SKLBh#QXBgU&T)$abUAcrcp0 z;OWY4Y_J+yTANyu)1G90$QkO7JN-f1joH5BsoWmVY17kcEzIOz%_( z7;O)+k(ga!b_j=7a-fYBnziCJjNvnE!LROoq{ys-aW__CpBoQigz+U@hvQg<4{$BM zz$UY-&CzM(#4@&HwAjqYQ_ic-N#_jKas4x{Mq6dJ70Pfk#!=UMumLY%KiFCBY$l~k`DphZBJuaYb_!Bij$jjfT0(IjWd`j7TRB7IY%$o7HvxzjR zgeOoX8g<^mtR{L)rxstMcJvW9;5XDxi`m9rtj2xVi^p&reVoU7)GB2ZRf@yTH1e@A z4pF@2d{s{VcW`2X6WcMw?4y{#%lI6xV>_$xaTYbf7pKQ|wBQ)3MEg-Y?B$@0rcfIk za*iO?wVTd+mE>PPe8`C~zC@*T4%w7_K;38om5D_+UUnAnBR$=vsEpOQaVP3`JxCI* z&yCL@m9jR1YFSwI|J%0E(M_5Oty&q;VhRYQPqp7ksO8d~@BTZs(2Kc|HsuoyZmd^( z8?niaccI>z|L4zLN^n$3^zP~}K)X|m6RiZ#pz&PgvY`yA&T2|)4N*<#zeEqRYOV6r z5z2-#!8@OO-9fF~c5~EIPDZVE>TcnIqTqY!jo^`Yuq2-F+d8`1I)Wcw5Xq#H=VIwh ftkFA?JU=j;97uKf=}a&Y>Yw@*I$a!G3=jSR#Y}4W diff --git a/apps/user_management/locale/pl/LC_MESSAGES/django.mo b/apps/user_management/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..355d578b0f2e4ecdb7f989e588db1bf39c24c6b9 GIT binary patch literal 4850 zcmchaO^h5z6~`-IKsE$JLii3YmaMabx97_?u_oRu#9lj=yvgFMEz3wKwcRx{HQU|Q z>gwKhk1P&WtOOz96G(;wLdq=?0(?PHZl0AQA(7nqkdOe06G#vVDTnZX)jgk@T?L`g z+MZum)vKyk@4b3e`^QJ_{~^P30`Hgb4(?&>9O&PNA3U$#&sY`w9_WC-F3W!fKZ){V z4>0yA@CZodli+8-^WbCPOW>!$UGP!x``}UVr(gyA4fu8NU66w-A1Sy|GAwxuJdE~V zfFB3n0T;nPfL{jLM~n8u;4+G9;J3jpcoiIg9(ed;h1|;}Un@BP525|fAnE%rko0}< zLB=ozdmNLn*TRQy|G-29JP!&;fr2 zJ_Np9*8dJ9f87h?ErUxS$vqG5g4e+W{3mF@E{t6Te-G054`C71uLhEySHRDM2}tcf z0Lgy80?D3lfV9rHLAa9r9VC1I8^jdseekp3p+}1PCqXJ#L9**vko3P$mal-+?>l9E z2+}-#@GIag5P$5K_@RCSklNn?VOsVV5N=`(yyQPjKYBR6$k((l$VcQ4^7XxVVQzLG zUa~nowAR^Y1r@cj64TgqQ!LO!wj#UJ-lpdmUecEyvhVO|;)DE0d-e&uq&q!zyyPdc zA;m4(fY$RkUV6ypCb;?az zeq_pYd7`-|eVIs}bS3Y^I*nR<$*g@K@zlupzmqnF_-P%sRUGh07?bJPW2a*&phGCL zLI*QhL(>>`rchH}QzlViXDByYT?nsxD&e!D)0L%Q9P79+!DvvvxU_67Q8A0qcUh85 z#jy2hSsH*uiE|}mX{1$kxJ=&0TnBVJN9Mic<>O$ZcTJ3t_f zJeYJ=U?VjNk7B*6Jjq4EeJN0(!_xOvw!Z)=US-e2MZ@*5&C-8{dzyzj;eklp?g~%h zoQsZ7VU=Cn*9a5}2Q=GIVK0u?Kbn?X!;Xwe<5VFS!5!APBE+f_(QX$-YbkQBGFC_7 z`#O`}3bop(7ha%3uEIpdZQ)8gFm?l4U18*bV@t%@hcxui$i-^^r%5gqk-BeKjoar( z)wq3rP}%lCgrXw@87AzqLXgbvzUj&oDj6o+MD0pe1p9dRPgam1E7W3SZTmA$R7H`5 zY&gk4D4)@8;h_j5v)j1%-NMvp$_@nh9Ve; z-eOi?`YGn4FT*xt-IH$OocEl|C@USd_=dL(sV>cNI-PBiC$@+_7Uv>v$F}ASF0ku?USX5)H!!%H^lBa)bDO^Y}M9 zWM|Up8Aykn6rOjsqzGDkQ^U?(zFcabWmz?$p;TL5tA;YEA^DIkOf4#w;YcqqHNPCC z7WuWx!p8ZH^|7TI)%pTXj0BNwm&j`v$VY;Cn!8;QBhRj0+B)l;9Lv$1Z5cc3 zp{qUYo)$m3t&)+pEgty`n|>M#-#M$}0NEytY|*S9dm4?@vbr3ut~U4@uX8jnHR{i- zHu;ew_Vd*0ar#`Q>iVfhonOCh>q(|wL7xWtG%E}2bU#Nd@40(0!BS|Z1HP|uMD5)WJWa?CnnFYe`QA@_*pN>8Ig&8G8r)9A{N}#c zNmAjfK52%_0#0&8h9YCTIG#l>AeZr;^bmYy=p8I3J9=tmIQ}VC$^d$f;z)4vInrN> zU|8WMitpapPJ5Ub5oDKQZvfU>WlyYmI-HAJz_f_xPl**_%r;9C$>LO;^ud(4-6WHD z0v(I~ zY?BB(DH7g}aJy4ik=bcw5#s;fNsANeLzwf@*o{*`J&NgkDyH`r9|!inGPBWrRm6Q{ zg1${TlkpTNc2#c+w?C6eC`-+6ndnV94%;Zt!kl4a-n|p|DHD#i3yUQMODrf+p<#A| z;P@{xJMJZUlJ*EBYEvZga9KUQ0q7nq9eZ<$rML*xSfW47ZixJHqfZ#9 O)M28AOg1jMIr|T2L9C$w literal 0 HcmV?d00001 diff --git a/apps/user_management/locale/pt/LC_MESSAGES/django.mo b/apps/user_management/locale/pt/LC_MESSAGES/django.mo index df9e96e88ae34989a1833d5fbea1a25a6a087961..828d2b0f6c8e18a0ba509036bdb16006b15191d8 100644 GIT binary patch delta 1340 zcmXxkOGs2v9LMpasp+Wstjr!x<@+($v8=Gn0!4#dv=yg6lcsB z$|345>Qb69r*Lu;7s}HNV*)sf4t~NW4P>tO2e6Rlc`U-HZC}G}wD00poWoLlizWCO z8;qGUtK8JlQIfSDL_7Lv$E`Eg1?w_aF#ZSguxzt2`>+c4U=M0MjJ0?J`|&yUVP3W| zLmI~l<~K{J8)Me2c{#=u@IWIf;$x_Y&meP}5NgFEsOPTQ{#!_L%st$K4>2F-kTseG zB3dW!Zl0Lv6_w z>tn2<{SJxEtYQuR+(P~}P)<1NIDrQ-f*0`-Ca{2fPvSK0#dJ>Eeyl`&zX!ENQPe`N zqZaT0Gw}s#%U+_M`-sZ$w<7Yd)UVnHzS{@>q54Zm4~sM9s29~DF_{2r{5bM4U0n3S zbEqvGKxHz4dj2+Yyv!5iW9GPM>s~4UY+0%Sslv9TevVqH(xp;Q)e3a7H;R6)O}3$6 zR5Y1VpRR^2T7aLb3@fUk-P5RI;8rp`bs9)X%6=jrr+}lbNLv*YhVl zcW@-+A9p?P@>p!BBe|G!rzR4QkGDBacsL$O3nCMU9vZ~KlillY4eZIKg;dTDvpOn{az>< Rahdx4?4{61M{=zw`X9WPifRA= delta 1232 zcmY+^Pe_zO7{~D^Q(IsEq?>J}m9M#5YOTBe3loHbwk|~-A|kyQEf%z8W;>t~w__6Z{1`UlCG5uuJdMkE zR?kBkmou9UZp=P7mvKDDE;34fzrQ0}cxRE?Ur4rfT4k4n}1a-x7mgr^-l zu@lp%1>eCiPGe5FdB)8ae24Y;4fWy>%U8P*mHR$t22->rQ6XPMAB$L}Qqkl*gfZIZ zk+oSKci~;vzfeW|)v-iJ7gn>p%b3C}KEY9p6YoZRh)wtkHSrHrY9gFGZKM^o;Qgq` z3?M`73~JmJRD^G!BA%}y{u(gu20U;N=8#R<0&1eS$Xe{9d;S$Q(RWm;R!|Z2h^xj$ zkz-_Cs8IKDA$xWl$yAUQMI@~J|1H{~CfP&Pq&um4c@dQW1-WlUmFOz}UE{P8u1CA| zsm-pfPg{}O=GrMuZHRY_9YsM-bRD~OsRr2MOBw{_G_)NZPx zqZBC`4OE4jW2J9C_}oFID#*JI8xgen$CJeeN(w*A@`Y*dU?|z)xA*k6_Y_vV@yJMe jFq0S_Nwj!J1}_d}2Zz$V{_sd)qP%~mB2`*A70&zta}sIA diff --git a/apps/web_theme/locale/pl/LC_MESSAGES/django.mo b/apps/web_theme/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a213504995bc038956eed8a0c47e2908089df955 GIT binary patch literal 714 zcmZ9K!EO^V5QY~h66}#15{J1^B|^@6mjKl^TM%t3RU#!SDH0MFH|uVkdTnESyG>Pz zr|6+4&b&j9^fh=9E{v0kN{sYrY|lTQ@yNfQtX)QEYsfQXfILLLBEbw2V&9NQ$SLv^ z`HuX#7e!a-A0wCdSN;cj!2M737+&V$GJ1e4ZJ(d{Xl(hZ(2a|}=mwbOz@+7@T!7S7 z#Y+$hC3?=Mp6r$6Gq+A?mBWZFn1bQX=u>>ajkcbQTqR2KzNs9U=p1I=n>;b+ZJ zZ>sCWYR9b5HmO5yBAjcui^m@)WE(4byq4@R&vVFVnh~0jG=ub2o>4;kl%kLvV5_10 zf4Yo9`X*0bzo2OG2j)DPSf-q0UfUdMF@-@Zl;`%CNtyNERW%bb^t6R)RW+>QWWrgU z!&pn Date: Wed, 22 Feb 2012 16:15:01 -0400 Subject: [PATCH 469/484] Update credits and release notes to add mic and Polish translation --- docs/credits/contributors.rst | 4 ++++ docs/intro/features.rst | 2 +- docs/releases/0.12.rst | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/credits/contributors.rst b/docs/credits/contributors.rst index 6d099fd964..7d015e8d78 100644 --- a/docs/credits/contributors.rst +++ b/docs/credits/contributors.rst @@ -61,6 +61,10 @@ Translations * 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 diff --git a/docs/intro/features.rst b/docs/intro/features.rst index 71d19c1dd9..fc8a34139e 100644 --- a/docs/intro/features.rst +++ b/docs/intro/features.rst @@ -72,7 +72,7 @@ Features * 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). +* 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. diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 68dba8a8ea..b0059814bc 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -69,7 +69,8 @@ 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 Сергей Глита. +update by Сергей Глита. Included in this release also the initial translation +to Polish by mic. Usability improvements ~~~~~~~~~~~~~~~~~~~~~~ From 83c27dffec008aaeeee0526290de53aadf7d2c57 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 16:15:28 -0400 Subject: [PATCH 470/484] Updates translation scripts to add Polish --- misc/compilemessages_all.sh | 25 +++++++++++++++++++++++++ misc/makemessages_all.sh | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/misc/compilemessages_all.sh b/misc/compilemessages_all.sh index f22eff7f29..2b446850d5 100755 --- a/misc/compilemessages_all.sh +++ b/misc/compilemessages_all.sh @@ -8,147 +8,172 @@ $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 d8f685c5e2..96e45e6064 100755 --- a/misc/makemessages_all.sh +++ b/misc/makemessages_all.sh @@ -9,6 +9,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/converter $MAKEMESSAGES -l en @@ -16,6 +17,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/documents $MAKEMESSAGES -l en @@ -23,6 +25,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/document_comments $MAKEMESSAGES -l en @@ -30,6 +33,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/document_indexing $MAKEMESSAGES -l en @@ -37,6 +41,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/dynamic_search $MAKEMESSAGES -l en @@ -44,6 +49,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/folders $MAKEMESSAGES -l en @@ -51,6 +57,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/history $MAKEMESSAGES -l en @@ -58,6 +65,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/linking $MAKEMESSAGES -l en @@ -65,6 +73,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/main $MAKEMESSAGES -l en @@ -72,6 +81,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/metadata $MAKEMESSAGES -l en @@ -79,6 +89,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/navigation $MAKEMESSAGES -l en @@ -86,6 +97,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/ocr $MAKEMESSAGES -l en @@ -93,6 +105,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/permissions $MAKEMESSAGES -l en @@ -100,6 +113,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/project_setup $MAKEMESSAGES -l en @@ -107,6 +121,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/project_tools $MAKEMESSAGES -l en @@ -114,6 +129,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/smart_settings $MAKEMESSAGES -l en @@ -121,6 +137,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/sources $MAKEMESSAGES -l en @@ -128,6 +145,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/tags $MAKEMESSAGES -l en @@ -135,6 +153,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/user_management $MAKEMESSAGES -l en @@ -142,6 +161,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/web_theme $MAKEMESSAGES -l en @@ -149,6 +169,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/django_gpg $MAKEMESSAGES -l en @@ -156,6 +177,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/document_signatures $MAKEMESSAGES -l en @@ -163,6 +185,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/acls $MAKEMESSAGES -l en @@ -170,6 +193,7 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl cd $BASE/apps/feedback $MAKEMESSAGES -l en @@ -177,3 +201,4 @@ $MAKEMESSAGES -l pt $MAKEMESSAGES -l ru $MAKEMESSAGES -l es $MAKEMESSAGES -l it +$MAKEMESSAGES -l pl From 8b80798283ad0de039a399928f7029c69dabc76a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 23 Feb 2012 10:45:18 -0400 Subject: [PATCH 471/484] Capture all index evaluation errors --- apps/document_indexing/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 49f262f35a..d2fb37719b 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -79,7 +79,7 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) if template_node.enabled: try: result = eval(template_node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) - except (NameError, AttributeError), exc: + except Exception, exc: warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { 'expression': template_node.expression, 'exception': exc}) else: From 244aa4aaa865206939b59f99d1cea072dd61541a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 23 Feb 2012 13:52:42 -0400 Subject: [PATCH 472/484] Don't create the index's root node on the view, call the root node created when the index is created --- apps/document_indexing/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index b8c3647158..5442493345 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -153,8 +153,7 @@ def index_setup_view(request, index_pk): except PermissionDenied: AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, index) - root, created = IndexTemplateNode.objects.get_or_create(parent=None, index=index) - object_list = root.get_descendants(include_self=True) + object_list = index.template_root.get_descendants(include_self=True) context = { 'object_list': object_list, From 71dfb5f46a5c3aeb1ff478b4497dfb685ae6902d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 23 Feb 2012 13:53:50 -0400 Subject: [PATCH 473/484] Correctly match a new node instance to it's respective parent --- apps/document_indexing/api.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index d2fb37719b..1f0aa3287a 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -84,9 +84,7 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) 'expression': template_node.expression, 'exception': exc}) else: if result: - index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node, value=result) - index_instance.parent = parent_index_instance - index_instance.save() + index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node, value=result, parent=parent_index_instance) #if created: try: fs_create_index_directory(index_instance) @@ -113,7 +111,10 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) for child in template_node.get_children(): children_warnings = cascade_eval( - eval_dict, document, child, index_instance + eval_dict=eval_dict, + document=document, + template_node=child, + parent_index_instance=index_instance ) warnings.extend(children_warnings) From cebb22731c63602b33e3ad9bc57b82165f806095 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 25 Feb 2012 23:45:48 -0400 Subject: [PATCH 474/484] Calculate a staging file id from the hash of its full filepath and not of the contents Can finally close issue #1 --- apps/sources/staging.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/sources/staging.py b/apps/sources/staging.py index 8f6608ed3e..c6a92a2bcb 100644 --- a/apps/sources/staging.py +++ b/apps/sources/staging.py @@ -102,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 From 750fafdc721e00b11d79ff9e9b67d11f06bf9ba1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 26 Feb 2012 00:47:19 -0400 Subject: [PATCH 475/484] Updated Webfaction installation instructions (Michael Terretta) --- docs/intro/installation.rst | 45 ++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/docs/intro/installation.rst b/docs/intro/installation.rst index a11166bc26..3d9056fab7 100644 --- a/docs/intro/installation.rst +++ b/docs/intro/installation.rst @@ -71,7 +71,7 @@ To install **Mayan EDMS** on Webfaction_, follow these steps: * Enter the following in the textbox: - * Name:* ``mayan`` + * Name:* ``mayan_app`` * App category:* ``mod_wsgi`` * App type:* ``mod_wsgi 3.3/Python 2.7`` @@ -92,18 +92,18 @@ To install **Mayan EDMS** on Webfaction_, follow these steps: 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': '', + } + } -6. 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 --migrate @@ -138,11 +138,29 @@ To install **Mayan EDMS** on Webfaction_, follow these steps: 10. Edit the file ``~/webapps/mayan_app/apache2/conf/httpd.conf``: - * Disable the ``DirectoryIndex`` line and the ``DocumentRoot`` line + * Disable the ``DirectoryIndex`` line and the ``DocumentRoot`` line. * Add the following line:: 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: @@ -167,3 +185,4 @@ For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screen .. _Webfaction: http://www.webfaction.com .. _deployed: https://docs.djangoproject.com/en/1.3/howto/deployment/ .. _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 From e49db7769c26253b7dd93af31188bd5ce42c48ae Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 26 Feb 2012 16:49:46 -0400 Subject: [PATCH 476/484] Add customization documentation page --- docs/contents.rst | 2 -- docs/index.rst | 2 +- docs/topics/customization.rst | 35 ++++++++++++++++++++++++++++++++++ docs/topics/index.rst | 3 +++ docs/topics/mayan-login.png | Bin 0 -> 81156 bytes docs/topics/no-icons.png | Bin 0 -> 121990 bytes docs/topics/themes.png | Bin 0 -> 152353 bytes 7 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 docs/topics/customization.rst create mode 100644 docs/topics/mayan-login.png create mode 100644 docs/topics/no-icons.png create mode 100644 docs/topics/themes.png diff --git a/docs/contents.rst b/docs/contents.rst index a1d15892f2..d97a668d11 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -15,8 +15,6 @@ Mayan EDMS documentation contents intro/index topics/index releases/index - topics/settings - topics/development credits/index faq/index diff --git a/docs/index.rst b/docs/index.rst index b13a2291a4..c7ffad1fde 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -61,7 +61,7 @@ Between versions Customization and fine tunning ============================== - :doc:`Settings ` + :doc:`Settings ` | :doc:`Customization ` For developers diff --git a/docs/topics/customization.rst b/docs/topics/customization.rst new file mode 100644 index 0000000000..d02c96a485 --- /dev/null +++ b/docs/topics/customization.rst @@ -0,0 +1,35 @@ +============= +Customization +============= + +The general appearance of **Mayan EDMS** can be customized entirely just +by changing a few settings. + +**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 + +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 + +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. + +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 diff --git a/docs/topics/index.rst b/docs/topics/index.rst index a97ff7d101..f650be46fc 100644 --- a/docs/topics/index.rst +++ b/docs/topics/index.rst @@ -16,3 +16,6 @@ Introductions to all the key parts of Mayan EDMS you'll need to know: indexes smart_links ocr + settings + customization + development diff --git a/docs/topics/mayan-login.png b/docs/topics/mayan-login.png new file mode 100644 index 0000000000000000000000000000000000000000..65673aa303c77ea5a23cc67f4561a7164c50f7a1 GIT binary patch literal 81156 zcmV*fKv2JlP)Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RX0vZ$@8ue`qr2qgR07*naRCwC# zy?2}($93TUtqv1*X7et>BIiXS5&@E6rbvpCC`zJCTUM}S%eHKvZP~JYce*>D&p!YB zv+vI7d_E;hmh`hNipp7}7(pZg1W06n$iyzv<}kApy1RaV%!ZzxPBXh80qzt&_{?^w zs#mXGzj~=&iH?pADTF{ui4X#y=x_VA*L}Alr3485ewg~@)^US(thkM*QaGLOI`I`| zEMBmBjipkYlrs*mG1+nGR=-@j2s<}k_^cE+VPLnzRVf~W@DcRgRYIF#>jr%TVZZru zXgy3j<V$db{4HmEe(*T^^BTJ!?)>oPxE6p6J4cQ_TzRh(_NgdU`j~$7p;0Z>QZ3a| zEjMZr4k6XP7zz&sMgY>jXpGfy2%y4aF%iyZZtqXrE^b>&>9zotwBz>cwfOtNVH=b5 zg3nLDvBT%qmk?qM|H2`#3pZiN_BXOH0m7lsj<-1qv#Z81HkV_4xClyaN=%hLs`N4b zTy%DJ$|?`7mg}KR){-~f;j4~mdX;i5fVPD~dR%*1BZS90MT<+={ypm0iBQ`6aQv1t zKCgFV8DsauoeY7avITmVK7`LVJC*Bql|H5!eQ0iGL#GrO^iH)@%cQtYv8MTk_gSvM z^i~wS->h%`TJ`1Q61gGfunagw1;V^2^V(|x^LxL@yc1%fwZktQ?TVm&>~t)Gk>Kpp zZ!FShtYPu!X{GU)vvM>tQOrH?9o6bXQKX5$xARgD1*|4~(A0Lza745BqR7$%Dw zxBAr>z{Oq2aoJ(>k_M!o(&yqGkbdKI3LQ?|*vB%~whMlwb4<3FD_rpAt6Vx@kuFBC z&_asOb7^nOrQa%jROzFHJ~THi+)E1$(oTb(l_T*^#-dZ{^;E&>#8;U1Dus2b@EDe` z!r-i2x^Vlz!{BwYxCsNhpEYnQ=ss-UQ!$^F&~>@r%w*}U61chZXLJ&?eCOJsA1oAwjX9JUa(dIQzdu|3!jVT7Dzu~ z;BmuQ5Db&WO&Hj{##;$JRMK~)v^kl&m3;H%(0aMwUKrY(D!9VpVJgQr$@!O~0rS#k zxsdi}WB;9&35W9Gde19>-|fD=FWdj3wrv8nbXs{_U6r3FxugA^e>%lhEOs*$36y2l|HKU;YA;s*CG@Y%M+F{dNDD#xEwFZ*H5CZ zlyQ4$K3)>EmvkSbJxyi-@X|;^nbUFK4hHt(MP!d7?ec~LuK_w4B=d~h8)&4*uq_Imb|BVNB@(tO~Z7DIaB!woLC zaRsCl5zf>pWBt1QZO4ySn;~LfU32&OesM1HFXkJV#jC5JaCXjO7OJUv7e!^nd z=U#$nIYIJ4i%2<1U|lq>(5|U+-Sv~*1mb7juEZ4B0+F<$mWGCHi$sYV4Qz*Ov25dX3i$KVHd?eH3^Z zGzV4ssM3em^|VL?Jx=(Ff+_@-lvtKE`V16BK?txc>zbyB7;9Tm6cj}%d1hG_2!U#Q zChf4o_%l1KLMSMT7=Kp?F*+uJlopmHD?SOKTB@a5uInP4dB3hzqTfm^Jod%;dQ9{? zwix?ac({g%ez7GQ_DJ;Wsf?DJ2)ariRr+w!$F$l6qAD7(SOg=VBa_XIzY~c@QH3Ov z$zaOK_339J8sB-NMbI>5T(Cn3q-B!JS*WT;G@@gf=BRC48GV++LJ)~WQ56`;WH1bg z5TI&>I{93dyp-sX2&$rtfB2SZlFR3i5?_mDm~mD&fmBWplj*zMu~s*MR0h{n)qkTl zfrN>f^|F?_y7mK_6kP@l#f7yI|_BP$ZDZeLD3q9PQ*$Z$7%j+~^S zbv`SXFGS{sczOSR&UapA&cbD^U$=&cu9M5UM4~+48lv9o(lSK%%KRf zL_5}sDW#8q7`UKpeP2GRS@)~Wg&$?(^SknsJe#0 z!muQo9zhX#Oba5>DAF{rBt#+_`CJaeG|}`3mNCN4=f2OAJB~4D-co8~Fg%oI*8FyE z+q!{6`(Nb$e)0RPT-i=-T;tpizsplgHt_F$>$jL6Px1AC`7ArnNdDn}{W-U9XeXUY z^YV_T_^W?>oJW57)3mkJ@XfD&o}(A~XsnC#vnPMTf>m4i)sKIa=0t>CE?*J8s}{hj z1+Z!Xy#6eJZfhEjqqsb1x9GSlp(sLAgzUO}MjSiUA?Ge!&Z4<9gk?!|O>*k^0eP`& zgq5pS(O4H1h(b7xX<3-2DHTOUAcbj~1uLAUfn{MyDOFVysw$*uTEaApf|9H#Ad#x7 zV49{dO><+-jbX<)4`ElFVZvoi!7Vh z#H%My@zU;XsEgl*DHVqMy4bmEH)lGovZQ?->sBr0^^*rNW6i8uxe_zo$H7DUsA*n6 zb6tc(`(EPQ#a@=QuVL$Lo9RAxlJ1^vGI@h@uU}&I`c1SiosTdJ*1>!}N7vQMw9a42 z$A0DG%&J#Nk7PlO(HK|h=;%a=HS>!f`Uo?dlAJ!clh6Fq6Fl*)1^oWUZe<{4aP*~@ zIdl3XcigrCYoMPOUwDDe%jeNG$&vj#`QdY~@R48tE#7tiR<`~48~pIu-5fY}hWody z92aP-rCO@xEm555Ac_`0AA!;STnI&%v4|x)PVSL^{NFw=?tIsW`HO%5YqBO5W9Z^( zzW#;37yB>A<)8e?pD}+|&UBT||;Z#jI^(!?HG%{2<@@#t%90+GQ3loW&Dg`8*dNcsGgMCH9=|W8UJWr~_B| z=GVW+Z4bSJy{{kT)Wu<%lPXXA+gIt&D70~r&wt?yG%VeKI?}_oJ+JUfANv)yu3b#d zEU1=xBuY|Cl1wB>Bm{~UMQCw!)j$Z1))})|xoRaXbqQ9lZs+XrW9&V+hcg$~&^&ty zo7Qx3`O+mWTpA#e>EhIY!r~?KX|0bDjn>mpqjTkACs%p~*?RvYtlD%tdaRyoHd~Sp zZL(*hmO~Gfq|^yYed81ST2>mEur%oAGO1+jQ-Sv|?RljT@|(LbuzBs04THZ*a6VNu z8Fp-8$5ko(exVHIq{ks(6Nr!Hq1Xb55JDQ#kcbQCFUzAZZKrGKL!!O8iG!!l@Y3!V zrJQ$XK}qhtDt7ML#pw%ISh##G8`rkWj*|z;MH&!PSMh&IfnwIMDK?R!a_ z>FAb=m#-4H-*GFwou|2a^|HvCQl2^2DOauAC{`_BgfLBnP=sOR>F&Bh%e;0z`m4Xj z+$N1wI*U}IG$(c0*?CcjXruhV2R|(4&S;e9j=m)R?`Qv&uRZZSKK+UN7|u#@^5uP; zdF?p&-nAKqhSyrYk$nxicZ}2`p+gaCZempmU+-USMEi8ZliXuo2r&zdT5ew$kbMWv{ zHqOd3Jdk4f+ATzoX;oA?AupG|yf_EF$Ua9pt|EJis6RZkETt^HVUs17AK^XkxChJ} zhGA4~Ce>0cZzT_hBWB3H0Qe|PqS#C!L7Ku)YFM#qwP+XW>$6(%pRH@$YfVgAeh_#S^^N zF-U8jF242kf1x*{uqfKY=RW%xY8S63nja9`UfR!xKKjetyr|VLy|~Fuq?@fNn>6cTM9~Y zngxp%uxMUAhmRcR<~A7W8)C)UTZjU=Y@XIxbJ^0cfc7P`Iq}MNj-Ncs!}r}x_meMi z?8qUSwowOmXhSX zkA09wA9(;(8szhNK!n}^3{E|tGkCpT_gA2wTVyv&EpKGBYf$1HqmwdAfNlE$GQK5zrxlP^_)KX zC5A^v$mb=QOq%pann8w1r$&&b#h5ZgqA_rpb<{ zzR%v17x>NJ_)TuT^>$_@;Mo^$!@r(I# zS-hQbKt(yigitWDX_0Jhlk?}y;KHTXcy{*)z5PSt)-9{#@x!MvBt#U+{@pLggRdsV z@JNpONR6B|e-)cowz6~k4j8(~EqC6<;>8Qtf9?RgcKt*iYm6~8B1OF(#k5QoEL$Nr z-f|18TL`Lq77zqhe;Akm;-?>RRT?hzcW_9IB?1NF=GP zO`=D12Kxs|<)ui}MlnrG&Rx0z*?pQ*$6uwx7-rex+4Lk+^!N0NOBXw3Tl;45hyQUs z-Q8Urd3mS&-VeS;*YJq=?GHU7bq(@{Q52sQCb2KJBh*~-#mO+|z1wr*`JB|@Isaic zEmcY%HmjCz%$Zwmy8z`-y0~{;lQ=uvq^^meeFRbAbm6*ud&1$8^-Ki)R-ljRkq8=z zln{x<5Y{j&R<5M;&@)`_IL@jKn@9}pB@&5{sEHGc=;ShKu3Wl6DhD-|i5`ovYSW!0 zjn7fL_%_<+%;ojVCx}HgGN~atub2!Dk1#_u5qgYxJb|VN6h)<`CQc-xW644|gQiDF zBopl2w}b!vw|N>83aM0zWYZkp_nrr7X=$SG%FBG^%l}McZG^-7_L5J|e4(ngFR7j z%-0R?eUJCx+5#3_~ZANsDwQEe8jOMQV72Ces>Ulq|~>nQVrp8H>f%+wWpQ zi!M@`ESan+OfyX;n_*~Zklx-NYIMofbBB3m#{ue>Y-aJ?T84&FVs^Bin^(`_E8lyX zRD3xff9xi5eJ2^VEcQJ2W3l_lDL($|pWv=7w=yds#B(pa$m<;!v1B1FjGG|if^Xq+ ze3|c2UzN;hn0Ld*VpmEZ&J-~&eU)rpa0*^tyLNF&mlAMXo$&h&8fOUn3NQDx%dXxV znm(q53s_nvBRR>k_KiGJGekUD&rP>K%qJUGv3|uYQWux8b!#o{Yj0-ls@d$=`ziyu z7$5t@C&@{j{BRGayDpNbYv%5U?gk6yF1v|8`cI!?*WN>9)mi-7Z~qRu5}~0!%H54~ zsMk$$#JT^$`)FvHO*)mqFieC{x%svS5b+~q4FyXIG*v@W1tU4Z+V!{bz8;fo-Xxnf z*nH1Bx&6+&Sh1*$;U0sxKX4y&7R(_&qm_?*>=Vpt-#~ps9qYE-L$rAzYu2vdzy9fe z0`8ugA=u)CZG*)iBlRERWL>6se z?t+C}8aPi)JVGWtMCTQSf#DJ6s|ILE;x#pBia;nTHHjLcQM~|*lxVt6GMQxeOS}0$ zfA>FWN~)yNX=)l~@xJ#wL`!oMLp{6r>Q}zZjK&&{?BB~sw26=Z!uzSyGpL$QJQii+ z=1u(FXTL(j`pqm`v65rEen4_oGdHcB%gz^{<}d&IpYha&we)nJBd0g65~s-bHdNQ-PPi{NJ}Dxf~KknEb@jqe(al2G-_(%;Uh4@GdT%I?SGfukp5bKT77xNnShCDOar7OzP@uV*5+`Ni?-Fr@4-t z)L3)V8gl)e{N;cD3%0)RV|?(j_hJoQ<>;YTWD#EbXW@_q+9Oo~1{ z_>}_=>1OE)FxJ?&+m^KFHufL^Du|Z{jmOdMxP{UKZ#Oi3Od|nMplT|bqL9ty3Id>} zlFwy9(a=-{BcDeoYQbe|npg;QP2u9{W9-_0lx6F;ux9Bz^4Uy5h}3il*DV2#A6XMBWaO0EHq7# z(vnz0K`&L3g-}#kQ&S`InGuFlX&H&tP*W2lml+YcydgdKlV^;VmkTsR&N{C-D#{7x zwZOZiU#W;D!_bGT4tiT}_ z7FE^Ib(LH$hhbO)<1Rq~!hu_uu6Ho`c zpzE~oxNM{;S>Qd~Yo14axy^~QKf9ZAT*xgIQi3czMM9QyBZL<$ZzO%V!R9ufRr+}2 z=|l628E`HVH>wNR`P`07KR3-pI~Mu8yWkh(stoIX3W`^#bfKQCOU`XfE+5X6xq$s# zZr6hgxDtWtdUgSaneVC#`1*7K+l4Rt*lY`w^f(aSHI;?i0_JKpn6S>+;+7N?MabM( z44utG643S-oFar3rzkau^Oq1VK97xIuE%hBz~^7(u3*2M}NFER0Z4%>zi; zv>qhTm)n-#xZcWn04q`A%2f)&Y#Q)WlFLz4-S}Hr0lXYVyIccBxk_iHidq=Ow^F6| z&7zN~@>EpmW9sQ++MEOu7AbxQHV45L1lUS~_5c7N07*naRCA@wv0OZac^+mQlYy_? z_sU6$QBE2YKl}<iA9h9s6YQUQT=E;9#o8R7o3Qm4q;ieVUvEB1*gP&7n4Kjd00P zCLIE&Up$#`nJ-@#pJR=&-z#!)1>|{?Hu!~$%ghgM-vE9)9vlm+SDv?$yl)}$yt$tB z>eZ$fkFuTVUb6WhSf;4bN0mNo0^oEjiXu>iLUk8MwN%S>R^(_-I!jKe1>vn)?2ED^ zbp>t<6Ed7_NgqMO zYqzKfp~%WGbKo%_UYi+$=Br8{*9mHtd;nZrZV*E5)mR znEXF}eMEGPXe5HFC{$zLtEF15Gx<*zzTLcGlFjAD&#f*u(W;XNloQwK<^uAwCWZ+y z@Z(`#F+4%MIjluGOdhuqC0U5kI6l`Hv9e@TykoBXp1ol*bN~!f0pn!axRF+=Dt){` z^dY4jJzcCI1O|nVdGU&AV*!*vO)N@!WQ3<)+{3;jC+Hm*VC)E_sx`1$s^!fV{v;7i zXI|S(?%A@Qo7$I>$>quA@>S$`<4jDpj?<;2Ynq5fbyQWg3xH0`lnA--d!?}u0nhw? zCo72frP&Yx@cX?hd@O3^%u_jOK(58gCCa?6(#IP`ABD_+!WvVOvpH#)rl^!ZXig0= zY+O^h?}e#5*%&~-dhuw4-o63;@n65iSHJrtJslTeBs2DMbtS2mYI*ae8PGLosAu!q zcK+a3KEONf-ioy3c#gQRagOEknW^GimBf(x^<6G+4x9eME$&EytcgZNCYzBz*}ac_ zhfj#!fdMEe$$l$IU=BK;MXp@o$TQDd1$BeQ6Sh4nfPXS=R5}Oc;-JzzfK~dq2J|5T z%d&{*I&)^WaL1;b*syvzdBY@=%?0r@_ZYzGkOn3i(aGlWJn`da_}ec%4t)bqUkk}Z zbfaGuEHy=OA4Aa6!vB z+-`bi08C*bNXpS!o$YzT9yF)`oZ|vpAX{*oUzY}oaOa`CmrbKGc(@`YPTgLxeFGvA zLDnUC^~h^HwS5ok+Lxj#Dwbu0N;@;1(!lufM6dKpZbD{6*U1@qzWL;H{Lg>-8dg^i z)Ym~GZlAlUSkSJ8@bg9pPH$Ep(;)`1N*|%$99;uUgIBii;V(uqVrEM-w{2L1X<3-2 z6*}XA5CX;dlHJV^#@#aZp7X!`J-2&q&)oWSd&jF^FZeV?p|@{<)8{)1%uH2_1&%_> zdfR{7qGZ1(gzY}IcPVbG=pDzik~SR+JhuLAw~E^p?*DP=507`eU@iGCT;R5k+c5~? zBD8=9e(f+h#*G8N&iW_x4(mUm=|vi!<$`%LOCJZNxxi^MY|5;u?Uy1_Q>!2Y#Y|VprpP|qHFfI zBtl38ZaZ5>?+XXbi^8+9cS^qnS$sc);bpu%Y`?u9Z?FipFn^cE1x%Rm!nqN_j^YQ17{;TwHZRum|bTVCs z`dVH)c~<`D`JLqQ`O!17OO;LA_b#10Lkr547Q{${1jMlKPv+eqxIvQ3=NZXnM=e%j z3>A#Vw;(ekkT)S7N2p4eG7p!45IZ7G|rigu8FaH7S+YPTB@adscS4@R)K*{f>+piS0#A` z!-l$e)eCz+EPoB*zINt7^Rik>+qD!xE}xU>OlFL6N^EumA%rBCm84Pec1b(m`^$Jyh&l+Bu8Aed(5OQF-ed z6GFsj4i9n1-EZg5e(w{kos)p9F(KreCJYWjR}b_KK;9@IFqeg%Ug+(I{vo*B#j3UI z`0%6erY#Qi4-__=bdT1{nT2{155X{O3~V{^sbQbH?b;98$?tVtNnNit{KgMuy9OTstWP zYqM}E$E{*^v=**K@wKp99=wDK$4v+P_IgDwco)M#aUWB#3%JNdDkiSQ1kOjJrix)6 zeZL4-PJeD-MifyLmp{?ADE9C=T))$qKJ3;<;comA4*Hn3iJ<-TUW6c*%`!BcB5#f& z*fb!QXZ}r_`MqCyl#NT<7#!&1>)-e~|N7+1-2ULZ`1D5~W~9HLmZm5#?%B@w_xG@Q z)grpCcJWK^e3%Drn$L)c(OLt4^O-O5-KTaTwS<#kZ95=EiL&P~rI%jg(T?ZAGIG@6 zWaoXkep$0AGn zlpgRppWy<7bd24DCl}#by5XY~Ev55sn*(PYtPGKUE6k?n5?UH zq2d%>kE_CSFSl*+F!Hjcbrv_ZFXQPNjlwYmLSR{t$;tSvHWs$EGBPy4xz{ftQ)$p6 z%wDsaq^`(;fquIB2Ssmp7l)213>k`~p@D{mdO4%Hk@R4n=(yC4%$uMo5-AG;g|w~q z0vRC3jEOGNhlpJAya`7-hZ3upo!QCJZ^zB-WZz=%Y)h8J+_{g#D`$b%hv>1(QNDB& zoeSD*qKQxa`iDsjz0OB|`|sF%-#hv6&pnDr%;es;-OZEV{W{;+eU5+ltN+A`c{6D_ z4~yr|ArXzTVcklyJ+JXwfB98D^+%uPoo~CH9WTF3*N}yXDx*$+hv{BQ$KRret|nr! zeNuJ^QJgxmL~awM0ms76MJs()dza@Wg5B6S+|u0G;dY5`7B=Bb`1CEj)-qZ0&AKu^ zXDS;vrCK=CsEAVG#_p8eZ{M-vlyd$+K++k+uWth20Y1um(s`8pJO>XICiXa#;q3h6_qE zqn5i|j#(?$^T}U&Kew%#F9!R1dHfqs@NYle!=`&4PD?ArN_Z|8o5D%h6 zh;X|W#p}JR_UxYs+HFIJ-SsDN!tW*2`w0Z@coUBNQNl&=aKoFM+p}0x_L~=3+Mg^H zbV{szRr(0YgNo?GzBz1KYyt^ua*&K3j;yMnDWGUH&X~{Yc{M!0dp8&My}*xt_A}1q zn|b)ott^fY@QtUoae3#9eCH=G&^^S|43>0&aHj=rQvJHq9AlP-dz@M#N=HoW2zrAM36r%mC5 z55H&9g_pRQ@PhE+Hz#4>2ns^+q6ZH_-E$s=2j3JS|4Sbp90aFZ{OII(#WdIiB3(W@ z>GsT#62gfS4^7xp+mz&T5Uu0)e(l4|*3$t7cLS8PT|CyJwxzTg#_WAh^g9l(ltuN5|F(}qI>srB zV6|7bZ(#6b-uAJ}5cDBs(Z&ONKX$wnqpBFr;$cd6H-rzp7H`&Y?9?o(GJ&`0OdsKR zkl*4im1}7MtmFtLzxw6Y5upP+3-w0QDLO7)g3eC3)IncwA9-{Vu?S$IMQTV!Bm+Y! za!QoArT`Z4ni$GxptL0|5Q6kjifqn=nnpCmB$XM#3d%w(q|MswVo?{;gXc?k%hGrq z=|MAL=tz33Cw9x2EVal9hxOd`oA=;JB^FALzJ2d`u7joZL>PR^()LR>jM<*MZQu)> zJI6f{5>+6VU8V&XJ3?<@VNs`H08tYV4MdGlp`&g!@;#_eN5E2mP@fL@D8nq*HWUya=6_0E?m6Eb?d~s;Pj9P$R@ONh&>p(HuutC@9ZS zT_{4q8a=H50ja@ZMn>|2coVu}GMr93lw{XW%$DEHEq|Qv2)#d;q9-mv{;se{Q52gi zLa>Sw+{)q{d6k?V>ugv0e$K*sc7qlp$Hod#q}vt8;FYv4-FF;&QJY<$@?x=7`Y1;k zbw3Jj+QtCdr!5-gwG)TgePlJu*KB6l8UKD ze&WSzDW!XyBNTd{rWG#*L2~-95O<2P2 zC@c!FE#Addw3nfT7$w3raM#5Z0STUXHqda9) z+AM(M&#D$cAs~_D#DP8h?k9IaBvO2eM>flsKKnVo^d%jPJPZs|vuFwH+ZU7S>u1Q& zINN!VR}Y=x*sh%%+X=*DoH=t26cy1>$FAp|WS0d*bcm=0I7M}vW3^Pvl*pS^3t(sq zpsl`rAqY+b6N!j3r;p25Pj#?y%iXNoBG6R9zkT(~eBp~<6d(N1hxy=R@1wKh9RKHw zkF)!52WH(Y9=m59>sGHMW|=~l(0So?w(o_mzJB%|Jk0Q=OM-Zevu94SD;s4XZ53j$ z$2Po4={$4Xk={cV?~o`_Bpesg&nDzZ^I>1n?P)%Q3`q0gvSH7@DWFIgkfJoL3Ak>I za-QHS5f=!&>G4@OnkWbZ-2FBrz zmTm&_G^dY{JjmAqIK7t+8xoaKBxkcWrl&(R3i&)_vW0h&HKd0JIdu30@4RypbK)wy zUfRLqKi&a~S~zD|2vC#>!c-KS669ee@l@Pg(gOJnM+$G{&t{GH?Au%GDZO_4kX*+h zN?{N#mO|$_$bMtMrLGq~{H%0tN~v@iqb%mJ#hKxS51xg)WwgXf=)-eL;GlvuFv6Xu z;FUyF__(=bsY0ED5>>5mgrAltj^4bmK`syk*rfVL^H?l0s0D!^$Jg zhqQ|yw$)p@nPEy+b7xz!*d6F4a|=hR0XJ7l5hIcAa*Eq`=w~w)c4pvA58*N{hmck} zH{sI26uD80a$QYqoDfbyZgf5*)0{p65-W;Q`Y6c*IK9)r*l1K$A*Q<1gRX;aTZpYZ zFFx}WFFy5CyM_$$m`$KmCTLhyOEniatFm<4?(fJCC<1(CMQK8CarwFQFDlFf=yok+ zajF6do;d?cOz1ADR@}OB(!ap_n-DI2Is25t-<)6c-Pz|zmZtA<;#o=$f!XDrRcHa#M2rr-G#tFy+9UcaS%QReU!n9yfP06A*wFm375M^ zqGIXs<>@-8qbXg4LLqp?A!vD7HwgH!rBA)E?SyTkyl{eGfgtQSgonjSgsdM1{-Av& zGKBRkAXRQza}{>qOi-PQEP#$*5ztl`Jc|&tB+H<&3N3(D7jO|%FUbSw^&UYnfYR}` zXey|2x5gxq2t=3&SeF(rJpEH%c>2l0wP{IIO;A%aQBRE&5?feOplK6bOTUa8j3$W| zj%3kZ{8kpjIab%MZA+K&cz(yyZlx)-7sSMc)7mA4O-Z)3;qn37U8&Bb^-|guEjezj zwHeWh*Et6cq!S0yuCR|nJNkEF7p)C{F7)BG_Klwp?BZ^jP(mH^I4&f~;$6;x>+1BP zkMIiVcpgCe{pwM0ev6IpF_){O?q09lb>#-yhZTszwiDKHSFS$66pX{IU%%%;;|}wz zoc2R{z$d*4Bxn}iBmb}@is15S@*AU#ru?W>k*sg~=uNJW8knruE_-7gh_zu7E=W10Si zpZnVWoWO*0f+EXL$=RfCJ0``b&^NZkc*LbhXQ~VlpfE|7Ab(pD@)ECg(Woct2)`B9 zW<_&adx``K&)5-<#oeuMDFUSq*N`E%V}HOu+@SkB+vU7wza>>nJ6J$Skv$cn@lli^lXFHMswkE$| z5x?uOKD*FC{$;jXjtwg0SJXOFnOupvcApq@8a#Lt3VV1+b@okU6tj zdEztw1Jkll6{WhsR!g;9=fyBB8WJ&vQzImmYP3qgqBf!EQX2c{OakrP1Tyw+E|Z0k z5kWK(lqxu^ld4>2rJJd!T!&h@S;u|NJ%o48O-1&8uHn0twiz}}M3p|?NcvD!$c&K5 zdP?R8|Q*EW&s?t67&rWGNYx5Fa7nOid^21T2Z`S)xty70_aBzRr+`n z=tBr0a(RQM+8VOCJR_qi>>M$G(vNRV3m34eDCBZEMlu=Vu^5I?bpcmPwOr3dBGEOC zp8i1;MU>5Jf_PWCJmp461LM^0z0$zg^8bxr52w;J)Ft`l#~!I#c&--<&(yzLX`59G z;Pp%&(&EU`W8`vqR8@6)0jgOQ$>ur2*H2szPEr$u$nC@v{!dd{Gv4T!KXR>)RnJlqb6w^KSvXaTHbpQSvRm64P z$Bo1+s`T+j_8}#zs*2veeuNMx4qh2Xd94Q4_$(ro3a{5@0hP9V!{Oj?6YMKlu&Sk6 zs^x|ev`g{;I*x=YvRsV0faR!RP*Dnr=Tt?p?bt>$Z3B#bhop0?emu}#*N+E}!R%JYqkl*DMLV`#t-M}y;9?MQ!+~47 zMKI&yYOT`8n@b;Kr}#{K#J)0$+niMe!0TEdwF!Tg1f@djg=v~d%Rl>!lvm8}-LMu3FAI5)8@yP!l_hzC!}2dbWxsgAEzZ*6BZzpm z?`CN5vrq?x1_a?N%(F24gf%pj;_S_%kD#%XyS{~?M?bi)1$~sMAQo=|aoz}G7+&uM zF(5a9yy8_tXgd}4>&NuQuKTWD;Y?>23l=Rz&-HWc^((AcxrW9>bW%i8NfE%s3+EV2 z=V)KC+-or2+kZyycU`&4K;IxMR4#wZ@ILnpZVH6>mIe!t&^|b|j<2+GLmduAA zp?baVHD~3z-ol10c+pANg)!)USo#dpZaFZN6P^(Sd!_Zu9cv{a3PIns+v4N53$C0+ zAq?MgEY-S_n}{HzXyB zs)nYyF`hWqp49sGpv`eqzab znj7jE9vWnLIE5C8f@vUy%8XgFP^H18%a_q(HMBN2jlz@R$l)Ux(RvmwTELagPU7`V zB;!#A`g%~~^|UtDl1&fLd8rFMmY}h&4rv*vdIZZf&>~TW28S8w?yixicO&%#Gn*U0%yIVYSzdj457C-t>T6YA?-}9F+cuMkDj;R>RxY1Kb1I10izdQY zIf67(FW7_Lt@L9IVr*fA53iV4uT&sG46u>~s2rg#tWxIpp5J%xmGQnD3zi>#!tkx2 z#nvqj&u@%wmVlt0zCuhS2KE`NZz5=yKE_>tgS|amxYWb!xpRn^!<_2u5{s5Dr#>F> zgI{>?cM)bzT-p&*N)#bP&(%xx4W?MSbZOAq;W@tEo?iNT`dHS!45zN^e7FBL*kKMU!_Z2Qc>n+)07*naRM=dp!f(y;a(%nVJEC0URXOw#)(GXt52mFB z(2t?Zv456@qNu2}|$Y_mx;OF1Z#l8RsLHNG&eC>&Eq1Lx?&s}%Wb^29K zT*gTj@wP%33`UYZAoxy=Vq@q(_nV(xg&pR6Poofke>Q)QAB3`+8BdD0Q`o(V%ye zBS(%fWaunfvV{KbF4Ra3waGZCp#jiqs7u6s%0>3=-if6oXh>?D?;d9BmYWMoGSXL}3ZkuY z6xOf`ou85yR>AY~ER^$&dRf(+YkClDLEk`-m&pwdH{+MrH(jX_%8wUKhCaf|KVEaD zm1BjgWN`>9c!h00Y+8m&;ZsFH0IaF4C8-Y}EQ?&;psA&mNZl;Du3X^w{+-NdTS7x~ zGo2mh7)j?@fAcMDTr`8HpWn^8O&huLdI#rUdyVF`3t7H;HOCI0q~rW~GN#JP)oU5) z>mVPSM_o*C`tSj+Tsp)2C96?2h0e>JtXa}V|Ii?LOVZfT#L2z^mapB!`W3VJ@|Sne zvTzk`wQ%^rF3w#tdGO))F>>`3-96pp@;RCmfr3Fglchc$$1+U@`}&!`Yz?<3gf>=!>YG#N`Hbb>k%k@&GLTM<+0vLujRmvBG zl!CCl*=y1CvJ8g}slegh9IIzp7P)-BkWNcVEX(59t2=r6+h-Xtw*MiMnKgivT|Ze`%|RdPc;y!uKn$Io9u!5}q~B4=sT)z(2uBhpw; z)XI<<%92RdG9ne4np;>nrwsr_s3<~U7V`H4&?&F+2 z{Tix~qP~7M`P?8UPaI~rua9KY0;FY;%VtrcD#>I$b@el;OVlttkfVOaJZ7{c85}%C z=Y_MFsms(iC$OY}qDRJ4=Tu9zTo0ujrWa(1D90-5#hb$Lt*|^QD4y1%ZCQrkC>+N_ zjk)dZ7M$aE@2BpRo!zKwyts~q3Aop|jG>YAH5bLKUf z?H^*rnss91vbntQ;!7-BwNmz8y3E-VCuGa|MJ!&vTpT`llJjTJFqq2AMN5{8{LmGd z)tg0KT$QJf91z`?&&b9Z^H4R7vlq^@YVmCP2M5U-7A-BUyn0}_Xj|0Ix)p8m>tFjW zk*0afN?06xWjp6D<+$U%hcNnI7gw)bmJ&lGX3RmcatsU($=YZPGjE8#?k?Fhdm)?G zFXN}*|1tSkEAtyPdE(G6@%mMR^;_?kapNK>QxWmnW~q$~k+apdo0eiz76hB}*1kUt7z(1q%_1h9WZz zq)cM5SEijc)Fr5| z(@`QS!;=Q4v4swI+*!C=SB895QS-xyBm(HHx_}MeOV&;gTlB`eC);5=9jo{31A2Vjm zq^Y46MbVfwdk)6X5UGJK4jvffbVoN)9a5{+QsSiz$qD1Ow zZE0e`oLS>*pdtj8X_7agrF8~P&9jI_G*A-ET{MSeQm5%Jd_mQKYm`bPeqd zK3ep8%p>|nq)hXp|FAMkxyt5b@|eC^Y2?b;JUOk?z<4bVt2f@p>W#M*z5D(Te7NZP z7k_Ed_}_~cE*Ss&mfJP~uyEe|@q6nxZ*}Q?S;?J+%T^X$>vgl3H+MFJ=?ok0ymkEk z($$+-x_Z-u(7O6&7Pqfu$1_i&L?bL%*3N=u?Y{lZUA&SHE}rPGrG6bBS+Q>P%H-hg z?W|h0oW}Z^F~lIKmTI|nR=vr37p7?u72sL8UEAAqv1*RxR-sLOk>Qb}q*o zc;KOTidjiGbNn!g+6Fdm*hp)Q(Y7|`%wIq%g=lD~Bc{v|W}*q*%!=lQ+0?|Ocyap<`iG-5H#Gy$+T21c z8m05%MdmMBMAnJ{n%H{lMqb>phsy)4ynWLa>LNN%J^LbqsSLN?dY@P{cL94|+0Rf` zux4qSnAOxkJYu3nH4#e{#(v9|O+5SDHhHmoSghG_GfjyE&+phH3?;_K#cgB;yM?T6 zrY4aX!*BH@kO^87ZhyOxC1sujVr#GHw}Oo@fzQWi->0tUNgz&mCPN?2jUi!``Ji`2 zM@NVBvzp!LE?`Ab$Ye6)ayb?+UW^`)3(qi2By!aCDKYYeAmp*rLrl{^N`at-aIqj_c< zny|>{4OCS_(^RBYcvsaUAWgb2U&JIrb88FHNa08r(=;b`r;SpXVHhZ?S{TDmLTICHNXtYhDqwN=r59zt+9bAYTua2?2q=9P`=G@?tne5X zmlFSD*8E_0p1JEvA7#$7A3SB#2j1rdS5lV%xPk=Aa^}vLK78VQWnW*PxOC|fb#-+p zg#_+ye5E8A_jn@cstb6chqzSm>L8a+bEG$+m*HbVAo7{zbqvRM*! z4I~8^xeU3{F&jo6!^lt6%Zwm|plL=MU||?}(&?P<9GZrKS=3)a5FDG+8MEdV?&b5- z>iDv1d1H!YS>$p#6h$fd*1`yPLA)kN*{no}ydGV^VZ#pGa8>D!e$zBTD5#olQ;Hd% z#|b4_MO6#eLKJq~no^=^DwgT4BumQz0hT2ZLIG*PSO7nT<2+RXMm~>enrP7|ix(|s zI6Xqnf{2i0vpF?xcF&pN^vsYm%|#1#69gKfPyh<0 zb!AnSNG(FRFx!U^59o zf<|7|`a#>V>-E91T0YT%AD}cbgW1suSd7B21?G@!sQ0Q^LRyF9EZDM1*LS4}I4L5> z^E~8oxfiOdoRNdKdY%AkBNd8*u;yIBIQRwhCyN`1KB-D#4hM zIOwhCdC2GU;GR|`Tpq2I+69kf7 zi@^zkB=(zB11O3D7R(3HI0O>O!G*|tG$nrNQVmbiA&^fGrf6@6U?brrqIA$;ih0vNp@)D6B_Ry;TUn#{x` zs!#O0tSmk$d0GrRo$`}DvtR)7{d`^+fLX^@r+=ckGZ=uqdp8YrFI@LZLz`r7*L{z4 z)=$;Crt`k3uBTaplGZFypGED=Iu@d`MSp4Et)#UiX*|-b$A&+W_xWc@yE+OujhRu! zP@=lhm@c~&2(kzOy6x@-m~vL&TGiaD77?ACx;o>f<3pC!Oez}xr1_QIFH8BQ(w3{n zA&Zt@M}whbLQksKL;j8Xq?W4+{B% z^92?1hiJ|Wf289N!F**pl*QqpT58%@pB)|ZPZpn)UYlOCJfmy=)9J6S$x^qCSxtq# zy0;rY%q;!r)&!iD*LrE5?B%>>HF4{h`?J2Mz3}nXaTn0xyEMXQR+o#c zK)+nBSZybNkp@gM|GN2MrQ^o)5hOt%yarGZB%}@KZ1_XYAENrZsUtp+ZMlGVBMgiz zO4G6|_`cr)bT(wjQ17XEz!I5SyYc_w1s>5eI|&9Rsh#o9w5~on?l$I-Y{<~_J0z!x z0#+&ET2a8VMQo@00Lt3!d0wi_1cnS5%D%`ovq8xG7Cf{#*o~BEvbq%Q(*0exe?MBF-!97NrY!~t`bWYajXd2X{;qWq8z6je zS4RP>GJ)s-DH|YY0|c$=pG>2)+kv1(rb!(E%xD0G{H(2li#f*gQJGA&kvDt+S#vBJ zhh*MIOj)&J~S2w45}yy%ZvuVmw7-B>K(p zM-Taf3sh0^2e;lS%iYzs&NTT)4GfHdfzfG876Daves>BCOw#xmv*I(+{6MgAFhQiG zDCnRK{-YrY#y83|86^;VCMnxQ){G81?O_tZfF#_n70e;&o7Sr&7%$ePkcbp@s{}#a zF*5woWB%Zxj+Ok;Jh18T$F39rvp|fbfq_v8HqR3VCQUnZwHY!kZnrQnGOgtg4FjXA z6;riW6}h>SVPLZGnh^rKKE$@7fSVdW9wLSl>V%tXJPMfGP~w|P948Jk%(FP|px_;E zMkDiO5-!UK;mT=ivn+!Z$6p=KG{yn(I(cXhE?;u2$Tplep=npJZZZy9gmDlkgqyF9 zDAss;csLSS&es^Ph{gc?voajOxUj=PxG+IEhCh15AA)QpPzk=V@!=zv+xW&rJ1De1 z9VR3~K%PmR03ia+5@S!r_%7fp;$`ZXL$eB^h71{c?uS_sC@teOer+2w585ls^~-Av zWdefWewnt4zqfgfhuUD=2HGZg#Oh&jO(x$zO$$t$NlnxTuCGic+;HP6EtjuDVS-Q6 zp2fAesyX1-awd9~?~_D3X!zqtz#lwlwP+p*Atn`E{I|GIl4V(K&i%Xo+6D7?_;Gxl;``-KcfQ!(QPU?Q9sg*@v}+=m-cs2D!6WVGV8rBLMpg4 z^>y=3?RFWkvH1{AW7oRY{EKaRM6dyhKx;`;Y0&s%%?*W8N(8B{2#eJTIlf!RMkZ>D z0L+&(A|qScpT?R@IBh2pjEl@)ip9nVlKa}qj)OOIWykv+-=Nz}p|NL@o@*mQ>SsyK{2O7&0DYd1D!sI zqEEtU$d&vddJkmUQJDsi``%OjfJPROBn`2Ff#C$4)uqSy-5)-|%KADA`65oe_6ANL zKLpEq_5#q#;ys-E_9j03=;v@<2i1+oxN!9*MrMxTK(UZ5JszWYw77`U*knrpl$B$V z0Dt_~Pcb<)hDu0q_~=m#m-?DXATw*ROc00(0_jx{h=GCWD3@e-pOT5dt8JqWU^wSpZn$(A?OZ83XO~Hxu|TF;Gf~Wf3q&NuvzXu)vTY z2oO<n>d!U&%0wzZ!z24Y#Q^(!_$Z9ZX97?N782FrHfd2T}sQ*TRM!mvow zMTgRe1bzU^0xUO2Y+}{jcj_G>Tx7e@$zO%4pwQ6D){?F^CP`E}k=4PEUz|TUp^ZpV zr-6G`sR4{@cH=4HIDa^8$QM;wv^alo>u87eoD{ZjvYG+e`^_6uHVAY z*cAG59$e2sKIdR_eH;CQCDi-?4vBE*=2etQAKrZ9b=1}tapBSp^p8wo|I{!Z+`olS zKKlwmkjI}la0qW)xq{ob7BM`vAK#t(BOb1YIC1PCD(g>hW8pDQzj786gL$0$@(Vmz zDPwkO8go;lSYF-6=)@2z+nexfz~=fkYQcRhKe&N~m!Hj8kp69kgvYnnC}u%YyueUi|q%00WWvV>1Q{S1$mmeDsbh%>Lf zj-&hMIBYooqU5x`M91zDrSlh;xOBWGs``CAM5}p;} z+LiC|-IaUT*!JQ15AnNC&g0O@w=gp^fzSWtzvExOx{05C^j8?qQ#@H-!shli?kp@} zes&!F1qUnJ479uo;^q;C6ye%ke0Tj3UOr=Ch}>&UCy*dW{3s*-`h zK7@V^)k=uXjV;t7irUr^9uB*3kOMeN;o5EG+ASh#&1SFT;b*XM8IPu_bI zj~1^npEzV>=x8FOmTnYq7nZE9qkskFsUTRS{2^$!RupiYUt{g=&=MzD6qHfGGHt!& zJrF)4i2|0kMRs2=_#@5vFFt3@y3N)upuqRxGltV=-o~jjr?9K2L<qE>H zx9|_Y{u2EK8?U|f4qkm}AAb9*|AG^*y@!IogipV`h9G3fxdfGvf;vUmEW+^QUcCR| z&#`*>Hwc{){@q{v6y@p~E?v2V124UWpH2woeKu!mn^)3@+vfBx5qSQVEqU%>3aGx+(jdHj!m`WSvl(O2k4ZMBRr3XwCZ@eCRI z(Q5rP}(UTRF1}9ZSiuc@DL}DA4T4Ic5|0T!}LRFk)K8R zy>RhTDXy~A|6{XC=pS?_YR`3 zuOBxqUBb;rTNoG_$5gQokM4bi_1h0|{N=wz(RJW?Ma;|$;?AuF>^b-f28!45*>C?V zzAKe*@aR#58;dBHE9mPV#J<^SeEr40Vsm{Bo;w8BuD7q~*r=7aQ3*@1zz{_dX7?U| z_w8+5x^fwB{^U)}PY&UWug>AyFRSpJ0i2zg!h^;8`1n^JBcIFR(197S$VV7OAOONJ zz|71(4D?;b#mnF0^|#)_+mnO%`uqj_^2Q~suT)_ZhK=erilq@au9HfA-VOet3I{Ol zoa#QGR_&h^2QUjyW-)1}(Q>KAs#oTD-TJbYWvC<2LmC9aX97ve7!Y&XZ>zwvZ3MLn zTe!PHjvhURH{N~=ELg?(^j>y6w6U`E7*it!oIZI9PG1R+mY%S_!4bT2@+4e~qBu~% z>e43r{_1^Hsv*{vmf72{A0|s{K3;qKFK}S6%Kr1Oza+)H#ZH}li<~`qgnjzke*6tcK0*3QM2*k zhaaI9mht76Uts>|S^RYG1pf6mf53L72Fe(moC~lBpp?P35rqM9`-a#r-uV#ujVt(k zwTusb{t=iJvM;{;j7;r4j-USG2>bX~zeW%-QW_XS_3;|>{Q!B#C8~@nx-cKjU=q=| z>&$;QFfg(DRM0|+{1LlGM8On-Hc88lwUfxSn9ziQ0SC>JCkp60!X^% z4`_f#!vujOOU7{td2)6RAH3g(u~MOR|H;?hMgQ171eBmOGKzi|h$z7;#UUIzv=1B0 zi#YqvPcb~c2geWX!(`FM+)FGCe(~o+`0mn843AA>YGM+ILWE%reiUM8YycyrNqq2ukL$M=Fg>*g z2WBUc^9opayo$-mX$%b(apC+E9D4mFA6Ccm}_Ny!+IIKZuJa}$~D0H9ha!z~Vz|LHG(hSNvp005u-^Y8G*mzRj+<}jQu zVQ^>|kM7;Y_g8N*r%)vOM#k9X3s-Ps;UV_^hyMiy8zhVfo1dP*of~(^`20x}3wQ9{ z7yp90r6SogI}1`>AyG(C8XO{16XUpY@jR(+Z?a065XY)-x;fisB&?EJ7{MY0uH#^M zYKC~u4Lo@G2&c}xjM=e1T)c7#_ikQdfe%bfj$`q`ef;h>zk>~m`Mu*LibD9l4+27L z%VrakQ|K?|aewgvPMtYLX2$w(`RZ-_?)Q($;-gg%Mo|l^$n_P8)3A^T#=9j1#07#R zyga1K?n07Gz`QV_;*a)X+xVLBQQk8CkhMcnACvK;tWN?+mN+boFhW=sI3*Yx(R)lp z?UG%WU3=dA!2yN~$I|2i=I$LB8phF~VF2}LH$n)8$EPtoKHc{0-28#o|3jq#?A?E) z^?iJL4&!`f-WcBd;KSC}QgId&^+qE&@aPa7f)^EpNK7(V8|F_m2V|?Zy z=J$*>8wBH$Z|GSHhq^%^#s`o|H6^^pLI((%*YI#a&!tW9X*2O0$6Ew8^go>SUbDI z4j(%~+CPHiC8cj16LC z{Q;}FFXQal*T~2~4&!sD+1o2+T)+DeBctOuIDHI`<>KoL7qPnLV|089@BK87FV0`a z==c=o=jNG3L-_tQsfIoq8_Z*D{3w3%lTBQ>asz`y!|bJlr-uX2tWZC!EiK{kjfs&0d47+Z(m&?N@1QCtE7&5>&7&4?j^iWFS`#vb84cs_G-3ZgVPU~sR?J~hL z48zts^YnKDnS9LR5GgG%`}X^vwyTaI7{8|-o}_+wt=A2>g+UxTd=x<#qE@ScQQEXA z*8AA_Zre6O=HadP-b6m{!1w+3Y&`@Z=nRgDXHa^o6krG`aPqY?DCS($s#QdcnM1On zp1<3K5ae>XHo-3K+Mv3=tAjvf&hM`4!hH%V`a+PcDTVd2-Ii@cKSR&{uqApI4Gy6G zTE=NP$FxmKZ{+alvBtQT`5FiZ0_#v67o7gbFb!uUGfZ>*MMP>$X%2`cp=!g+g zDh&aQA&jC<%+h9-BTC`s@??6pA7Ky@N~x%89Y64yL7IH&6-p@f5fViaC}XhH+F>O) zaMBd(vO>!H($q^do+TOEmbFaX@<a>gXcdIF6$_B3G+6H4IFW zIVWu%T0@2mr4w3W8*r+3(@^sA1_l0^;J%J$AjWNLGx2$zhg>elU;9B#d`|M=mo?g+ z*2E_*&vu-inD{iGO{zm@ER6{`-Pm-+AL!BqOeq!OAf~B9knXT`&C!8?NE5W7y7nxg zCDOJpYq=_4Nu5nBDP@+ZK3RW~vQ?za zfpKZFlAP;Bf5B#eQoZ$u#+iSFlr zH~f*3KjLZhAkN*bf^Z^SP)S^~*bW1e6gex~jJpM5OarHo^sMZ@UJ8MR3>kU>)LSVq z6;*49&Kjk&HtDQex@%O@VMWLU1jOhKIy9&m@yuS`81;d{$S( zLnH^ro;mqv&?05kmi<^XfQCOZ@&}hExvkB7CJ^I&ZOD)zLqB2?fju|Pw{c;z74Xow zFZNyJH^pyiNq$_3K4mfiwpmBKef)+R`(5her6GLtxN%ASX)8M(2*Qs^3am+`FrpL8 zBN;25IS`H;Uv7N9vhYWI&SKXLe>@}pknsyQ4}=%~fL)3Mm<0+#_B|;Pw$23UKC4l1ye=ow{EAWw2ebJ-O43Ime@NOK7p#cpd>HNp1@P&4FH9B?Lxy(4dnodY zGw)w-HxfRhh3*)OHXO^c;QKx*m5Lc)Lx!FaHQ&3qyG)w*w>^7}_?_O>K7hTh-;g0g z-7k8*^0!m1U0Dx{-L~mD-~g)1;eDW*re2{BU_7!iZvOQ=53cLV@Zf~g8Y`RsO?FL% z=O!IOjrNG3L6UIhM14)d^Gm{#OKKlKCP`!4lkk|4nc<2Mn}Z@jc9;(sFUL=w)M z?nXuwpWWiTA)(zWkYyy)MHB)@8l1N*>C1YF1E?$HrA_~4_#-2K@M#=V$TLd**p((= z+2)|L$?)HG!{T+zRsF65Eu(X9ns)aBN~If3tgaxOB+Q8fG2QW2-J4ZN5{-Xa_yrY^ za1wv3#vzLtHtArK^q%zsWZq~^lgCo`kkJc)wigGRUL6E_Io8j*j;!PNBJrT%kKWdi z_28;n4|c5&pzc8Hn8njhkSYS1zt3!hh71`>TI&UC3gfRyv;p8@HzXPnA`mdOa-=HE zP)wu+oUx5j+r$@#;D|pffI?B3_?Tkch-}<7wN^TPXOeq~1}_-? zc!BssLyqBLf|$_&B0b3PPS6mf1z^_E#_8OX6);-odlDdcmbQ1xOWlrd(m3k=uhSNt zGO~<=41iVVUPHar!erI9#1Eorz;Ao?KI#0f3-p^7_*e%-T<2ZO5^y8a=&R;ON9m9> z|4HdpMfY^WAF8ob&4Eg*oitZFi9fno3t9r;ZVUoZUEAK?#CCbB1E}`-5dozU3i%=i z1_nErHc1dt`2eawue107s%mJ1!H{o5&yB zA-NU25I3cYw0XQh75}aIzaTS5D`N-GA0kt5lmB-be`qK*I?T!OHO2&iaDuHx2nPB~ z80atkVC^ErLb<$^YV$KeASMXJ1cB^MO7bh#4G>X16W?&Qwl`6!Y@@$#0F((1!K7h5 zsb5pUbLc>K@Qeb>wo$H>QL9za5CFBuMIc<0m;fn--N*vID~qsJr5zQ_4@ois_kwr$ zGLujwWc(p=HA>*mw(%EfB30{DH-RBPcK%4x28!A%Oa+%V8L`fNDoB$wCS_f7v}j|_ zx{*X-2mlQfZUzt=gaE4D=+o#r(seef-!xnVFAcM{~#F} z8cE!Q6pJBAxTgAq=jO1zy`kEaRc;xieK=TRsxQfP;kZd4IEYLL7tAZs7(bn{Pkk`u z=RXU7H2!Zhiz+nRO8yX}EsW2vls}SQ@7=;5N$bO|^#PRii!lZY3Q8HGC;}lCU;)wA zBh(iE2P`~5SoX1b;~$aV`wMubX)p$WQdpLSD5{%{n`y3^>5?3$u568>2tg3QaU58d z1;*<2#8JPW3X$sm>G}Zb^j&8Y)zKOx!A?92en>iusCcngIDlDsGsy=~biZn@MB||| zc1gmA?k1ud>m<``*2CK_2ZH9WD}4a@`?yUcZdz-Z%$oPN&pD0FC1ZdELO>$Fg6iTQ zz*vaF^!u>A{`w)AQAX;-&#g2MYTbMY#JkKGW0qwRN-6IPsMK=COleC0H{L{;u;ww5 zpQI|_AZ{Av=Rss~(0La)lPO8d9}?|am;BMz2PP6MxiwZO1c{=F69UTG`p1v=PUDXh z>yg+8a5rlcgqu778c{@1h$sp{EDwwVwdE^t+%34JK{!Q<^5PfR`2GP(r~gkB`ulKy zVF8<)o7lg9KWy7Z7=|rDFPF=qTrR`5ZPaQtEG;czY-|je}zMD@YPpydmQDm8?a3i9)R z3b!x_Mk%pvyLAX|mTg%UY34j_UZ;)2bW`?V46U4~^>$dGG$L^)_auQS?gJUuNQs0k zPGiNgYF8v{5s`gY9b}UtW)p<{_;WFQZ~5V#6I}Rbh-A!InznHVRw3xPL<1JW zA_^ecN&J!0>`X*sV1hsd8&MdA2!jw2r68`2sJe|PtijENKXK+o;*RhT*l<&BrMBWK8VHyoTeOO0^S`aVB-UrsG)BI#})CCz~m-1@x|(9@l895B7|W8 zN-2o#F&c#k{Tj*VJRrIQCtrn4u44QC8uRx32T~{&*_}Ig$gNwq@X<#fp-?E`(W6J~ z#*G`8nVBJb_Uyrh3l~tWRxv+6kLBfMJbd^Ngb;Y1hkg6@!Sg(XVaNcGD2fuzb%Js2 zFn@|n#Hoqqn<`2)#5 zfc*TlMQj@rFt?~u#_HzVs4fVSrQgBz{|UBr1DngkSl>8_oHq@3{~6?_UPcsFQL7TT zu8SZDaQX6Oc%IkL<}p;ORaC20xUP$8wTi8+t-9pxI2aur#nRFeYPA}IAZQ4H_4+Nl zJAh+j0@f3hliHqiuQ373-=!p8>qWi0op>RaH-V|lT>>pahY47yscD#g!!QB`0iqg- zp8OG{@&zcpilDLq7DU)ua$rq;NSIRq0J6EciPhCrc%FwSig5AbMY6WGhH|-#k3aqx zv$M0fd-pEN-MQzQHgIj3=-f8>+eM~^1pREZ35oiFTC_)rc zPzu46t2hn3O3SPfMG-8^HX1;q z0W=!G9`HuiIqT;67a<4)0zWTa^CHs##y6Kn8BhKH7$ad6A&eL(1F-T5bGH5wj{QBU zthrcUJpdOYAd{~mKmQ(!SV)2(V1y77MG=;lmq7@@`uaNaJP#Wi8|3ok%Q$-UC@7^^ zT3Tx0p>APpYz#|FOW5At2Bj2X7&68{q9|kllL7roSv8Iu7sGht{Uw=7v#X<>5nwFJ zG)f)q=gR1Cf>X?AR~kUBkMVjtaQ8Tn;buD__#GmRGT$Ci5D2&wZXyexXdEJG7&14udWatOeEK0vO56KZlL@hX#>#)MFP^mds-Fgf5@H-CfMw{K%{aS{9X@5j*45DJ9?N~IF^ z?c3LJNDiY2wk19^=qfC91#F!|P0|=L3uA*@{wzDD=Tt1UCF8F!(ld#DeYG2&(GjvxpSMG$+f!AqavN+)ErPrdeb}DHu!?aFRAm)<$Cj-nk}V69kgD852>|pMYNo2X-5O zMx=3S1H`3KgeVF@89|K>km~wgRB#aXp1(%lR+apcGm96EFe{r&xzo}Px|I4G4$ux%TaN~O_mfJPCq zhz+E3pl|D+V*TMYFtWKKN$+<;*|M>Q&Trh@cWnahC4VSz^`z}e!gNepM`aQ1JDoo? z_Z%V;Om}4vhzgm!uKkMu#_B-!wg+N6Ac#OizpkPq4OLx?D5WheUXz-qRm&nR;V%s9 zWk)1xJ@>SXx?IU33K~&uAtQ@`mDQnL6Wu*=tka&-vYu?SnBr7|N!otOo=a<5OmfxG zap8C#r_eNWk%V}!TmEhi0)ZrhK*9#cB;T9Asq*$V56LVFeZm+89XQKa;Uruu52sK< zSls}NLcp>CLh1>78yn)#&=4jjCJ+Px3xWWnqob^WjY{5p^G$f32hZ~u0Fuk)7^Rdr zj>9OWP3*tcA=!o{6C#v;SrRi_2h@9 zTrOuO!;m3E+L{v{2$$Dn@L3yVDY>}KutTt{TP*597?e_w+z3b^2ZE5Wuu=z!CU(8F zy0=)%Z>(1HQLFi_`l6@?fDzYqQ7rZ~EF^wI5D;me>arxGlu=4$QJzGi9bzJ1S`LFw zC;-OIR4N)#1erJySsA%t28-7LnClp7hxFGvw+}vMkLlJreqJGzi%K> z!=V$XpsO<0H9g4cmYJ=R?w4tB)8=~AFb!yHs&zFuN&V}VC)2bcg^3}t?OC5s+t;)_ zXGr^m&qUWaSPx~=__z~357OHJY-T|ikoqBc3&562+rScjV^IVW1iny6iGMOMP)ZqN z6pn2(4UMMoUFY085;Z(rRtzL*d<10)|K~MQ@#hkvXL(Io8ck9ne+V?+BJ*wsf5ZbD z;u$PNJjVB5kRe8tl_XxaND~Of=Z@kJBu8>5@`oeZcvTyt?7k#Mm2CiVCR3S>Z1Ayy#7#Q)Y>OWeLBDE_K)$xgJR4&{K6y$Ag0ML z!fY#|J(M%q5}Bz~wjXO8zO--vMcFPS??)#7kno#O`^01B@xmJCBbcb{;5CYI4d71Y zj}(V<;T%|IOEF}~kf9wz9U4H1Mw19&I^x=sHV6Os_a^LB^RH1BNf3I8;5o!MTG4gE zCy8e^XtqnG`D(VCJhg$gX+wBTOyfF{WlvC;`x32Myf!SRj_YWzN&zDoUnw9kXWngn ziu%uK{W>&bjXrenhpfE~X^aTw12LYGN0KCHHaQKMb|#RWz#qEGtj0KW%#oAE4BIQP z!n7cdI?w88-&Bm#OWo->ch3Rrxyoh=1y|HL1R|4zDW5;H2l$^gZc!ejJ{~`0L!8 zHiEYs-p&fSl$PfVb$8g#DsT&M(X`6rH5Um!XHp+Hox`TA?4)OTZLX|ON!LVUt@7K_ zc`iPFvcIHpP~ESpS2iB9c{BX+{P`ox;g$bx=`8+PqUmJ9Oqxw1%f^ys6BBLLs!dlV zpvat;b=xcx{ABkg-JiDaI&+^j;=31ugRUT~60DO1Wt9WE?B1+GlBh(zV{|257cCsy z>JzhLCmq}Aj%~YR+qOFF*d5zu$F|+Ejjx{f-aEefQ5oZmoUyC+soHz4HRoLGtnhgO z`$4s%jCZT<$T{nN?nZ$VmM+V&zJf{s1qoK zKzn*Iv1iXfukI)ikghd{%X<6j5>H{1!APXt$HwEU!{aT?zLtb{B8CNJ^t3m)jk>}^ zhQPQ3>EN${79JZxUhd?`ILFS&-zQ&xl46Q^);-nd%b-FyxhgS(6AzGh zGV#cGUvsdpjV_Rm-{sa zfiXI*PC`Is;XH9xI(f_%TLEiGmN*Z%zGlc{L$8$dPhC6%=Lr&AvN?@N87G#Q=%yq; zYbUdFFJ(lGQ0hQ+P&FaogB!m6Yjx5JQq{K!3mEszrNjOTf#bL^zedVALC z!Q-2*Cy94Yuj6r_HtQ!AB=9?aP&L)GAAd0XAAzIy%qflr+Q}w`C=CZnje9$N;VvQP z{;Z%bVcx4AbQ-7J_xxp9kFiD$?>~}ps>)*v->R1|-}U5f359%jLLx4v)eNk%{lrso zf+m3^IZ2u>_8Zp_xiesZ@xX$L$$|9?GW2hpor}3^UaK+U@t-`2tg&$3d=b>IkR?E0 zQIfqSSH1o+N6u}Z4z5o&z1JZVEy7JPx{+m}-DfvbEs!vNlJ{6L9?=R>8idl1j93}x zjjQ3Pzr-;QWrhYOzs~nn?CaLcEJuHgHfO+eGfuP=+2ow~CLwCrb;vRryno!2eX&>T z+N>T<>WF#R}v!@dIahN z-pP+)Ccd)DP(fe!kLhcDSCgnTIWTb?;+{fyDI*2d5-~)lju;>r=CUzR2MCzGvt|EN zF)PB`Z9oNtBuBKctu9VR9R>;#S$z(cek}g5+UKsOf|wTJ1SF)gSalQk?(jsJw?DY~%b7*J z5G2(fNj$E;Ym?y?=_l!MOiSQJ*@-h_p=HRiKv@kGat(?Za3BEU>59tAJPmpXFzTXJ zT-Z7T@Z#R-(-1XgS^RbeeQ3_a;tKXOPs_&O&RIP(TtVIFe%ppFK^*#?2IB>tH-<5h zO11vOL$kHK2?d_nnb_g1vjXbC)3%83;OWfOJnkn17$)~7GbaBCg6C2gc(*B`5x)}R zsf3NOx7c=m_m5Yr2kZgQH(|%|zbRWPzT%%dgFr(d>ooxSyWi}?M-GyOhK3qwwqro9 z#piv=&bYh|f<*=LoG~*qij^_s=f#P|3{1>OGFAZ!4H3&t$Y9Is>tX^q@-C%Hns6#h zCU{z!E7ILxE$zh@(SQ9A&*<;4wpO9xnH!I*y830(Ihtt35_1~46L&OBJmG3s;St-o60t+yvEKq{qX#z=lZf;mPI5?Qu*`bCV zl%78#aC!-mAm`BkjfqB#guT)@hwO3H&`0t4zJY)*Q{+rVk%gxt=raf#{Cajm&+`;n^>XDEI8yFaXwdzzAJ^#R@VbD5rb;PQX6DySS5!z7q zw6K7qqoZqazb3nR_8ud!uAl%00iBW;VJ%o;3#0w_)u5mt8{z8wZ$b@S=pxwwY0BTD ze|kufO_?G0sJY_f5YZ|v8?gceA50(8oTnK{gQ)VZag6idIejPpm^?(*X+|Ewr4rE+ z{euI$;){!piKzvWGJs@%>k*t~gpv5`pWmZq?}1w;OX2&<+=Y1Oq&jQQ9L&p)Z%c8q0uLTA2t+Gfh}*RZlin zFvnB|YU|wl&2Bt7lMSf2Tm69ymh&<(W5}B5(B7&k?3c$oSLDoeZH5p^ai!>lYzymZ z2vo!S&F5q=H)~a>i3sLL&YomQc=`&hNnFrgReNHkMHKLmbI<&A1xsvMEsrh0=B)OemEVpt8tR^^ie<0K zZyRT4R?GBOEAWIi8ub4Rk~8QZLv$6-xKmyKVf0v5Fb_BXivJ zR`EXS$UNx?Hp~BHW|_K!+E1K+3WK~djVQ|0R%S<)K^Eh&5KnshfxDXZW(Xw&1X;K* z35h-Wb(RuI;HMmo2-l}JQ_Mqfc2z&$DAx+ZM>>YL`b)~KxT=%bSJaH|ou7RE&KeHB zj{nO06U6>nQL~Ds*a@#jyD7G2Sf_d~KF_p5Fi?&E!Td(L8>fp7H9O8=wdP7^mu;#U zo-bucNm)Y=F+@$Rn(0Ka1Pu}e!B`0B$$uM0Q-oQ%73x6?RScRjGG$#H3AE|0I{^tY z+*g_Qx)3mbM-Mh!`eOxL?zwwF&4m7sos-$N*ibI6V>UGf700VlD z8$$sfS-)Mjp#+iypSN7;zy@6QH~DK7K^XDc6T+s58)z~@Y{5bXoO0)~LqG=DXyzt! z1S=yjBWzU%py5{;lfxm~Hv(k9ycbya$_=cVT=`rI#E(1cGa?+OusGU9>o46Nn49X# z*c~`)NOKatL(n*6ptz^UCl?$$SSo+CU$er+J3A*7JX3#%MA^GS1(E!YZ^8;7Z+>H> zsd!f6$IsJGv3DOi5@qvg4ppwX*+1N?*LKwf4!%Zlz09&GAZRo};>{~mDQYx9N1;J2 z$W~O?8rz#-u_K`MO7uEytB=A_$B(tzJ28&p({VjM9~p!g{^ozhL#T?%RqG9*b5lH{ zGc;Q6Pu0(o#P;~jRrh6W4L$Px>-bbm5Nod5eZp9)hVKpB*v~Z}$ryavMvWDzq1O=w zh=UPCm0ukW=ixPQ#I;iWky_z?EzR*%oi6rwueS*kc20+%1iqb6n#;2_wYfYR3DkG^ zwHap($rOx9T6)xfIX_vr)f6iA;{NR1hhOl`Jsqi1mQ+&69)ih!@tH$L`QCo$JZ2}o zcNg6NxRqUT{mu|bEY>DS>Fu^(2JM&|-C$1TiMDU<#Z{V99nLQ>^aSo%!@DEA;+DYi z@^$jKd``gn5C#ulc!&f&z?49}wL!{H7pIpsgbE!mhwaOPnmt8pOEoPWAx5>KPFuSD zQ@)NcQO(ucg73qh!EAP&aZCCcqWYg;IE?zeAvX{g{0L}Du%92*pGeML@HubSe8oo( zq^o+pkDOnw7c-gmK7ziTW#Nl9>I@w=#jOVMK24quuVCJmJ_~=JIEq7rRe?q3LqrE z2G)Qx801|2TNVL?e6z}zu~ttF6*UUV&6~LiezxVQ}B)%ZVgiCK3dyN-N7?w zqBtVx7KdvDJ)cu7wJ%lMNmQIQ9hQd0OalvJ%`7Lf22M86ckT5Kd!h>=L7XpN?9cYc;2;go|6%}Y zPKWciOZ%%|k2R0S(iMUo0k4Qr?zi*cV8ZIgM(q9)kQVIzygwjEGB0)ysY0&4L(%NQ z+3iLyNI%KaxuPm|(0Q+1$COP->tTMz+n(zdk@4LZh_*sw9Q~y<1v|t6hL4zfjs(3`ioQ1O3REbaVvmfYbBz36fa@&x8 zqdO!9&)(#cC_3h{x7=KR_-zvx>F(axaf%?8h&wo6b#P+Mt@fX?h8n+AkOV0RL|JUc z%+C)njmTyPEL?n{MP5raU5Z0bParjQwVelKqt6c?5Z-bB>^uI`QQRlAo+VZo%0<|b zC+PSTR%mmfX2&CSq#~-hSExZ>b#c6*>cC;GCp8|bBrBg2lol(brkj8|kBb9OY%s@r>n9mOwE1s3BL!V$DdYbT=U3Z- z`8}%>_Y(c?t$oL|mk!5|%1q<+#sb#qQjP?R(h>9b8vOU`n-h|}%-;NU z=T(pbcPOh(hE=u*Pls#JOCOu_l#`d185_b++@6Uh=1^`8n&G;Zs57MMwyAvDQ-}Ui@HTqARH^9oT4< zc5sgap%{9(Xq6c0=mH)fLa{F2tR}hYHR!!PndurJ1DNF+0#xoL@R{S5>&UN5Rhiylgq4eQy()t_>Zm{wDY0>0blym{%cN=v!dk+Hk{d zm2%T0f!h!173tY7%s(7vHr-Z`)7a7G=H`FjUmw$H7gCM-EpM+yc;Cd8{xEG;OGDq1 z-VN?Hu!%k9GFj5iuv`nrpCGcNCA1LZ2vic33D(uWUl&$gP zn~B@7{5M6=h9#>OF3_zN7$3JX(8GA{Uda$pSi(X(T#PV3i26vNY^0pCQ^WR_;rjpM z>!Wj*mr$8k`>uaFvKF9Ie;vV&6oRB28uQ3yw~`L8I_h=e2g4FZ3)H~r_#M`R3TBk2 zf+sd#I_9XeOj6@01hDSOK-3sG3nwh|TH-YN!crXgV-}`-)Sako+vMOQO}Y2$b-Xn6 zqftp9CjX>eQ=+dM*n8mZ^=>x#_SMv`?+;JbY6W~*l~wEjHC2S$Jal)8n`?|1c_2B4 zP{`TqC?WP?VtJ_7cd6Uo1NvC@d8_?t50(ju87h401%e6Be{hJ%M>7O9FznAi^2(0g zi}Zj*dvwi_7=+CGK(vO>|AGhJpFrZ3YF;loXwLI{!=oHv(*SzgeMCCP&#`5+$-thx z49}gbE-k}Gw@h?ioh}BCv`jO}h~QvAG0N@A=tKSif*i8^1#*+U(#YhHakkTbg<8^# zH>zi z2P=a(fhHE7oku3u#bOK${d03UUaId<4hr8gvn-~(fZ-IX`7dCA`a6`HP8t}eguO7c z=r-6%h)dAon}p>wfJobsi4#E5E`gd%@qhMbJj|L&mvoYhA+eN(h{9g5A4<=Zjj|opOqP=nx}CL1wfFhH5417J4^OTxnt7PPTI<2As&MjdFn;zH2N3Eg3H=kG*Uw}2oIs5s$^?A8$%cFX(c2i6sbMIkZar8BEK6LI(mbIUGTN> zRrgxMLj+JNu62_A|?(qhHS3V8(KJRHaLjla(&}^n3M~UK&OXDZeF}Lq3IbJ zK|}CBOKqP;b0WoI@xFZTrgPl^+<7?8;%@d zxK@}R-v9}#6tOIJBe0Ehd^m}U&ff7Igo_JSQ1NxW82&Ht0|J3_DAGF^#I_tNghMCa zpG>-^!!h~mLWG*|os-6&)Ge>}&+V5A1X;c7cU-nQt#BuIhMv|?wpIQ{GlMUq2p1cE z;Us_Zy8R$H?ynCfc&U+5dPr5@9`u=ZV%#?S{8a~At0(s=1wS7_Lby3^51j6GO%b!l za1as>CZFK+o84hC6AXN<@7#SS#(W+vv6Yp`Tp<_;zhIy4)|T&Qt#M%4GghN!7={DhHm0Aap^fBaJitookBAG-yQike=* zw_5+$e~QPG+H=5j$WE`q4?e*H#doy@|)9W&+o3C}ky z5ujr4WC(4p=L4Pj1F^-&4_Z>+6Mp6aQ>XJD?iH0V7}I)haicv~4gJ-u`1X4g2HytE{hpwbl7dLoP!1Memqp-v z_jo}>m;KL~_*_kHptVy0TRpv?rPSe|wN&5+BF}Gl)QC2R7GB4wQ=4bhPloqSQSDzh zY2|Ww0)A8-Pc7M7jtLDAdIIz1Vg4jdqT; zyju`D)o&S_ZSgItjUChB*k9B;jU=EoS|M*u!(IAafsbb5Yv_0f4v+n;**5gLC#~Yw zg06)Z_;_m8X!S#Gz1HMf^kw@V9j&L}AAg&3RSAP^E-$~!%OlvIe(MHQA|ndFE7-Nd*{S}u5bI_rcbq&oOtF8Kum`4&8QSLtH~unR?{a~C zwB6|0J5WW6mg}pfX4LI~S{v(a0zp`j|EbtJwPPfK0*VKOMARx)RMYQGc1nV_>R}t& zpufY*{T7JfFMwRuS?k-s10;x1H4Fw;j!Q}SZ zd&@e$!S@TQ`>>(Repk$TJdR-DB1qBEI|F6Ppp!AuNHXTp?SmUo=5LW+C!u}>A_j(n zW&J?HU)Lt4*agb4#2>cmQ4U{5q>Zn1t*Qt-~W{!5S7+;2iNWhy!n0Z8S8X-V-9waEfQ^sBQrk8 z$QB%9=ybXw%5{Z*5cJLhh_oU!JYV6@FC|NN6|LB(Z-lZx@VXSQeev{U$~#B%-@S0o zrx&hHduWSh7Vq;n{_xB-{ct1jT+}}P zrxwxICk_pRad=*{b2vXFl$j*%4e*)MXz{@IA@`~=w?=cb)sZlChM|)CEz)%Z5;ny8 z&xlz2LH6?fYckAt>V1*lpBES@i$1@7_UI*sA9Je}2Bw7st*0b}_|7tkf_{dzIQgLq zjP30IOIl_Vh(^@+j=cTCNWP@r7a$r|bL|c;uf}n8f^TQkklcUh3hg6`31T>?t!;u~ zN*%tN$Fji6#nIxrAH{cnJVU3iwlOp@fm@hR6>BB^&EtTDFQ1}V1up3E$UyKrr^of{ zzUPw?FilMEqU?>cX0zFQxn=MS^C>{so7b^Lj-j`8U zYEuvafe>hB9*^>u8AA+5HGcNLP~!TBN6nu{vni>nd#e*%E^|kEjdaL@4_c7vW*?s) zm!BV>9NKBX+Ru9Fg@}mgjh7HR82adOa!B!~?=bOsmV%$Iy;^qGg+L>Cd#8_ZzBFd# z*{3F-mWWY6Xlt5lk%(z`vkxLR+Y>v;BeGiH6VGSQ%VGBke7>pKu${WW}!ga3#_WN2UkdJiE0)uJu_0W&OJ^j3L?!`$1mhZAj7gCvKNBbN%*LZQt( zEu9wu8kYx+F5)dV|4IA(Td1-wjuZlH@xcuyroKc7^wCaZn##b z)t7P3b;XCuj#yuI8UoAFwZs?x*!}+flc=OE1o@@0g|EE zP8$jcl3)qk0!k2W=fIJ~pj7P-NmG!BKp4ptJ_HD|_KXJ$rPe?js!HsgGDa&opxS^_>nqhm*)r{GBlV`M=T>|H$Sh2WS*R zmU1(WG+5HZf#Vs^sHs6-wXXDpR+N8TE~~2rfltHvOMtOM{HKHV<#Ke@4$JJ*a8hih zZ||z%0E@O+gE4LZ?^(~D2txChAhl9lrbP^#m-B8bp|sWOsBrFc(1o+sYlfP-omzD* z`6quMuTs5rLLU{MQuB=EuBB5_@xQh4Kb6XtD0()i{{yc9bOwz1e^DAPYeP`Pdbi&e z*biJ!(o${xu8mEBxsna>A=qi)A2+6}zyfV`qu#fWMhp@iXXj~NWnqJxR#McwD0=!W z!Ti^9%+qrY)~X?l4u{nh+G^}7Kfi&w)k6q3H_P)kbwUIl4(oF?w_WP4J_--oor8ZD z`&(jTOqJ;-O)I^@K`~JT9yr;=@gM4sk93tqlj6%*bkNy%BKo?7>#zJ}EZ+WKfD&2vBHBVTIr}{U|Cijkcc^F!RXD4f4$u?3#>P=v%IY zo>cirYI~32i^D85e%8vO=9+5skvcp07ru@e+3fD`?o|*i>cQW&+VX`jKQwXIfDiiRLrMu zJ#{-CL?T;uJ8LX>y^lU((Y-GG?y<;%K$3&>h#M}j1mD2PxB(wuhyNsv6i$Sz3Kk+# zYr+mLpX1F6_Y0$6T%!#!fE#-)Xu|FnT!0GXr1~S|2#~-dyL2zqv;FE@5W|?yEQG}Z zXbdGppM=9db2>R+V<`UKz6qH54ifen#0#?qa;BS`>guZM`drHWtN|UTEz}}PwXY6B zKtS;y3#a)Bd44$*jt2vWxXVplu#)u03DUe{(cN%SUrcaQ)9bjT3ykJ{W9Jv60BAvJ znDiC41>FyiQX`4r%+K}l^|MpK=B+7$VIbq6l#WDAJax-bDaEOu8)cXQR|H7;Hkf(g zO9^3RITJ>UwCwW#!4&5e;8V6yTF(ER|Eangfi02Ltj>3J*PCO%()m(iL(Yy|D3+>4<(IDn2cCV34pwZq{i;_Yz<_!1 zx*Qv1n+9qdXtEJxL1y4d4T6o@@C#)F}~;+5_#lB0Ue7lRh4lpq{drNBVf>gr>r zCrbhRJ{$8Qhn!XDLUYdSvb#JSRj2uGw^A@&VUI0>F3NDwK(PxhC^(t=IY!}JA?TK> zrN8H;KhD$;r(C8d;EGpjSDFZA=K5;2m(MwBP4MQJc~GTX+mmo;FvOD}hHH7t5(`83 z8Z5tM7S8%mV8DBC^*0eBu?2c*s3G(-U+IPkxe&3cY%8xY8EYxdrr+fui%3<3M_js$ zKA-e5Pyok%2=7oA-A}L}lAcJ7WH*kMmzm*tn^X(h;irA1^l2|iwcPy;Q!?V!8-Z3(HO+%v!j)gM^7Z^e%5GcrCs*ducBlg^rUERXJ?zL2j z&IOc3ka=aEy0easOp{=QV9#jkc1-DizPi=Q1numCTD=nr^QfayYP-6`*%u@kGtHb_ z;MFy-hAFSC)+%f+W>WDfQ=8KCHOLZ2S$MxqUL5iecR%v7hBz>G-O;lAtLbQnPCqW- z`fcoF6XTl8!lIVj&?z@Jhl`J2ps98E@xG?AO4Ic?bc$qBP{F`}cI@EYJn?eFSKaXe z1N&;qXUM{>XW(O+5L7(eyNHLpR?PJ+swgwOr&!TWF)dBRU3PJiB^xPJ10&}~@Zx2Scu%kE*CVV!kv>V4eujM&K&4ir+Pv8nB9{NX1cPlf|2 zC?plJQK9_PtEG~14ABW|O26;QhMi70k9pv56vGy68`eORMFN35yvNMVJWi z{my#>s|+GMsS5oHd9mIhXL~~cubYdjNJ)ioc6ol2>9%R=Y@Ixo%2?CXCH}dMHm0vv z68m>~86;OA+{N{s6-W5Hw546@L?d=&LBUxHibBTV^NIs)5x?*4WIL9Gq{m)ks-~Xa z*Yt^k9rPHfBg?QLbhJZ$jvJ$PT(W@ zADvx7Q;&nz^60+2?~8FLY`yo@B-4r&0%Nncic8YO25r0c4~kdV_&ySRwpQPBa3UKF zpLYxQ<67{hFP9FF7laRMl%Iow?^CVb4mdmC%D&NB{1yHv5cG%%k<`B_-|`-i*Uv0u z!ryyYc(ku1NOy+mZj@xJu}EpY;>#I4FvTd7l_|4W`DX2x;LP!3+pD6IzNSsT0B8p( z6XWO}|OX`;5>yOR4XD1D>fmnDg;B?utKC(ydF3ve<)=Yguo9>m&0M ze@ZHmkbtyYRimZkI;z`;xZE!7$CpX+bI8DD5;{)XfSsBSZBk=AF*2B@y*kA|)5}2B zOd|#cdyhXoFJ?)tX7G|x+kfE5eH3ws__r4)+8YRxz7G}%64vNHT5vv4UvdI^{Tl7p z`3-8!XRe=grcF(1BvvzArHS~oH7zY-K5hYPx9uIzi(>7DKousItfDZ~_L ziD65ErVeg7u47+u;}SL*S$?N@`|c6V*0eYq25NI&vc(e*xah3H{_JqO|G}uAValAj z3%Hjkl!Ex$Rt|gDA@O{Jb2@wyT8l7_7`wmI{@Pz0z6?^KzvR)Omx$P>(#X~)yIL%j z2(!3Ql^%kg4QETUZ}ENSC<>xYs$_NH99=f}Ju4R!_Gp{;h?*Etq|xb?1i2*Y30@{c ztiRbAWp@eGR4zPB=&Rsb#p-!VT~dyRa_j}^04w{-bUQlKKSJUgDlC| z;U0aV$;8k!C0yUo*B4%Q4)oXjdB0O16aRNn9gk!&b1*U2xbA0Q->;mjdg88Lp&_Hr zbA^?)o?86%mi8Wd!?f88qCcHeZ+!@(Hs}ox&j)q_1}~$T<@16$ph-~=khm`)qefwUQsf#vC3Ml!|z4k)Kb-#H#80=HzX<8e3qNSiX~|dVV|~_ z{GxDV=W=2dxR*sO%*?-LLFBpU@k)|WPMBq86@}3=($ApeYBJn@ge`@e!blB~SFC%- zokvbd)e04KOn4FNnin!hs&5!s`UEwdCQKftrSS}Jt|Qy7KPQGV)ts6NbaTrWGl|!0 z9(+D8`HANaQtz`>tiJ~Ts*}&-lJ=vGH0NB=@f~m_ln8}g7A!SVch&rz)4w>26;{{r z+KyVb3Z7(K01BA0FhrY(%zKsPlR?-k;A?RT!fz&K<@gq*yiugMvhz^+N>6Xc%ElXY z$lWk@N?&DdP#h)m1-8}q9j8xbnmFVq@q6N6-PHUt$hV;HoHvfzuJUU8gM9QCOxYQ8 z+bm7={?kOYZ}0jp4`vc(!-M)tRTBvBuW0?K@Ze!zh?5w7(8Ppn;tFXYD-F_7n%C1; zb-~V9+?aX+x2S^&8>LphejgU!$1%5+RemAroOa^R$f6CHp#B1>=Amledm=SHQAX3c z##$-uAIxg>v&3^6`oH(oFMY<%bNnWQim(G+LsHI_L4>9z&Vh7HIihW{YN;HS>Kqyy zHq3eiqD?>7JNP9njUz$^RkftU(u|x%cyNsk=zU=6bc93G>X3 zxw%8m-^kb}%SxMh-MmiS5(5h5_V!0|IfKy*wdW{-_>(rke z536*g@2VG5m5Im1l(z7A3mEEx?s2eDYwQ`wu1#v_GZe}Nkn1g;G1~f!tlVr7x+{Y& z1ck+dj~dte%Pu%O&Wpi^R4a31Zo^+~QQ_g?J@gv7pQ5^-h`SNL{DC006q|{Gi@AYu za*DGL7XQQ4-+RH6O=RkAmEv7RtUH&+?Uo=zIk+t(m|{4cGnO!MV4s1_!Qqx*miX6* z*y|Pc?qHaD|JIs`VcQZtF`YnJxga_gsiwVAxbZ-l8YzCV5En1YtU|-U)-YRxJ&+W; z*>2s;(h{0~Q{LACZev9fM0x6^`tkxR{Z;9AP8JDzRDz6{y?5N8noU~ zSc~HU0*kV_lS@Pj9Y9e_@hvugFMNSXBf$TP8FXJs8`1}7JjnMifb0vS&VZZM*~LY? z6e=4xcc`f)J01YKByjNwzoN6@(nja`_bpSTGLCPv(~ zOr)9{^eoAjCFfjcYT8K1*fe(~_U|~iDmxA*gY>;?l$_6VQI*x9l;mq=NvM9-Y|WZ)ZmDSh)j;UnKKy_!Jz?bh?Pesul^((hZlOc=Hcp5 z4x7t?*Y6zuF#WZinLgH)JQmi!Z~?? zfTOzBE}(2yJ{Nb)MYD#cu4G*CNRd(U81ED7%MZKWef8T5_isy?l#Hh8)b}sg?I!`k|fjDk1czw-bFx9$05+9eP!P3{k_QZ-AJ?;3vz`k%r1mWEJ;T*>`Hk_X5r8$HW!)6c}N zv=pN{CsZGPqRg?)QCCmAEHZYT8i-+Fg~61nk5yD$vT*Z@Z_fi;3rW_$5+>Watx{!v zAT&1;LrPLBlCd^Pwq}i8D)l#WejHHKD3&($i~DuYUu-soxnO;Gm^y-l6M@Hb?H+8_ zDObKikvX>O{s(i~q`B4aNZI#!(?!qYJQrIu_Rk?X(k5(NIV ze;QJf(~v{(mW>l(&a&9d_IJAlv(pQK%wfkb#o{ zwd9~EVx&n4C1A_xdCN?z$r-;vZBT{_3PqtkF3ts~!}xl|uT!F2rId9_dWBlxU$oCm ztCDNa|3#K<+68&a1zlcdGw$|EIxp`OW68xqw;EH^MiVM~4Zd&&8A-Rl)&{NaR(n|d zgeN2UsY?>A)b4Jqe~$nb8wx7!H7PmlpE(-F%sK3Ln!)*O2nzlJLn=F4mi@8;J*8}$)VW|UnA!N zSHfZOIT!l5f!ejF?*_*_XwFL5&a(KMi_nCV` z#d<@PNt4%ikf)0I_y6jm292n}M1l1Ubz7RKXL$G0KL2D^nrim1y6fz;PX_o$p=0pz zzQBj42jL7U^m44%{ca1fv6PA;SHZQO{w|I~=6XmCXGRj9CI(DLctcy^y1 zdv*U{4v9d0SnvJP+qeX!0Qzp*3<03TNurzj{ zZr5M-Cmk@XWqN3==warianl*@y?qzG_MGKH^Zefw%1yb^qTkK&`h{0C7VZ#wN{~a_!J-i@o7rFAh43WZ#%Z4;bE%-!k_t5%zOM`+QUSYD+x7Uk)SlDLTV$aw%w-a?vo@y8IxL`yKEo-+k(rl2c7t#GFbi6%k%6)E4KEW&m)M337$m6h^(zQO9eL=2 zGxFFJb|w0n$I$X$>$^-dCHiNJz-6kM{9dos@Q69AmrdeC-F2Ffc<>!`@whBnul| zr^7yb%}s4Oh65RU=VlxP1I}r?Ns&&t^J@1QzLHLMu)#0zx(}&_ClJ(%tJI4kDyq5Z zWgZiH?)ZF9d^77T*lee_*BM82b#nTp2C28d{Sh~VFHCpM*vku*A#tBd&^M{wji`>r zEsXf{j^ShD-UDgQP{eBA|osIshBB26QH&8 z54(>rsp|2GcKuyEZr_i&vA4se%j=!)&*qMMs!wpc&!>`OU&N)VtA8aqGgce`21^ip zgsBamT<^^6xNR@T8XgWWdDZB03+hU+3|5+_(}rW~KS0Dxc5T+w)XDR^BS5v)*?W11 zm64HmGBk?kbt59v`hoQ2M(6#CGG>*Joar+@xGr3bfMe8#F^f*AlH=*-gGccFS)NOf zEy7L^XL9#()lXj`FRZ$@f1ZjIIP$=dp4&vB6f~|uWhRLyn>b!x+Us4C`wA8;Jb08o|+%08BqAfxxbCQ7eOjkq_pR7YLjTroE*4nKu1WYc7f zqoPiAdDF^Vcx`?tAzfK_Rna!*aX?{ zoA38b%MEN4I$`e{$S1Kz^yJTPC*Ls8g?Weynz|vWt=ICJxDjPt?U!C5WJZJ$W+qZYlpp^+Vk^#*UQXF@6zn>oLwzb^Uf%2SMKhg zl)SEyDk|n~##uMV6wfM|VUL$}jc)!N>c!JkAOd{z+um;~HqoI{Z1HR?-;ldEj^PIT zJoJ2?5iZ|$3Dv%&K6&WJMx`>=cYDWGzVm$1^9kBf3641@OoT`LO$($cRo=P!gWl<@ zs~m5Kj?&6aopJYeods-Yy&xga+DpwX;zp`}(ouhN7zZp#3xfj=JgxpOhOIZLCSP(RHJ&|I6QIMGVy|Oj%X+!;9%vG;z%tycttu-4X4@#JwsG? zec&Yx5`3P1zIC(Rk9yRZVNrD4-5`n;ECRB7RM*#S(!dn}JKvNR;Usd75X> zFrEXg4vz}`sf#FrU|kXLo-p&ZOz0?^%L^Jb>!@K-ch5?NlmFcl)4L$tWE>udMYR zlEZa=*Tto>1)IA5Ju&5XmB$B~U#>NYK?5?FqRk*`IU_Oh5nC`R*BYTJrXRF36lA*= z8NE`5aHL-u)(W_IL<(q@E%DOYJux+o0bmXIN$YV+hivRndt zP?}U+nx$dNZD^LPU!cT`GREbp(%##8U-%pop4fX8e3hKmIP8?~HZi(^_}mwKmu%4D zfD0)8m)15WN!&5z)$Nn>!|wg}7@Kk-Y@$hB5EM{Do93D?L<~J@xRmH@4?14TJVG1j zOCwRaNty7S1ghZ=_MHVp9*-A;WWJ(nvupTQBa6CvWPSfoOAz~?*Y%fOpUrNLsk2tP zx24a6oH;8F%jT2Zbn2q%;A1hhD7oAaM(9v%F-&7vyHy!npO?J9S)7!LZhQ4~f*@Q4kAvgpAx+p4nn-#G)bx`d@z5+cwj)<=e^pOamPz;J^1Z7~%?5 z4@_XjTC4!w8GxuQ2wE{b3tEt*-;l=0>#`1Lyun45~Mgq z)Lmk~$pix#ja)SMsxV7UDe%~hzI&`tOQUoND${UaITYs`hWme70DwJHyY#AxJMtR9 zaNrvjrkU9Y`FdQK2=5I{sa`I#Gv?ep3lcD@3gV#n@|2}=^^&~~aT)%A zF$7dt1a$GFGGZ1mt(!}4S*G|MGdMS43JI4__&TW~7W5%g&SiT`3qkG#S3_*4OUSh-h z)6cz*Z>-M0nk<0VGC*%#ucng-|G)7_N~3z{KPee+$oQ*gPoQBBVMTP_F)r#ef)oKWw?T z?+ni^IP+WV@m{YYkzD9?*gb2J-f4O9THNZq&~Vi8dYC<=ss#5=x#B7NykiB=xog*Z znUr>UYUq?F0!9}oe=AtDAyn1xtmx$blS8mHG}TtTcXr&UPoSz^^6#{yHCFFMnd#n3 zr<=dZj{me}@9f-?@QmhS!@SWj4T~2Dxy8}CAW*nhf(kqz<^H#k0TcQ zHuq_ntuu9#?3L(Ka_!9*mo@AWu9tky)J7C{YlJ{LJu?#=kXuhxT@Ar^;5wT^a7d-% z9EjJ|HC)c)3iPDw^ImPADVMwilw75Iyz19yZSL70_Oq8$yXc=jTYe>-=Gntt^{X2{ z-UTk-o&G1z0Kp-+yL)g89y|mI?hNj(!QEXGJh;0A4GeZ`PFKvUlTe^PT{NrW?)nW3R;{WbL7`v;U1wqCl$6vBj;&)?H zuAN7&J0?$x!M^P^vwz%)mwg0{INU3~eR95CbcVc`0rJ*9EPpALH8;2jb8)5wAXJj1J6B0+eIJwd`C2tQ$!{)y>@mU=K?0mM4^{nYQDPg zcf}KO)ggWh-7B`e-Vc8ofj$uDz$?>bP;E8jP^j`*u6e+Dzep;*QxE`G!cIrBr&^e)DoBrkL_KL*O8WT002 z*%>}hiQb#hm?EPRB*c8?MEWkYk5j1_0eqd<5sx6UE~j|R`8iGlwO8*&{hGW6*6+r7 zlUPE9k3Rx9E3a6A#4&$Suvl`SnrFQyBX-e=oY>F|;IEkG-6R4o zIeiY&SGrhU59pg*K&pK?LmvFjgb*DS<$MP3F^>Fa{%tn7W{wa?FK=8)NFq{ar?2@V zPEh!%K+`fmb^g!6VO}Lt2n}`|Wy#jUvxOam&XjmiL-1me@b+YFP|;kWY?e^N^eUYhQK>zaWArLnr_2 z&^muSJwgR`@xKSPFVT?(=dEhi1f5PBJESmgD;F&N%;V zBxrKJ}H`2-iY;9vkxzl2oT7h7isA5tSm@--t``#+jyW=|9APpISTR%ctwzgN2k z>Sz9PF~(^0dG<$QVBktFdb-UJU2d z*7tPDR!&=5>=OIZ5X`qoU6MY80|Jg!nI(siBs51Zexa}0t2>Q{w^2GsKMbru{u$=X z!!sAC0*?aRUk$30C*QhEIo+M-Xv0Wh|2y|_E^aws21J6^n>HDR3$B;N7esh<2Lv8OabrExiXNeXkjz=idWF(3vCuXIK!HEkcmwLDj#|*M^0&t~^`6|t@AZFWpWYE{(g`g$`jD`1=Wq<9z);=w zB~y3zw4d^E9q%@0%+rV3k$DNXO3o!;CVF2;CMV*#xdj#C@EhPk{O=dk^ac5A^)it; zf5Q{*!J@x;b1#e=1nj7I{O{}Yd_fvtw-L(I6HXzaDT&yMI;c0UskK<Fh(T==P&DKC1%2R3R$;?#%tn&~E~`OmxYrvf}H=A6IN#lpRu$imuc4BU`8 z9QBOo+on8QhG^Y?(3loEmQZtCe!3qDjH*xBxy&gr)1}uyS(*@njh1a3UC_#MGZO!l zg7^dZvwlgE!iZYW*S-(1!B`uQv?*LRar|Sh({Is=<1dy9_wNFNm=KRW(2(DbPfeHf zq2YDVpZjGzYY>5CiGJOvS7;_maZVMOy8EMXB<{HQ2T6QalS-DSjT%t`x}tw`)Fcv- zTGVk2-#l=87$+-~aVqCY1gpVHDe8BQ{*=UL$)~p@LeLnn*Q#jM4@X0^@g>n*77LSt z-Sxeb3{pc~uFuNP-<1=8pz1lrMfllDje6%zZIN(U7@^)*)_GDU8q)103(%eA2msxg zuL^T>5cPNHgL5)+9i$9m=T^}%4CnP7AWx8&Lcw1e=H(P=M7mW`o0}!qxlaVuH5m55;d7H_8IS7VxM@-VM;9!~Ls! zlkb3%r}OE*9i-HD`uvaZ!z%A}ALaM92x@o!WjQ$i=@o=)S>VP7AU)L-oyX!9QTtwj zACoG8_Vlpy-Eu<5TH{qjWA0;>|D|`l=(uQLc2B^PZ*4};{r97TW^%)w>u0eg@qaZP zS}9E9U#;O&@Pvk+# z`#r)R*U?3TtQspJK3++X+ehoye>rvv3J_j=Zfq!)HI5sTS`dXB4*OxY1d~%2Ol=P1 z{V1tdL`o_aN=e6?q@nu9=@$co*+#F@w+5XBPcPo|>nh<=|31opk7ELi-@>5ZjP(3r z%DL|Q&w&f)WeVNXl^LgPsnp%{Ujwv?H)76UL_hu0>JX|RA7SIx&F^m{ zg{VQDgOMZO8B45N^-#W<=+bA`Y&R_f=DvuFzO1t| z;&1zL{=ArI49_?0dbh;nKD4ROevj1?2MVKFmaswIw+LeK$Ng`hfx<7Z*i<~t3Con^s9I4|wYE^RjUfQ@e+RBfLs0Y9Y zalo2=Bd7rr4l)+diVS!++o#iE+`4zMXp_>@7R-dVJP!kQ=PceDe!`&fcQz!dKP#CW z+@bYo93DFm@+kUgTrUr}-FiF79mxZON=h2EzcHaVNpOk^qDmEhg&A>I5AFvnNWlAc z1$*~-d9u7@!3TD&dtMRLV-Br#WSBq|%=DlwKcaLWp(o<>QC?XNLKnYH#TRvU$jWBF zA;=!pBr}_!L3qSKl-8Et&*=u}P%o)$knCz|XK#vP z&WiOxW%zbw*sk5^ePx@pk19OpqCf_-8|ACs()-uP@4>T_o$0+k`Ek>ow)nvZA@>u< z#n>GjeWGzE-+(;u-T^Jknttr>o zqs0P+UvSoFUEAW$O*Khz3KuCwcsO#DEGxgZw){2bw1aQ#&Lglq=74F{vUrfs=x=GW zjC5p}GCQ2Yrv0+h?g1t*gOHT4ubQH8WR@0}>&rDf#sT@Z8Dj397^XvD|3Q4PZ=LeG zb#BCAbcWT)-A~Nkg!P)nj(TP8yl=hY1O3OC-U7YKftz$cb}jfnDqC8Woo9dEgA)9D zi)kXfAxIA8C@A9~GIM`nPe^YCW6MCzw`rPe+9+(T< zPOwL;wk7dPdY8Q9eT{#-Q%AOVNu~>SU_}m70&B1DjxO*K$eGo=j)erfC)Bt@PJIQc z`SVE%ZHbxB?w@8Wy>N9CiGf;+4Ja;chMxwMlIN0=!BH?0XNt^~4h8`vnq6#JG4 zRqmCP_bYRa!(L{PJy&N8mE-IIW>!w$|l>@ zfGmY(K}+BGy*hR8=mJOEaYorbq3%-r*t|>mX9edD8$T)<%2oQGuj87>(Mg3G;$crLCSlKM zg16TH^zrZUTL*t{3M$%WpB$}aI;UmcgSW{vfK9m6h`Epit2*u4E^(f=R~ zHJ_YD4ON+kvk3cpc+}vB_e#ZA*bQ-|M1xz{-?i|RaWk{OuQdUgne2Fr0{tw4#~YUX zow0F5Bx-UrJw0jnkhF%6>ic+)W`C+Z+R|D6U5m7MK~(Evu+}!o^T+-#t-b9EOQ_cK zht|VFr4|>J90Y>e@@Bq5x8y65D8VI6H@CJ;VOx`VzWSZ@eby$SkhR3F-Yb;lOHLla zAIIFwyYL6i{Eze8%6jUhV=Aiy1A|xDthLon+b5*$-w1vh1CUZ#D9zm79nHU0VN^{M zW692bt*oN2K|@+PM)S9Epks`U_q#H02_qpDJwjH|j`6V-k;Ny3{c_{iX$;w_A**?W zv@dyHf$3w0Y2AvrX0CY=o(>`D#?}JhnG5EeUH*5Is@tsuI=M!sCIOK?<8;LJZP$x( zUNvz>%OfYrqx06?V0|AN#byW1(zFW~$xF`uG3JBViTU4r0 z2cB0?0`xvJ{f*)#vKU-c=^OnKc&e$lWZ-K+6G4Tj()l)MPMLQRG6_7AxSK^*`}vpF%$PNTLuQx zpyRebEy`F3CJbo6rTOL!B7jxU#8EhTN2SH)l~LHd9=8~SH3STU@Zd%+t$FoA9U>c1 z2B50!|NaHw0SJM2>}qf&*1~I>R?Vfe&nK06Y&+O*Y*ib1H$YTwb1bdfILP9v<~s_t zCIxgWK1_#g;Qt{RVF@p)@q<;P37HD8j6wxR|NHG1wImaK;DG(lZDxZV)W;s zZb6>K>G<}|o(NN7VTMGA)!VL-<3n#vvRq!Of}JRDt!L50Q^Q+Q(TY6sf?fzr?Dpie z?W^F#j+X{e_tB`|+`8)WYtLAGOd?crSet@x$!+MgaQyYZ~O0))wpu z`RuE9&z(9y-|)iS()y})Ajfx}q&!^fUSI=Ua40DY%!eLd5yATXj`-BP&{0V&5iS!{ zq4OS*ftV{zUBz<&ksVgt`4n8J`dS|#EOnw-HDtI-At#t*M#&V#|=e=J~qi=*I zR-CLe88C#-Mkx5yESo?BaLX`A`aW&PpA;OyOGD|7{!LAaGE4$d3^hsvHk)2u(XBP` za3Kcu3@!{L!}*r1bG6X0(kzocy<+jZ)qtq?)XM;?vaYmdIJA&DVHrKPy zDn64G5*2H_fmHk?;A>F_oO)C7UCLJ3k1-iqw_|P<)GmE&(c(X$M>9wl|!8t*Vr4IyMAvB z3Jeq#Noxi{y_@VPXlzX66QyRXd9gH%vyf_5&)vMOi?`@^XZRn}2;iTcF~<1Pp#*hX z(f-1UM$7|g8KuH&0(4Vh<0r$YtrRC*z7E-oS?WzN0Oc^#&+H@eA#lbNm|{M9L|I{; z+MFg+?6A=Ro7ICJPVNL<@aJ9(a0wAyYK9kaiyp#0Nb|?AVQW|vTY97e)ZLJRq3R6A zG|zH=xM-RIJI$Lji_o8T(KD0$^FA?_7ML`vs??^`FyM&bVAAF>jJOt6W^6eKUzIgN znf<4=)gcc9K(jm*3LZY-o>q!4XV=m5lK1n<^$R4}^bMtg`A=yDP&5d3-r>SA6>3JT zMu&X+qWOa_n=L{=5Vf`)Jg+KdS=Kc0XNohS=PvUHxmB(CCm(Mdo@{eJzi7>tf`tVd z;^3bv9&z`(m|n-bpcZEG1_Oo^W%b!dP|eymuX8#rtug6Uf0qx>tTo!1r2AG^V>w5s zCr-Bu?k5}$uDkt=&+sxQhMnPA>UO-Q=4`l5&U)?_G>Baf7|j<1M*4b%`imd_B0=eq zbaf3jic}phUmI`NRFhXM*PskZEq>a~tvsUf9~h!i<<&jb`5Xs*eIE_&R#r(o12=|- z+Phb~4ZJ@n@KV!he4KC+7&sR_w)aj!`t|tDN47{StLlJWM&nMJQ(nso4l_}HV-&gX z9hAMQ!6Iv=*E3-;Erw7s#m2qBM{i4q;8Wu`>ke(svR>EgrhSdRPVr|pnl9EyWaKLU zC)i-&q4&KnpT}}qy)U0TyRJ&cr2`_WpFiwbX9r4t-|kUAu#!tWXp_)c@L|zEU#s?_q-68_>Opxj;?HV z%E_0;noFzbOc$QLBKx034+z5eQ5K6zs>)nEqG6y;C63?D0b=8;Ik&&?=smgSJ1xy#$mNfxt+X@Q+RZ3N$v=6B2-Mdgo3$x{o<`^S?io{ z$$PyYTQx~OI~ev3tG5rASQVJG>;UzN)$gBHH#Z0Pj#l7O4ia0}o+Go;Vl*-N?=k|P zVY9aI@;sEdp!GfNlO(-Qd_1#6=%1#9R>H3EN=&0EUe2JYEPSNk9l7;au17gOp$TG0 z;3JF20c==5!kv4--S&G%rAgD~8}C=~fbjs5JqCSh3-ua)&Q(%L7GoFgan-;p8vd5s z^X0eX)uKCf8hgmEH~!=+&yhYOaS{AGN_|GPxAO$g~i{{!0i&CA-IZ-U*cV>H$ zSrd2nu=zz1$DT`e4i!WtaGu%C%B6nIk;!XWZ_($Iv(|OLq%Ypdt?Ru%$7Z-cW)#SI zz?tHumw2_+gD=eU@9({9#5{@K+t+92?2cU^bmkxzlg13J`co%aI$MMpw}xa)I(hp< zd!V#e=-M30NuMBq^>5B{@Lh(O44)q$y1GKDOHAB)F4$Q#H!{BuW>8fu!>Y&{+Fd0Y zX}peeYSrC@L{=PU_V4CM-bR-&5zs@k^t&b2_|(V>GI}mZ)&G8A1~)>rt!2Dt(ud|V zdK4Rd`gZ168~1r*ST0wx+LgNv8FDzBUY=yM6hWnXmW&g5WevR_a8-6hJSXi~j8wt<^f>L8zQYuPfl<>Lb7gwdXbdZiIY0qe)y%S&}nrzR{CL?&M zBi}VKKjC?Q_y*lmv-Ob3+$r08FSE&V@fiC`R11Ag}T~g|xqRE%N^GU!N92sA_e5g#=nCRt2|Yt48qGM`?1_Qxo$AYr4aB! zqZ2s=t^%Vaf;N;6^wGt+hU7ja+6`-xnG~>LU@S5V}@q?DC?WL&hvixteiXC;N9R>}Eb1aoK1Xg775yW*=me(m> zkucH`A&Y7DdUqhM46V1^j4C>N+1OF+=X|1pI<6E!hwULnLfJ)C>PiQNboU!1duMrJ z7#rpO)8!b}$uHMcx#qyf$OTxWn^wc$mF@dYyTKH&x0(gpOEFSK`WO|x%Xz)u-^I&s z#xTY)5C?u{aSm2rUw@9HLbixV9L{S-LBJbbJDJB^&ROC?X8pl^rbx*@-qfgfdst;b zCYj@2GO3gHI;ptEM+QDc3HFvcvf~w<8O-=eS7GU=fO-<`r;8A3gKnf($?2cY=~S^K zNhEy9JXHoainZ&>akM!SNZlV4GQQG!%cVGY$ZKdn&+J>g3LLx5m9T_71WBrZ#3RH( z1(m>^7)90>0B@hH;xdP_G20tQ3PLhUj|w`F0F{dr?AO;QHeOim?|OQ=GYD#hMN7ft8l5AW@jzU0pN(ce{J zIv5T9)E34oFuKC4lPwZ_`yJ9G)ytHkUaH}vOcO7(%XgqTGV1HI`+CK33PUyF!$o^O(UgVq*=G^#|KWk|+<&GRc<(gUM$ zcb}~I`Jmd!|Lu=TXIh(wd9!2}^o|3Dvxzf!@BT)z!hYv4m0k)1z~(a3JKOq9cTih5!-b)Vv1RE zpif0TASLNQL)~=q zhYIl-1V0}byzeY4vDo4Ymzeh+U{NGaWwa6ZNDFB!S-@_>URPS(i&beAzg~;^BwAgM zzCO9UjfH?Mw6BR(6AwF-ipw~QzFtGVq|T0nZkJ*oIsO7Yxyy6ADWv$8Uhu;$FC<}! zeMA(^>(Bb66!IDCny^0suzv29WMF(T`@4I;Un@}3HaMrc#F;`ETj<8X8+U_mfp(!e zVr4rH<%-0CdRC=b>9I&kz!&jPONf0ALQjI!Mh6BrYLbSDuz?&)ETHX|U_B4PT6V^k zRoXx<7Z~QAU}$-B{--^Z6D9I3?nnzt2n>D*w1iR%K|R!dxscX`wjdYI6a{yj8^w>p zWKp0+0Sh72By`({^21Hbd#+XVd;M_BW~Juo{_(x6U#0PRt=pf3%|nxs(#_1sg_Dl8 zVkps_yYcePuw`+Wc2f>6g~@>7m4>J$5?JAx>8ot2gvMX^OR+*tBw~XP|BP7hIO!u3 zg(H~!qWrn9z9gM2UkB{30>mm{xBI-SLt1Y6%gfUB@}Q?_^Y)@0{awCqROP!2>(-^V z_@8Tg#BrQM?P|{@sa}PmMf$waWEDY87CzGtiC`o7f-U2?%&*Am2#Q&$ zsW+nRxj9zOCfO>LGM%`|idI;RruZ(<1vZDZcJSa8DcC@Fb70-b$`%?qlqR!BPzq|^ zoN32bOp*DL=1*Q#O@%tn3dQq%^tDS9PHlx`8uknVPU4Z(KLFuvV#PjU`aAk|*F&>X zOX#ms(XnRwA&ocG1(eaF=8a9npO?rAlzJj97_;M$N>iwhb({3;Njc)|vqDYotfEf- zG7W(_fY$_^IqnE*1qj?Pg?HY9Z;D^LkxH=;0`fW&S~A)9)bjv})(%IL-|N(qqM=R% z{A3;-LKCwZ0cj7g3aRx!tkua)&v^{4Q<5z&zOxrC{;#1Go6w^(P_=mVuYxol2vCbZtZLsEGIL&~8kMi+M=TfM@SB zDrD^m8*=LCe14x%UbVWlS517|f;qa(E@w+|Va%e;YN?Z*H^hnF(9SCt;d@jA;YxP} zIuuh%-Wis(-*eqMtXtaLGgsd8Q>?#as(DwjgVh9u23^q|)>o{0XZG5m9G9DpYo%Lg zhIbbqn=m1Z0NL%bi$h&?c?hIA)vs6fRg+@k&x<*^z9*G_P(34tZ4~MXm2UDA))O*l z9)uw{)~H9)zYmoEO}1zn-3`Va-@3yVQm8As<>Z_4w8P4w#1e3OB76j)UWzk7t?llw zCTZR0^;9#A&pCZf-U!P8wUQjIK13dhu});!o!Fh<^!7&OjpLpiUB(MhP8L|1SjPA9 zMp{I4=e>2PO>1uu_^IcpZ+1V!s#5c7we|I_?TvR=l!b=mAZG9F2SpyDetGBTFJYpA z$yPCR4NM_+>=D0|O@yds5o2C&17EGaOpp~HJ3sE7-Vb{knt9shs132Qaj11aijf@R zFHjtFrG0dD@J_zZ9S=a9$s%PM8GL{FTZNlSs3rI1=+cE~bx3fEb)4c6r#Wk~3 zW+BN=O9+9R{#Z~)g%~ofvD*C;3D%H(z}p?kV$TwE+9{f-CLG)za=?WMP&`y1^9 zuH(?VlS+>B>snE8Ue4*cqxchB@8gE}UlHFdQ&6;3jp5dG_3hon68YWeb@Mh) zj`aw$bPc^M)1nf@jr}3JPX{>ZDJB7%q+tEU5qbRkoJu-+dhXS{?ijQ|^_&EU@Erzi zuVcMhVC0Rx6wi3cJmQ`nb`6=C5PL>`;2YcC$)^=KTu@H$>xkgLKYpUAqu(w;`cS3+ zjH=So7wG3iR#rFY+0&y~hO5S`Y?j4eGD^qJUR&Q@FDsN$mIyY3y6XGy)-qM4w%73v z1Wyk-bF&(B4Z3P;MQ-tf^+mwPz6ovKQ1T3;Ct@gp)vxv5kpR)H-3&v(0F#Y4X^6$> zm6#fX3mw;zLH!$e?0|VZqlP;R-_LEEpk!Z=z%m9w62=-+?H|!nfbpM{5(4uA5(;Fp zg?T;m1d3JW?F%&Fg((!^pgNSJ?`cl|HEQhEl%~<;^6cZc-F@yVexN7Bu zq0?!>T%i(#NX$s%ylRT>B^IG?oV6{H2Ku-=b7V{<2;sJME)Y8|*qy653v=Qva7LmT zlL^Bmn4&n@luWR~s8Dd1xw#_W6xGa^@<>yH#Msdn$_tU3KYlwPdsE)7Fg7nHj845GAwlK($ z0fFm+Vlb)2+rl-3@6*;QWUxo>q@OiLOy+1NecZ=Xh0VKjhYeMh8RatQo*zfuQpWnO zgu|#o{wiO{TbUqcwyDOMB{xjqr z+u*o|GdZo^cC#l$qaX3db)b9STwYcQ}Fjd1+$pY}r`S4lz>)JEIo`jopiR%R`f z0ZOfC!gzaJRXcb!?yow=i#I9qP-i&R`Rb_c4o0S=ksBtWV9vxJhgD(=&oRY*I33E6vxEE-Wo~#>@fPpLK!oMxl?>L|^opZqWi6haM9^oVIgbZ_{aico zkhO2cE@}#E)5R_fMWh@VgD=5GL;h=(>bsRl*RUbEGbRje)`Em_vaa;l5^V7QSry`L z2*C2lMVdaWY*>GH$!IjwjbTJ_&H3PrVN9VFUsg-RpqR0yF{bU!Yo3TrFIKnJ^+o6IGA18x!J4;BQWf@A!75ec z@wv1tC}nxJax#3;X{kfO^pSD4ci@Pe;naC~4^)PEjmP<6d0RK_G{x)XA2>%RgPrrU z6hN!UIXO`bYJ;8}iAVSw4GKY??x(SVJl~br4Z&%!_DY?aKnN~#C10H;DDbWoa7Sx1 zMCC~9Z?Z$59c&%ArfC$J`5OB1x6@xOnUq3DZgs`r3wAMl?svvSP?c#8g^d5e}C3?`Mydbdp?ml8qN<>UN46O_p9 z8ph^ix3XxWN4Gc*(>z--ioZ<8|BXrQGRsYod|Ln`{_y;cHlgpduD5j{f}(4rTMx3R zL+n+Z(;5es9Y*mkCRo=jiRxuSji&1Ph7YMG_!0cV0zhro?`KM?Hk z@ALV0VHMpsUU(fFHmY0Mn#Jk8uW`QJCb6qpg*rKAcyxcYkP<5>^Ex3lZ0Vajg3I7A zF#e%we7ccn(=A!nHU7mS=UI*-g-s@U2**dee)&v692(zT`A{lpsso^P(vHCCASKC2bMLzA-}xGqWvC5MXIDi&+n+4YD7w8WgxFH< zzY`T$^cH=oHX;Z5xC|jz+9y^sYQ90Qn~216UE;(-bk*U#{CGorm^M~p@cXoJGmljlC{4+%rW)9|Gko@iFW|yoWhSzLOK#fp8L6pAVmf$S*1TycPs41_&Np#EN?hu0)XyRZ5*`8OkGli#p;*OTc;6_d z91ue_oYnTH-k4qt;e_uxIn~KgS=93iD_1XWmTOQY!`48Zo|ok8R(io1wfWnQJ=dS} zb+csem5C?#6^96s$~WjpYo2XnHOTJ7m}`=t$ph$?;B_-un< zB2AyNwFoVM&Kyuj?9zC6+%B&DF%ICC8*_~`|6NpV@S~Ynn>`;&QtOBK;ePJmGXR0# zaTro2qWW4A3^cuZd54%38vNry|GVcAynTEoJV;4LhHm|ZCXnPJ9!beavF_NEW+@9? z83{^tyPcwHMLe?(HrZRn*XRh?+h@=LiHZtyNRFbbo6crj>w1Zn<3*ffZ@2{`^EK+V zN6;Z4h6u4sPYQr%;0ZQCNsWy(lZlN-0M>P!tZ)$V1VjJqwD@vMg%)#FttjOIufUQ4 zbokoVPQ)k3f>E=WQ#mFr4Zr7M7b?H(1XaNwP~2W(Uv!H$rApXtV?_A)@uR)~V5j&% z(Aan>;t3++Kn3yr_$6=JiDkdKS*K60_k~hBdx+&Xkn@{XP{jWWwC4|oac^FvYHid( z^M-#W!f+v3w}QDbKrNv!({eK=m;_R2zGJvN$QT}VdpMRpNi*#2AeQ@HY9va}G*Woz zBj}`H;is~MJHnN2G3(Ik{mihwJ$xFVyvDP*xKyZ7yX_6?qeR+!m)=&_5smuA&&f8g zxtrdQUlr>P=;`n0G!1l&@aPPI3U=KbXzQ-8?1iicMp_Veo&9Duo^n`73{E&ECOuxU zIQ^+yN&x11J!<`>!iM`X(ro_r9z8jDpP?kRn2kZ1Wk3E%QdskGalY~`=EvLprsSq; z$z2M~JxS0t3xty|$mDcu^d?Ue$uc#d2;%V9@c9>G!-s#D$W3H zt;PDP#6NPZN8$W9jI1*TJu8%~o*!1Wz>)$~Gq^(vfS0^H6SSeZXL#gx0VPaM$jsyq zyDTX#2|ZBFQY6=?UEsVBoB?I5PP`46w`pi<7(7~`Mi%BemVJwln5yV4Jz*8-3qR03 z8MZ|lpCK9ka-Qn6a{Iw@Dnh-sgJf>up*dJGnQ>sPz)(2gagpn3$cU4=5)V?GGfKRauBB$4D1rTYxWgal97!KW6FG%hk13j|7&!VFlSDa;Rpq`LH zzsHgS+A(i#YF@@Ao+`2Ax%pA6WL`J{#U1B4D?wmkd>;%q0h9$vsdkQz&UKfOxo8n_ zk);%yr5Y$73X8w1vAUdZF{8~QR+W!VtK-j3B(f=Oc918bOUi}@s|w{=dUz1`Zqt}4 zbk18^-VpRY&Fh)-Fui2F-cw{{>l%xfcDAU=D5YP7n*5r+f#>#IXAo`=+O>54q>E0~ zVX;5U{s2P6sO$~6&Zn&|P8yN?;yOSb^bh=fJyTfvr15i`R=qZ0pVnV&fI7Yi^$!C! z4#f`2O{Fb>jevsd9*hmuUvXt4G|7Y$H`*u|vBfhJVG%#41kbeqTs=ngUZrXu`J%-^ zce`SZyF83VyZD%Q9NcP z`dd3uJygi>U3pkxGgcG9R{;MRp#Y*!x4|~*#(|e~-h^W6u7L~E+gDYyab1)F`szyO zLr|`5N^0x6BSYD`2!~9!;cl7u6M3tnUtb!U>yf=Mwi zfD@S=C&aPq0>2cE>H9Caa4|xFIg3h_?EGxy>-jEhsQ;i5fR04rj3phNp|~o@^!N62 zx9p%Eg;|Q0@b{o)l6fW~nKLiV&0FC#5GEVy+_ zja|O?^*^zeR4`dWt+KN6hF$FX8Kp-P0lyA4h+K`vq9{9 zwqM0Och$tZ&upQb^>)a!4LC9hvK7nDrGcsdVbvZuw|_j_(&~Ifo(e7ZpaW#4tm_Qt zPr${sr$iG}V}RaLqQeNZMin7@D=)1<$)e+gu!io9wYLO0o%)RHhO z{ix!4wJm_%*Vy*TYN>ox?*zn$>kcEQ8)3 zL#!Ud|D2aT-7_wt05U%-I(}kJgbHnQVFYnpD#B??L&a@V{v~sSllzV%FFBK z2FkBtj!zTf8$#q7vREIK{C*fzl>rerbdr`BF!)2|K!*x5M9ua$%vPcvu_eDPV&y;uyZUHeT615 z_+#VE8LVUXIa>BLs%r^egfGd8?-|OtvqFhTKcz%P=KZ2Bfg*036gCOh?E?SZYJ}$> zQ5!6UD0H~u*r?*cCcBw19Ke}#qF6^ilObn9omH7rSU3&~ZZ=eNtYq~~g=QrlsxCnW zL7iQWR^>#FW6wa&=~KEUzbd;CEef48sR=Ra#~`yeB7iBN%b(>oz&VBnV3|4X(Px#K zer|BE!Fgrh@H-%!RUOUz%N2`gf`s78X@bn8VJKb=GU-b#Ocx0NDAe^hxxB+o#9mdU zA-u9R{Xj5=)m9o6D-{Ym6a^PEOIL~pvSXo-hP%OF8SJMnP^Ag&^Kj9LN2`}2G)6^U z31YkgwF(m=$(Q_khYDaK5OJ|cg1lmOH9^g`DN4+(i}%h?>;Q%hh-2?Z`rY$5ZA1Ea zGvaI1ei)NMd7@+w()@0he9Gje@nv4-OP!VoPWxh$tA@vo|Mdk(jRaC%;H>`_!)2Do zKk9ZedL*RELKlVV?r!fbxmX+cW`Q1AIH!tTS$$OxI{D0JYO<+AAG|K9IJ&h02h}EM zuLI~o^WdUxGV&V7X>?P?PmL0>$;pIR^-^Pzin}N@{G4P7E$b$)XOXf+!RuUq)>cRA z0lYYTdMD5lW}m%tsVf5BCaLXF63f|}UP78Lf)BVJ2D0qvj9xeVfgsDGcs4vs^x#;^ z1I{G24ei$U=e2~oJiNsUS0xUkpDlL9u~&Wnsw3Ip40r)+hBJ`NXVperuiV4Ow4!ys zf(4Zg=L4I$M^(K9t8-T6*}-cK04etMzFxkL<_UWO2b+caH|cAqm`6-VBC6duWi&N4 z5x21DKSxoX61br#((5m2x3%kA57o$bW7MA*v1O0~L1s(*Iv9gfZ=`@=K9-g9 z>7meSD1QCJ@DHm`+wg%}zx-mP*5KkvK`iZgCZxk4n@F2S zJcuA!>2Xbv4>r>sRFAAU$M&93`t}eghS*Kh#;UFQLHp#7?Nr~=nN>|T{%u*nS65=sZwrXdrOOG1{_c9dI zbv^0Z^c2}hyxU$?wefZ<; z)hp%}*O#HwH&i{mqs5}YHHlqZgkEt z7?Uj@oROBZXN+{tI#y&v-fT9F_|f$MD88klw?lwmhGnHp`{!L>@dv^5?X&9)BVcDp z^~P;4Npr~);WXR02?3rj!;?4k8q7+T`9qb7^FmN>#b1JU(ZGqL`0B^>&a71NK+ma| zz5NPMlD85$Qd*?7r%^y~N}T0C(CvFZA$bocZ~}ZW#y57Jpa5Wq=pToT|A?q8Alp^O z$tPD*o~0cwTm>~YHjc_s7|Y8IYE~oQYeJ6nA$k?rw#m z#ogV#6xZMscY^ahyubf^Gnrus;Yo6zy}M`6-95|NgG*E>$81$)Y&8luEeQ&<&@^#G zq#S@Qr&jlHvs^R_MqD~>bCDYo#mg7``%|a{wYa0|H&Rb7T>EAuEyI*GAXi{#MS_FI zc?U-XH>$XeMtpMvy*r=uk)Ti5Jt%NANUbBmh{Yi?$cUY6`Lcj7n*dG@cY6GBFrmv_ z|HHJEVS_s9o~8ugl!1g=2oLjTHrxqW{j^F~du2UyhJ0&(J=WUR$#D!H|BAV{H-;=q zvUvplbN~s(=k>GV5aVScNpR6L;O+?t-=^iT#=C%jll6ZQ3bpJRj3KX9FGQe!}d7+u$d%2mfn)vxI?eXy}0{B_&mtZk$jd}w@8%Yih_eqS zWGj$%Cyd^TKUdcEBt>rJh3x}Ac32o`8aU)vuQ=&^-p9Biz0%8BjTsq*KAgD0%GYEB)StXqh7D#)<|YbQNH+ ze(QgJJ;xWqL9T+B1=B{)Q%YGSIxDmz6^p{F{}q(NVLfq$uuIv*PA^!7v+e)9y!!m! znykNB?jRP^GdboM#!e?CgU4sG^HKPP#8W^(1DNfE%9^d6AB(%v?47Zi<;^T>papF1 zGo2JPAQKbj3PxYnNE5uX3Sl_1JKU05X=<00LTz(OXHeEi4l@lv7q~s9uSn^su~H?a zfzMGpM1eqoW1D^|CiG%e(v!7Tg{9hI6V4+tQk>xU#1#4z`!M6+L{!<-)Z}2(bYNv^ z2`UclcK$N;_*r�tGvyq-_ARS_Tr-^Ga!2QMpP#ej*0 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 literal 0 HcmV?d00001 diff --git a/docs/topics/no-icons.png b/docs/topics/no-icons.png new file mode 100644 index 0000000000000000000000000000000000000000..d00eec2d62a35d333c1a71c055495a7f9eb525a6 GIT binary patch literal 121990 zcmYhi1yox>*996pXj5DY1PEFvP~6?!p-6D2xH|=kySr1|p~c;T6e#Xcpt!p|zVHA4 z_g>bzla*O_-8+*xbLO1A_X$^4l)^+KMgsr; zl@bM1Pkh*a`+@2pt>X*;pyT}Kf&*k^5x#YzxX36-psc_X<1!I5eB{*x0KfnlaS?To zr6XT=AJT!Q*D>3!=W^YF1lz@wOg#rK!l)iB>VUeyU=WZ36G%ZZ!VEGxRX z60EL{OGJSP*f>U(EqkUdP7+Fb*pr@<3>Bk_?t3vSEsojXo^gaHxp{^s84n@K8Q4jN zeN5H*RHJ9`tNnpsH`zA{6r^`JLY=DT^q+L0+ljpU4@5i-ua0!{BukCkT^P=~QucWapQ#Y7cT-j5zebj$@x0C12#pv5$D*WvX&i{T@`uX4Kzcq!F+|IjWe}tvY z!?jC{(o!I>1iB@BjNmxKN)letf`Z{vkiOHXX?m!Y(NJte0k&~^iR)H8NEKH?ILuHU zE&zlbgt-a;F_fdxBZ&oI3Rt}_XJ8PGg9n36(@VY*27wtOFzBesH)pcx#r1Q3{_j9$ zyNGJE!A0B!9B>qanj%v_>!|M)qz+=;-6&LoK!&h0#Ci+)thg|j`B~D?pt~u43<{UA zg>#8}osA~;d5VSCId^L_(IZmmK@sITqCq~=_R28 z0Em0@=K3C-cKy12LBtP#U-RS3RfW(R0Sn*P*HH!gQ^AAVAE9LL@a11-pf6d6^PLa- zu=OQ1xxlMrd%xGndFb)Hsj%bq+Og2fB>731y(%8{G1lB8W{M0f@!fZ=t0E&oE0GvM z?OosKjsIG}f6Z~i(%?K;_1(K1M2f+@JQoar;aW(Ag*+o0W}o!IJ+)ayjSdoEczpca zlUn}AabnoecDOjU2|NX201Zxf(boVR3NlE17;PeNa2R%iJk9p`Pb(dOFfiXNqfT3X z9y1J742hS9xc0fx*1k7=-*LNpIDV`zm}~#|z~%RR=$+&DVixwhAYEg5&95Q<-h+;C zp=tlv+yC|Zo`FxYW&UB;)pgg(V?zLj>o<>YfqIy9f$cCY0}5?aG$YDtsN<@I(=#!^ zP+o+aIK1-VY5wHy!u4}Z$Mu8FqfLzFMA~b`YiD9ciLX0KVA2nKLEMnnnI40ooieH{ zc5U+__jKM1X)vj!+9rU4Y{x3=~o zln`dl$Zap0LjVYX{KfPdab){?U?MwOqL7YQ*J&|7F&9JTuep|h6qy)5vFiO!SS1iw zO+?`Ii8@^RaU#1-!ro)59f=~>t?1@=Plgx7n}J3?ho!Tqu*!3J&hBNUPL4o9>B{}< z`Y#gMa>$#f1;#UcYk~UQjLUuMG}?(E$hqrU7rf|QsCVSRRFFJ;QLt}+dU$|!UG2jR zJa5Qv`JW0V3zIY_I$r}(%yZorEo#=D3SaLdr8JI9wY}EvleftQ9g1c%p?-@Ya!2If zcmxqX!cv*x08dwK?oVfH-_04d9}c0fvT`oc@CAVGsm086F=w{Y(J1q$#(Jk|bSYkE z$U-3;XGUAw|IeEU7({=F7Y@t2a}tG%a-3#KHE|xE z-POxU=j-^5?2Uqf??FwA&mk?W=5DNN9*S=z^srGl>3?tur3VfJ0$ghZpO5)oaS-6J z9^`-QUR#%A0DkkYt+e|D68gW4E179rqKIXb008_3{%(qj+#5F4Yxjw-zi#8#U(SNe z_SSE^w=;H80PLJ(ADNh-j%&T+ZDj3R4=`F>^II}|R03S2KF=^>saR5|Du?6ZK<5w3fgu0509Yc=M|1z z;i>C*)v)j7y+u8(d?rubLWKvlMmo2VsFvJ#tl!fm5cB!wwyX2DTT^o+0zCx)F!0?^P6*fd9JA&=`Py0k^|org)qCK8M62UwiG;c8*VAUR zsjV2FU9#Y1Q7L*Hewfdb;RMu~$inw9N}$67nydUZCLXsmDr(wa&$&{WyFl7?rMaFj z=q)QBEQI zl!hRR#6d5h@R zxVTW)ARU(@7oZ4!czB?U2ikKj;D5{cL!Vb(jxG9ccsB@>P!}Ib88<||&8UA%F$u)< zSB+hx}3s*y$1kx zCvtt)?S!-+7fHHY_IXbEUvG84zD`U{Sn7?m9;*@H;o*ImGY6;x^T)MifdIpsUg`z{ zctE!{W{u|!Q5FpfBD^g&02CYq@#^yf2#@zKXugzJujK(&L@_m_oV9s5CH%tQOwA4 zY+Nv6QbtL*I4ZpH7x8%N?;Yu$&Ca0>Wh69+0jhb@%Bt)DVM;O-5LyA9+%)~!XeXjB zK6WrhdjYO?8YK_}kB=M#_-zPLz!v_&z%a=)1Vl86RF=Uu8dY0PL21Jy?n{XXpq^`AQKTAK zD5L}~k1m4t<}(wl09QJJJ7M!P@vmuDQVPgNv;l4_!X#BbuH|!T4h1!k1YG_f*Rk;1 zNLC6&6GkAss5A&sHjJkqktK~=L2}85RHi!2%veoI8f1zjY}&;kA6POhvua4R-DdzQ z4hDsRoY3*JDUc%RiYqj$yf#A!QW$ldjuz@#TX{7!m|*Y#>4c)gR)|ax7zqEFl~h*{ z4)RFyg}1hBFEuLhO4`{X_RTVt0m|nKb>}%TF`a}+hI%?Ol!6ZJ4N~!DkD(=2!}X?w zDUfhnKyaQ}MligD%3IV$dtf4ZC9a2yC`z9P5Rr}lK^O5&F4V}>%xu+jFFTP|314EW zo^gi#s9(5bTS8`Vp#Tv_)J$TaBv8shPFdDW2OqJAU7>6J^=>=%^{P~8e0+RoGW=b? z#aK3zNTV-IQzXGuhZB=jSOgczHa%EW2D{Eo1t6}%j!BgS{Q$b&-R=kqkUX^NPBRU8 z%Ag_g{X0D2>hFD!t*gbH3D;eham-xlYu6L)4i8|@wf)ko)#*9EC*9I-Q5{mcmyz&`HD)4}(r?!^o<6rLZg0b=P#Omfyb?+A{k^Xbb z{a_h1fE4eNJZyMk0v;e9!`0z^mws5?de>~fh6M09tBJkxg24e6Jw*Tk1$0bOHm7ZS zw6XkGd%9ic*^~OdBeyS?kEhkIrcu1;hQ-8D{Jj|FCI>+Y&)f+lR86TP(p<93Ho@dR z|9pTH?5x+YMi!;=Qx+f|I6&u@CpQsWS<+!LZ>tw(UmPADTsaA{Xc&l6wjN+bS@y9! zBF{t~K+#{4qxMDPOA}C37+AK}$vV{xRqaSDk=HWI@Ay^6M?6%5ilm}pDv;idD4hVL zC<;&&wJRk8BZeo08B)e8t4Cwo5{H7r>KRB{QR#Yce?(+S>Y)y!%V=zWqZGYXc$VVD z0Km~WZ2h&$kR~CH=|^^<3#*4fuw`^q=qQp@MTEmWddVlSK8i|dwG>$bxuH^&@juGT zTc0jqCUpxi<}N)owZn7E6f?ZklzU$T*|R#T?~lk^2C+k*6=v#jHJUI;!6GR|B9D)V zHQ-=%5Td+Djy%JYu?a5MK;7hCt~SrCym$;JC#|c#YGc-sE$nk^n>V}vLJe@WLjVyN z!AR6f5i!i7prYEJKXP=3k0T1Cuw8@$08RJcP4ZfV6oKa+jUN1Dz~J_bKVI!(33!O~ z!C{~v5IcsN28ZndK3sWuK)m+?NEDw@d*j**>T^C&kWhzr?+NU+ges}YeJuICJr!m~ zgWX!`g?4d)yoKQV{2W9F6El}Br#QLx+MCSvKilY;m{1fA1Ivcon}DbITD=(2sUTtS z^(@Wg5g;_c0AXZ8Fc>igkE|FV8lgbx*(;H_6%JR}A|W2938i&$R~D~s zUxQ$O6y(%2qL_ja-x6XtS)fESkMF~tVW`NopTP8|FRHuOk7w*zBI^~27o(jwz39w( z4dx0O8p%W3^b8Evc6QfZ9fG+v)zx1|5~#DYv+J~NCvyZ6Dl0orLR&GJ$$92fIsLYN z!I<|KUP5X4puvPd*~*qkvnLQdi?+ZYFtVn;Gd<<4Pt|jAUPnf;@Lw{g$N)#f6cy+ z0ldDw)lI=e3xN+5R#c3!V>^d8%rIB<%VD6L>DO?c%;B)>ox`*r2)xZ2xb$AqJ;Wl< zY;)L*M_7KWOR%)RLFse;q(d4t`@G*n8~7t=^HlMJ6{ej|O37$B;zOZ~^)yGUpwHpK zB>-SU=KC`@&r<2_XaeW3@2xQVK3sH=KpzfB-A{g;=(L?2J6ptX$*bkfway#7TtsWF zx?E~uNr?*E`|m_6^b|y#`o4Pe$R5dY={?5oarvERu6ONycTWp7(ji2>$#^$fkB9+t zBPVL@Y4!%UEPP?}S{sA1!D)vk3Z)Vt`JqY!5T}?7y1$M*nz#NbJW# zN)$+ON?lI+r!z7hd}pr_!GO??7!Q5}9i3ms186eX%AK$(*V-VH%1DWB3pJ>8)*H#+M<^Z8g2XBpCNL z+FpYSwKQB+@(@)0Jlh!}4=t#-oX8r_2<6zcz)g|v77@b0+$m{d2d!})Qd;9@iq ze^SV;lGs`VX$V;!?hqm3K<3|I68*sJ<1KznCT^0I-KtSQ@E@eyY$j^3N8k0l*8E&^ zQG~lPrQs2y6AW9!deIt zbI4yG)+T)q=k}mpRn4tSnHt;`+&1%_Vw(<%jV*1pMYbbId-HZ)uFE|p7jfG|*X%xH za#SW!+vgta#7y+`I?c9=OHDS+9apLagP%CYkP}?wX-&nZPV2 z=Lp7Xdh0bc4S3yUHB5!2`yY%E^gH5T_J0{@D^LCTLrVCAfc6vmp&iKqAGJg}m-}Gl z{pIVEKeOL833Rn?lT-m-<8tB?6a63dk<)V@r&;Pr{-)iHo{R!kPp&n;<(Sl5EPO5e zWObMQf5RmN>t2s`5-K0`3f|&c6*c#}y{?z_Nnf{Qqu(ttAEZT3bsA{w^t(Dg!Zpaq zsod-7$Lg%DWY-8#rONZWZx$@Fl@PZI^54ZFetS!FHs8J84GEpJopxSM3JJwagM(Gq zX__lvEE(f;e>$A3q~>^8-dlV{u;X}qcTB{!U68yppw!i5_Hb3+@KHAB`A{s8M!q@W zna{nQfXzr4*_1snF4zzSV_l$lSxUA!L-mIU+UP7=Hh~SZU!*|<^-MWy-kHbT?`ihzzUG) zNG<=H@9S*{fH|vl&_kz07y5C{Yr0 z)bG|w_ll;`V8-cwE-NtJBIt6QFGt_4_PsfGJv~lieQh75ghDT0T5oCI=pTFUPiXbb_G>@<(z1oQXp8GRA4l7$pq z?qZ2+H8GDhxvvLp>o1aO&X;ovneh3-hdHhtBO9JP7|+#HI)t6tMj-Uchd>L z4t^n+IGVWo>rbbXG#GW&GL|=?l%8vFsy6$M`tzuG%)e|k?48H)a$DyPZ1Dt4G!4F3 z(Od`BTM;O-m>>_2kMMZ!7cjMDUhH^C>Eb95<*F9Y9cXnu>`YIq>T^B$K@}8MnP2yE zw4wGQFKKe4r7le_{yR3%8X@(}KiB)tDbk(RI-*jTSX_i90#u+vMKW8`vCuWIw>?_$yxd)NKkYcJgr<_9HC|0C>Ho@W{`Fd}VWy5D z(Hc|L{*du9v7O&O?QEgwb5drZ>KVj3F)>kHSy}nxhsRbp?e0Xju8vN6YUa$^TnZi* zAwDToB^^(-uP3h@EC4qO`-pYA&gD9a8&p}H60^@%`gOS(gqMB;$+-tE#HpR~)50J@1_-1+)wda#B<0*Vfh+7Q$H98m(qhm~_o2vcj2cCV1p> z{Lhrk8VI6E`Kqri71Zf-D+7*6)?&hUs+yKz7V@Z;)=uEo`=;*lVW|#1sVzOoCuGwA56zb_!Mk-;u5GRn=P$g*JUOCy;!2aQo`nAol4K z?ks=oPuIt}3wkx*ByH2QA?kSPv0S0o>v?Fdpl_?04wXl&G{4LzZ7-FDt{o4HM~?Z` zTL0SzKlJQ|Bb?u0K6lcNyJ0!HQhy4{@?dAjYnR-xye8h798!SA`AqyUq{ z6sCsVNukq=!_H=RU2HKx0Hs_Ke6S%uF%m$}^ZEGDU9-mXq^YtJ1OTaih&%)Y*w}Y& zFJ+z@TDt0!OaB7|RCIYf&O+N)UmQ>8T-P6C$&dJ!ZYqRUg{t^b0397Q(94J0&fCG` zL+E?R$RYaGt-F-5IZMSEio5UgTGzAZ?%#_@Ed%HCQ5yijmo$34;}PXOy4TM8<1My$ zd3iZec0CrwjEhCT%HZyjxCOAK!~f7CX?lO^rP0UXUKL(N=dkk7##zH zt<~3fYI>__D~s%8yb0I{n!U&7PJ~WQbxNNnTZ&iH-vUoH1MSPopv2Q-`yY%XCOT=v zb$+A5l@k!Kxx3POqYip>u%MNwnQor}f;!We zpLBC>+S9sNbEJIUFM7ZqLj=}5diwr9eb14c<@*r(qC)?!>pi&NP!onP>wZ(_lc3#Cc$zoL;^0r2rzcYDS5vbPJc(I#OiGF@ zQr_m4lB$nRFS8XlU)R6+e$mvN7~{F5JeE2j(dF=$28CRlCpz^W$k`ZJ?vMPsOTfcy z`tE{5;kW>!SqKjDS-f_ilDUZNMzUT4uEy3Lf zXB=P-H~zY%`|b2eyLDqzYF-#};S4m%%Kgu0{m-AP3BFTc5R3g<`$~Iz=L6N0wC%xI zI#ZPZ9^N+Ay!!3HR(XMRfyGKu_%EIOn@+OWa!UjIRwW39@&%%^*P~Yj!#5O?HaKu= zIDU@5L48-3p}b;&Q)?(4vM88uUW^JqgiHcQ{rbpkk098mE%OWfCJ3NkEhtE(N-M7N zbZqb6W;&A4WHayP=B6rZV`GCSLI3H~S4+#`k&%(fNhx4Nf{)AVAVS;CiQPULQ1eF~ z<41?9ouzLy*enN%{SP)bM-re9@S0tUjK42M31rand!HP}AEJADoiK0RuKM$r_VC6- z51xlfM9nK_pvt(KYo7LU_dlJ+3o$YJStN>$JZ^r$&;;1I47C9~oWDE-jMGBFqnnkC z3L00^w!K9oNW}X*(^Nqa5TeWtSS3rn2~1nvGOIC}>poZge2s7(93*e^Q-&mRz>uyJw=6m7U(?V+4}@T1-3QYt!OP*G9-{XTJh0#oAD%hUOHVN*=kjg0>`C{h;Phh)AZ+=(`eGl%y`N&+SfA)c>LihKRT7&UIdB8V&pjaW;ucqypA7^PlQ2|T<7eIVWrrh= z*b=J^)9R416Tu-G=5!g8&O>kEizjdu0QA{-R<iG&;rM8{7o8>{L@a+56}k9ht+O1XGV9{#3;_JM-d;AT$a->cSt`w~Pa zNdL=3sfh|4qZ&a^H;F%FUJ>_Ow_2!;Iil-4lAx~3VRI$jywYZ7Zk26!g7*C7M4F$E zcJjkN0vY4e&E^Q1#E47h7!J;V=N|kV|n_Yi>fxz)KW;7_geTKuTH+>*n=;fS1 z5Xuif3n#+YTJaJq^ypkjhH=-y@!c9mt2vR*>igOp?YMY~RDwNBKRjv2U8_6#Y3vf# zK+EZ2EF{JmMmolRgsHyh=#DAw$odaijDR#rN{fRCiBx~qbt#mDx%_WU z%Q+8=Nmkp$hgdixT3IA?jP&OW2QkOGebhJ%a!zwyZBw~g-1(J1DvFCIapCJ7e>B6P zZoSO}VWJ1)@uBdZJ8HMrKmAl=SE~6H5?mWFWcryNR!^$+Q3iW(A%;E4Y>{1FB?Z__ z7tmkNLQwz_djqLKsBREYzOXO|5P=$yq#aCGAH@_YYWn(>Fck99g#{ViL=;bggGmir zBFd5bLyiiEe$XERjKM^6DXBNimD}SikDpM1r;$;K#@X4~{~QKYBoy)+N*RwYQqfdR z$tIXH{Z-<%4kh=<^H}-??YzMjHR7LMp5uEXTO^Z_R=de^m84S(;3&j_Mp4dAPGo*} zn{OE?pODb{CfGeR8B}mDW)g`O^M~y7kAP`rBnrY$EWvT{#F`?amD2uQA!YM>x0auC z3*jgr3rB~sAW^YRMwNhPUtfG0L4RfOMxkkY<4w7i)wy*y+ksgweQy5)d%wGAA^v(! z(3Kbf6jWykiD$>vxb$p#=@eY;4-}5e7zr%ee21(qQvlE|c^@vxT9U7iO8xTz+Ji2bG5TjRT_*3-}|lwYGZ&Q;XzgzKvZ1H zSO!`gnN^lI7`-h;yTnWip{VoyvPakUA=KW+&hIS$JI6Q`@b_<5$Y}p(j6U%Me&3sw z5ARm$OtiG@#b?VKdFNtZa)Zls@P35>*MDhQl`&v@uK^Fjk zpJAcTk0{3wr$R32G3=J6*$xk81{I}<09ahrRB`e94;J$2n3yy)uHRrgzc)mp^^Gax z<5QUV?fQo7%iy}`f0vGvFiq1I{{2P?sGwgqEN5oc=8dSz%JKr@jM4kf?i%DuK7IIi z%-?)yhHXFVDyPCBTxawp)W}fuNwCWbg58P-M64~NeS4l69K3v9Ng3dG?D54?75?^y zq;+U%A0kCCIC$Z^P5;VZjd`(S{cAH2o#k`00(E3 z@O%ws)zrAoa-J9&8BaFT5gul7f%QuZ*S)a|O8#zNJEhc6d!#|s?}|ym(`6<&^l( zI>?{lf55S~7Y)*3&Q7Jx(pK!kseKESGSMmhyh)V?uu|BcvHhhMz-0S{1{>5P9*-9W z4mkBr;pLGG5AhM7Kmfo4=~$5p^^14|{$2T9NG4Fq(&q=f;qKa!xH8!MzTXf4@~{Fz zHDPL*X4o*dA{C+udSU)m@1G54(Lkkw;?7_Q7%dNAH6|`aSuX(yI?ZIVT8F2AT+hV0 z$zA_R!s!X!U@n&CXuFlECx}uevtWn2e`1oKfdmiN+nx^drkGiw^akg-pkl2c(k`$g zBd8(5p-$7w1sz)5EqD3B+*CDJC*nsh8T+x02Oi@TJd|Eoxx9*U+brX-|joc=$3pi{UG1^_S>Lq85m{GWUN zbE6~zg*dyyjB9Ay|Ec(Bn@GgxNFmO;N-Uxujx0q-rA8Y@KQQ}FSC3M`ktkeUTLu(I zXCl!DmeC&nP9xG@3a(3phjqWkA`?pQ-+HMUV!c=(-}E3+i9Ig)e_~;Yh`V@a&*1CO z<4`*Noi};9bB4`@!S{;X-<`o1S8f00@zi1nB)iV_4r8uH_}ew>v_SIq{e5Udu+6{p z2WvIHwUU_7P})v^2g93Oa%`3tr^l>YbjBtt0q@8{L{3$Fk0*UBnS~N-a#B0gvz_Qv%u;SypZ< zCkx3XJ;0_fa8l&s~%2@x*&}W!}4_qca^6$i2I;6LQz-BnJh_P$LTld59qea zl69jxo#9UIRxX%%%$C&?TlFt2>qj57%9VZXkA0O^+s}PGf8A3oe#`Q9%h-n(FiAMi za6-90B8t>fksaCCI&L1@m|qty4TJS#D7|Nns9-IMdzg~njgryE{EFfOioMiT1J8F! z5?$Atx5(M>2$`GOkFB~$9(_33*bugv1X0-530RQ9Of0%ZwnoGPEHv6g0gLv3UEscf z>SYq})A~{~b&RDD7&VL+H*Ro^yFJ3qKC%oQ@->yQ6Nf)@Wyu~DzSi(2+xB>LsnJ*U zmt@Ogg+Ko*#b&M}&n@e3TbIg^C4$_Ta3_D3J1SEsju(7!cz(D(LSoAv;-k~nwSM#) zJKM}nN$+m|HAKVkij~F+OZq4phGbGtFk%CZt8Pw+&JiF%*kxhxRLsUDeB4-4>M2S@ z8I&8830%ZZCrW$HSZ8KwTlyr#M#OTH;mJ(&$j-u+3x@zWtH$CCiVh~gFevxv;ihLX z&*ZxjM>e$ey%7mu?Wvu2!X)X+Wn6e30xu4_H+v^%rL8Q#?D*T?-y5=#85{*S>~b|PWr6Q8%^$y!b0{sWW>PZGfjS= zZp_)U|9tn37<26UZMb)adPMXN7DS zSO+favSqEPZ~l~EGZR{sPD?+%rl!jtMe}hF8bpg3FGi%Ks(y#{!$mlAUnj`lNGuC0zKA|8EN)igNJSr`t@)H{t#=lM7iam&Rv@D6!manQmhCNv^ zvL9>Nf1IxFMExN^Eu5!L>fw$JMsvMAIiy~atSyDbKt7(TIZ~`x+!*AjTGd~n{UT9{ zG}s({*MWD_soJE99B$Sk{d{*hnEvh6Cn`uRLY3ML64SwKNa@U18>jfl>FMcNKv$yw zfn^1&g7%uiQwY^tAm-}bT7C26AJ^6VP!ZW}Mf01Oq=IxB480upFR;Zv2{tGk%MfrD>^~+WAB`eOWivo#4-$zR>%Izio@@ShoH%})> zgyOKx!YU|AlG92BTpcHENu`i!a+`Xj_?Eb2kp{Jg0$BC?5E`Tu#{;A}o;~?u-N{S= zyJ_e#cgo07M68@Ff}8R8tsgFv){XuK7EkCQN9FGX!f8q_GDAh9fGil5}$NwRv|}0j+s`5}v`1)C#5R5;?B#eEYZT*zqP1ub*%kW_&|# z;CSZ8{Cz!Vl6`YVO6Rj2vf&LrVb`}lN{EM{k9d9`t~AnM5YC&$Ge)jUIozFj7`A6d zhkRXVY2Yd+q?JO58qi*drK*p%gVo!11)1rTmxuNloo(JeDat)bX8%tO1G#Q5;djye z>grE7w8iQPkdix{--63)#>5kK97jN;ohED{+^(;0BC>sSKe^ucYeVv#(;T#@)nPcs zrayQyKid)PA%-y>360$>gY}Gj0d<8z;Ip;1KjT+#OU9UBmL6hPf;8xjuP~DY3E%6o zV+r$N0zLvx8=TsQ;}7I{KBUohFf>I~^yN7VVE(t(!UC}_Pfp60n57*zFk54oA7w1? z6j*1v?!PuOaUgsC$(`>k=H2y%7~^7n=4!mVA@?X#?bxKcp${%8Lf=&qLYi-Cd;nZE zCBD6Ik(cJ(D&ksL-K0FMZmj!=TrF_1@VtA$W~asQ?wMe!t|j%$FJ2B|if>m%_`73z zqCOB_D~hW>LQ*n)@xlPTn$Z9JNz-LGYKA^fXpyDP>g5|v8OKZ(W(e8P+UVwR=HGJ$sjL)f^wu5H}p2Rdm$w zBvf!EX5IovT#0xy30y>Aetgu)N(YIRV6Id$-oV}^eF9xr!qB#gsZJ6kc8E$Qfl;o2 z&N`#SlRp7cma#jfE|SDgrhtnSmS?6@0HFxR)tFV+NP^VNS1{B=J_fPei8n89(tQ}J zq%M&^rtT~xMpzOO5bzt*S;efGc5#|49EqCv{U!33L-UF3(`#$V0{6b^!ae2; zGw9viN1LH>-Zn;|xE@-#X%0$~>WlZ-P0ia(RhZw|S&2#o!9N--6umF6wGxNB?ke{q zgg%^=70?Z$Y-J2p&^bB#x&{v?4yL|`5r)yS$0}jJiGb9LM!2BfA84CMq$LNqDPoDH=wYqNAy%-uzEgo)oUVzxBs9O#M}8J)}p) zZl+Ek|Ho)uMr+s8NlvE!nOts=+v$=B-D0cNVU}}BSpv)N`CqrfcIOM9!>(^8a-LX2 z0Ef@<+B=QqT)9s+cAw+2@eU5&7zNdZsX6>%CJfKuKG&fpVSM%ireojjQMm*eHr$K( z*;zGPFR{gE((&P3wWOVzlYc~PCEz&%`cL$Cho`4RE&mc{A{$>ISV--4+6Bj!He0d5K}lr+3l-@jKg+H z#%%7FDw(ibc?|TR5O~%{0ZoMh=6bul51UweT@=JaM$Ep?$4t<+OTJTnH)xSzPp{18 zGY4kmgh9LgUZeo4o{C;caB$c2v7HP$W14{P>4b%@chAA>$2P1}?bo#v<(@RHoTs6` z<>k#OCC6_F_QmdD23J;Mi>v)}9V?F~>G8PEeaN^}#zdQg&hJv51MB}uvifmmG-CKw zr7rRzGK?jG^laZ-Ui3FC=LhX3ym5bNDn&DbEYCL^j&CTWa z-oG%lkNh|8Wp^xxmuRk~h#~aSe<=d3t@W|>hj5zARdVI{SuXdK*x3Ix`=V0~k?9cd zMG&xiee8ve`?{#+cTt(ED^y3_TxX=g2Y~tW^A`<5=_1;pJ)6evxI515kwz)N!$queH>f6VoN*ra0WU}8c?A5v2KP_ta$;^o)L-)Vessr0mcFzNSD zHbkc2(yVtqYj3N4Ir=l`EI{#b=}@Hdt_pKm%kO~UdzXZ$+M1tu-dY*=oM&Hpu|W>lE@D@PUk=gz^Q4qe4xNy$~=ngiOg-A%&0 zm5`v!UBSY)!qYsQn@W&y<934;H8RQNSZQcGI{;(gve)6Wy9t^Yq$1U?yExy*G0-n~ z57n$4I?VK%OCZ95W!SV$LiuZ|J3A{OLnLUXJ5eIs^(U)KPwnmHJg^|+`H5DnngEDK zyWzk^K`(#qx*RZv-;6RZl$Owd*Th;{LZU-IR7Q3XAI?~W&XC_$tVgq=xgk)geJJhmGfq+S`7tY)DYXZ5Xz-y@EJaAjKWzy}(uQ;6GfaDj+2uzN z6rxN}^{FB0VF=ukY>$)rt;3dl5OAZ<{YBsL;GfYgj>)db0bv8~JWI`;BzltvpQc%k z0cz^C>8<@4hS)5QLgO*QK8WPe+23^ZLE8n-E03YZ1fLg!J{w~bV;%evQZ0FVRQ7ji zBZ2?qT_4}W^|YE);r7;_;}}0jV~+G+5j8|1UU)wb@nyj4=qwtIlTR=u7t+WCAzFV9 zGcy|4u1aH>3S(&EXu?ZQ6m{aqCIGPhHGCO!%=hdG3f%46bTmthsDF2~=3iON!KEBe zO!8l!{8yFXoF~wSm38f15C3H)6M7fr-XF3-VQs&u1FHrL`H^?PwXC_q*+AAE*kyya z>lcT8iOtHRhldQuWDPIK)~)vh&trY?*NupXfT&1XMG~PJ!@P$4rpb1Pk%Vpi_&`gj zqTgme{Y;9Up4AN}N8>v^$06E^+monmq9C&n^r7gHx8u`|fyc!Dp||S0b!_y=^$=zJ z(bLhu9@L>-$nj={NGhf&H5H%K&XSIdi+?(y?O4^w zF>|LONO&NjsQCsr>OLmBZzk@L#W!ou%PfxrT!SgAGoR(MbZk(nt~nrDw*7xA<_ z?(tY*9F^3e=(0+S|LJ-^J%TW0AabcAgG14?t>SjP!t-^j=%t!7kzpGq_rt6oyJY=z zwZUeuzf9wg^e~w{BXP2LylMb=YP+sE=PpTR+fxZ)@QwO837!fttvHp=SxVNIuj(BC zZ3}j=)}4g^Y_52?i4eqPBX4kX-mIyULWwYv&|X=Zd*`j-{E7+v$y51-FzhotJiHCr z>tPSpW@d}u8dZESD!WEyg@B%lj#WQOlxcfKi%?76Z`#0z!QGV=ehrN}vcrGT1Ox<> z!Yg;u|EZiU#`rTmO$qy)Yr02=aS*02J)3RIoEtm!4H#Y!z{D6vNsWjK--90zL?9gj2Q0|sME0{0T5KWc=^!?hhB?``jm{V}1 z6ozU2jVyV84prJS5CQi1D#1SuB}Kuhc226>Nvl8;JzZUxCoz~h<+m<^i4;8tJ!{}b z(*-^y6Qd0FKniKAr7nMH4hsgl*xyTQm*0+vsC5bFKl8jGa3TPTykJ!cjVp0%O2qdG z;#2IHqJa#s5;JU33ekc9j6N51$^X^>o4o|IG&Pl#qlFG#@_jKqhYN5sBt7iwpAX*6 z#vwETf|35H*!enG=;PkEe)plWS8Ngv1_R<$d)1=@Ktz8I(^R_|$ZLzFmZMMqwe>HH zE!1!P_R5YGHcgN7xhpM9PS|E8%`c4cfG;_Iyzz3jz+gRlR7hf*YBbZE1xK{^( zB5VtTCRa@vvRKzoHQtKV#`BNpwRlZDn65T`TR$rwp!T^V(gB7sl!`a4-iTrfL_~P` zI1a`w?0)s9v28PNjpX2du5g>rIjvc0EizqGf|p`2;R0h zgZ+QXzInox@*69_++NW^`3I7f7uXvYEE*aTK$W(K&!T@`j#SI(A__~t6{f+#=;F+X zge~_b#Xf}^)&dcO15`zDm5NY{4yU-~Piv=a&Bk2A0D$3o{vWmPDG8TfOOR+}rZ<$w zj+N+}X6TNVG0XmnAixLoB)%`u8yIZt&a=~^K>VdA8w{#*rwa|B5XqzG_#}mZK~Y44 zOn8zg3=H>qb;7T3QtiMJY~$F0kH0rp@jJF^i;@YBfu=<+rbBlZmZuo-yl5J840PoJ+;9#KSVS9ls=fn`_+C+6MoB zX`kl%n1_C!EGp=)FeXnX*o6nbT8Tn~29>zw??qwyVs(&2x0xZlY&Y5Kq}|~+T*I-Lx?|)_6VqWVXIriX~_`VzvXco>3c((=k);JM%bL)2G> zwb^W42MKP)i@O(Sf#UA&Qi_%$#ogWA-KBW(;u@Ud4#k4IyXMPz&UxPNnqRRi_nn#S z*=y~!*E}TnU-Gkg6I>+$g5vM^s_Jj3hEXXnY_qASTh1sXI^8Y!&?L1Ssr3kmVHEVvkJ0ksXU~!%Dc5^x z*g;tO$69RswuDTv5ja8wYxgr+ID}9V$oDc1I58P`M!cNI34HRpQV>EBLnJ?@{(s6D z6G)EEw(xqIp>v5L0DzWa#w$Z)A+(4S6YDX=ajZ3vjTK(`q2HDU2^N%&)+%_CyZCaI zxr_Yw4*}%?VDRhbUv9XSYP%|5V{zr!JEpO_b@oxeel+qnx5rqD0AnJIee`8w?-GDJ zr`u#^i9<-w;oSlZBG%>B+6oCJz&rEATw%#DPN9ct_bYIz99;M?4rNfU(cWI6ZJYa! zY0R=+XJA?AM6D^akm7ZCZ-h`xpg(x35de^dB4V*X3fYr4^-@GVxMv6j@+jC?89XT8sE5nI6Z zWT|0NsNMbYo1|*GAxLYokRdfSWj~e?bq`lprU5D0^swhlUs>>Ssl=uoeRj@8kSGEv z@ca9b0}*Inp#CB;ruO-29RW58sSHy+R@~5s(Qta~2zL@3OQN=HaY&_ zv)pi&D7d<^kcc0daBvR2Ap|^*((3cH=j^q!QYYfS;DCNgx}$OAA5u(S&Hy!|&^2_9 zeDNyzsI>du|FR1Xk)8ie%$f6=?1x?N{|Z@BSLhAVK3x#5uhaFcQAX}ICSP0Wu#x-N zA6~{lnp{0zM=Q;oVrvw#MHGg?NhwR&9@m9Fo#t%%FE2&PTI0FP_V(IC{wnFTSrQkI zjS~iarQ~r>L$jn`(P0s`WJNE_dHxouOUP*1+WM+2cX*_2VKUW2X}Z7bo;(F6fDjAA zIJWGhgCEQppZ$(nzKz!FOxpHn4x6=;xdt!}!gn1}RYt(KtWUFG1UZCqL3XGG2&2+_ z_ttpFjKSmgZk2gJ3Fc< zfd(J2CSsa3$j=sD1Mvvz=~H&kSDUJexOG!&Z2vmsyX%=6D!chsv;AF5Vn-?tu8Bly z!5;lZNUOf?O%`0$oq;*{ne@RL4!@>n0`t~Q2n-Kj@fz`etg#<3-?(_*k{0fPQc4H;;^l1^ zFuUyy{GQMrp+N^}0CYbJH@QKU#)9SyqrEaBFVkbn=xQ_iGiG3K_YT-YD$U2|*knD< z8Mg9e{#Xff`}!EQ{~D&`On1NnI-bwkJ3eo2lhAI68MeSAP2CvWR5h9N_`ad1q#JE0mdH^*9EznY6K zk+U)#T9(CP6_-&Us!5FThz9!87!5pc$tM2x-n6#LN3~r36wB#C|3?m$5_kN&!205Q zxHrb6KP=QgO8u@zZKah0sCD`ie0kI=k)-Rz&0;UB*p_?OH@#$lsrYbt_@hcnz`;z1 zICzEc_;BEQ780@L#o6^a$5qacbiZqV{$da&223r^|6L->GT`lMZ5<()7)No30R*cc zh0&HfPE&b{egKCjD(0vf9l%zT+!|rma15vF+`72b3wv1`lL>#N2u9~ZY+T(6`~@(Q z?2?+e`#v|n{60oH=W{rW zc;teV6ysp1rX3*0CMNm#h%08DL5ou&0zewXRYCGWTIMAHu>ekRjFbo|0mimU?_iR@ ziN$Y3p`ZY0+j4gZddk~U7l&f|QJPqrrE7!GbbM&;*j9$Yyn6>2f7)S|SjBaXyk`-l zg>6eZmMpB323#>d_ON6o#$74^>8=t|StNQ@6ANt5OR~DI6z$G*s2BL(evRfnjK;wL zZl6CJytR^dH`t#3HP6#)dHDlviyZRa?t00H3bV5pQTiAs_ok$mwFjH7H3UcVc1G_u zpWwhId}X!H<9-xi=(k_$_cA+Mvm^z_^W*lA((`7sySsgVO&(wWul>nVqI`{Rlf7kI zsf_QTQ?u`RGp4{@7P+=b9aZ;HHGj9GniEamU*Pv&!3lR$GNU<3)h?eP!;p+Nl#yE2 z5rJ?Mmrrv4+mW7luK#EiDllGsN%NM5mEI!nW;M_C6UBPa_W+!D%TO9mtvy>&0#Z%i z1;PN9>M4Q=F?A_ReuyC<4<=(T*a0wazf+|zslq3#Mb<^sF+?WA%6%Nf6%)|Wa+ERU z!@s->GOBJ5-hRDmjD?cqLOSu>KoUXrM+yXAM9LHsBL-xN5yVGs&pPbvAgz7=a)4Ac`cBo;3 ztF`a3i1_|;!h*1{y`OlE`$D#?6J5-?MaA>0k00N<`PyyJ`PZBm%{fk*LF*m4-;&na)iT?f@7Y+L-{UMfF@KWb zv)@M5%FUm%&;Yx&x8?P{C&=4)p55!2-z};8Yb$z~pZ%iEJ>+a(Y~q1EyyJEKtkSl_ z=aF{Q;CVo}%W23)g1P1S%q~p8(Xj80-|xnW%luC?GVmDcm=XZ-`nDQ9;O1>SPk#0q zlx@g*$9+~N*tN6jM0{sGQIidUEPGw^v{oM}y>wI=oX&ey&L`?t`7~R9NhOG`8#iN* z7xAwR_78v`R-%Z{_%#+h!Y=C{zr&4;ERG}&KxE@VFtHvTOuXo_*jUu6X*|DO*dQ-` zKA7{-EKao<#O}Js^l3BfbUSY?H8{@pNc$H##4PTDgQYl+qd0xmj-a=Qp9Ze>;D)Ctl zBGGd0A!)9Dd2ED8l`g?%WDuZpdPCnWhS&s7_IBVxN?Rgyw9z;Zpx*GzQL{ba^iVw} zVt4Js4kvv2&{@D4aJ<*bMqo%!NhbH+()o#ASIv5q1rxWg^D+(RhLgJ`@I zz7T@kuM>fh2KK`K3PK)uFE^7OrSMd8qU;8pGASr}>==VnYV2<=+01!6CpvmxUQz&4 ziFFqQZx2c5&$r5kF1IBcj|X9KW*xMBo$4GMsG;~mcRjCR6Uhs|^c|M*R#Mq?kpPBI zQNpdSh;h)r;X~NQ;}fFL!!hcDEqY4q>z^>c=M(3ruN$qT01Sb~YpBUc1Cu)W^TYW{ z{_8He_qXS+k#Q?2a-WO!jfaD%K+Joj7Q}yDEfu~T zsM*-XEq%M__Qe2@4EY@M`(Dm=UuR%?--wH&KH0WhHr~Ik2zwtXcc~1Id*8YFo)Y*S zcHRqKt=b#bZ?=st{QBDPZTI{wP5A8=)AwfWyldV?@O@dbI0mo5k05iZK-wn~>Tpji zq+tJ^Yx_|5ENV?F3O(1eMu#$ zTIPQ(Q4wvCWi8C+BC&hHr23T7&ec&ybr4@Z?z~Q@nh#Jz1o0H(0}fu8_YdREO6Qve zcd5H?GvYe;Kcr;f#GMLX7nzgmV25~}`L_5?S1>QIo)a7JEp2euZz-|z9d>#M#b|>#A+~SyI ztUSnV;|1}uZRPz+%3traY+Ca;HzZu|BJ#Kfxz+cFU>}m|a&kJ4-`03MCDd4ZUDx=& zG+}lehick+O_JMo+-7DOLSluV$Ig9=UD5FMAp4NhYs}aEIHAjt$*TLijXP;WAi$K> z4p-^+{_bw$YM~i&aqjE0JZRJXlIv#R^x8kA0(o^?eH&Y+_Ip@f>GFDx^V=lYfB~f1 zSXGq#sK5eraf9_+CuT5z7 z-})VDtU?jsDd^9|LKqqlmH2_4O?npUmlBRcl2#&E7>{cT!UG=2>MusfeoCLinj%B* z%csF$Zn~Crfyyb*nYkfz>w!++f|wbTXlT}&f|j*Bo_?Cz1{&n*7H3a<$2eVo+=slP z!l6Dvt|o=PN$V#-Hjl^Mt)0i{CaK%YO^<@h z(Xg=3acuWf(nh0NRCUX@zU4lz^N#)M8lU^Kz9A(NL0`HA1(@J!oyHv}$gaBE>rl7f z?Xj> zTg(%1T+)ip)hKLk_PaN^_j%5Jeml$S?y?=#JitvI-PL3Do3%2yU-H>#dzQw08OihU zz1*|etSuq@2uL4Exlw@!5V`OZMdH_IaF|bKGtP7MrOyYEouNYw%u>3~zI51{oj|L< zBFa>T)*W|>&Dq{p>uiu?zs#wJXTJx>K3B2O0G*$tZ$H1j4NQ=uVHj}UmH~_w9oHWH z{Sf!9o6D~YPh|D~GxTTLw$6a_sl7Uid*|9?rKxh>66zYkNyLe{ZuUis zHO+~nRD~gV)O4lka>M%bahok&63CBqh!H<(*RfTrGG)|swEj~D+636c;B%G>34PjV zL0O9mYnnPPZQAH2dXo(S3ecOxZgkhN1r;|1o;7VWMXp$_9NfSFHxbH>8#SO?rB$=& zVAbMDmjnaQ&@I=fn72%k14=5E&U%l=ZciyeKiX*^odZU57cWrh`Ji2?sWDEs*d`zo+W*jk>9l;(Lq(8po2e0kmwzF&TR+y1&t zq}OO#R3*tB>zenWE$;y;_g`}$zhPPHu>A3KQU`fH-yqiMdbI0$DPFWTxEuF-ERD!~ zB=CC_HgGxRx*dxkKVN-5(l#WR?l=obkc>*z>vZWu=iYcYiA6l~0n?9uHh3M%d#vi4 zeA&74^7Ve4=iZql^Lts|uJO1{0bm`IrSn0%{l0Fvj9S&Kz4muuzV6Z6cHUN{l=ng2 za?V5ALTi?470@%D$yVMG8$d!PAwO8G0Su+eIeK+>^~8pL@@WQ;!Nu-(#OoIW-A^6b zxsEq;=!-TPxg=5dae7|6PbSi_wm$Rd)Ns?K7$gR5j%!!Og`;ZRRff=1Yvb}x`DN4M z*INzb&gR2s;jCiCv`}^->V|p5YL@ zV#kqOy9_lRPx1$BE&<|#UXNlbKl8P50 zVcDq5fZH45-VH}baA6_q|MDwN ze(v~Ig&`PKl{R?aqd;Z2$)+vlE+jP*g;16ZJF6EVvt$!3)l{-*+OjcH9_c~BU7Uwx zu+s?pC$bxOTACcM!dk3g>go2lX!?LR&$0S``dU;o%b>^zhTflQb#@)3iMy*OZelL| z5J*wVmyEb=27jPvxwo@Rww397d=@oT3{Z9{dI%QdAoaae9mQ?^X#<&UY+o3B_$_R7ji`_6tBGJ!;Y~$$6?Aa z65%27GBuj+fVWXv@nJ}1Kl6m135_f5#TG*PX`QtvmT+OFG^cy2DGYP`&o+457o%9h zK>2W1pbflVlMQhUt+5G?Gxd-z#-6PV_NU)sL)7aO@L>$4eXUIPAKC)lbW?Xda!tQ* zQhI9qe9wXd($A;ash-vdp7MXTQ&FVmml?UNfR#dRk{B}3Dd8W`T&DWb9AD@uk zN8EoO+dg#+ir3v|H`zy`x%b$^iO=452XTyhA9!?j`d{R1Yon4^a191$ z4JY*ked_MD>yv;JlBd_-xW@yc;T2&B+4g2wu~PWjRABwQ2&$+6dqvL7xymG7f0Gg@ zF{y+Q`5I`6TzHfBa!O zy%%rsVwZ-+d$UcPQt8^?%P0IQ@yGk{oz`Df8oM6WP7gP5iUh8r*oe@%fcP&m9fO|5 z;AY@7GbIw;>ew2RC_9LmXVDRP9GxRa`QjQ8(5lk?CW-$ZgbFLqd!F)Gwlxq`Ec4F> z1l@uP+pw$cv!y?M)&K#}yr=GcW;ye`&RV_BJMT@%pLJO9D;JM%l1tp*Gdr%5#b#Ah zxswsP7B%(rTSb!#KEVnr=&$Ih4NCnYE}BDs`X@4)N9)c z*T`k#VJg>N{u|)bw1qd?wm@*Uu)u)UkJPdxLx)F4&`l~SDe2NZTb+idi#*PPdFyW? zt1$jm!5gn|^7-qbFbYS-s|v5`oaoo8b&D#F_EQ+c&^2 z&3T}i(D7Ssx46*{*ad4SbHUp~RhsrQUvS?IX%B(+gj z*k)9}6h6L~;02%@b1Km$3~f71hFi?D>#U2V-A6=3r>#iUl$b>kv}gDF{Pm7oWqD{;thnz zt&QjT2$4J%=qsA5+pTbrZPc1xM;r#G>eipu+b^qruF=nuqm}YRWaeVV4zwcJ#S~D> z`PKf1i{d9*V0b4(x=MSGezp-7l3%gSRTC_WT>eo^e$vp#Tv_%u20+l2kS41EKZxOt zQpMd~Y}5!ARu|?6DnW?Nk++GvW|`auD#n;XT{#>s~_EFR=jU3p>pp_*fwu#-|`V$>pIu0Y}8>v zfLgaGk&z20RfewHzoukXKaz4-CK}i5()_!2*`lf`dQ2s6G)Q_8KZcj#CP>rOBE%P- zS(D8>9nC&AL|kFcqzGb`H*2+pN35(ubvIf!jKJZoWNI+cLHJ0wtqxOPlT=*DSUD^qL(Tr3|T1K8;a?kvI-J9HPld**8dpxl__pO>tju z*Bg=QPsU~ZISTh_s$Kfxd|TKbU$6kuu1vA4(#7*m<9&fEo9omN^O!elP;=6_CFul4 z$eE&0G`UU4vv-kpFw~kgXT>Dhsuun4-`*t<*zB#O6_}ij zXolNM=V*!i(NcZ<9G{z8Q8BGaJ>o7$%J1@W0$S6573VlS>FuJi&~4PYh}J3RxgG0L zXC}BmVOA=6lFql^nObtk?r=QYk@Zp$6l^*iTs-mflpa9&p)x+#*m%5z0KIS!f87gC83T6 ztd5))S+krr+k-Lvf*+Nmzb`rv$9Qt$<5WWlpt_LbnltpA{Y$xG{3yxq`O5!^Q`=kQ ztE>VyQ&7*V^yYVJ(z*63_?g%aVA0gVo8CIIPAn>CaE5zfA%@mBHAX;z;1z|ykUkiI z@Iw6;h&h*3wgVq;*Z<)+7KDCIzF!*)fM?+gZv>{qIx|7GP)$y!c%TEt!X1yG;pbrC zAa-YTy_;e3pxl{))?H`Uc}{}BgbS99QhjQ8SVYbml9!nuE3O_p3K_cgL95#B_9G~b znUmTR2`WZ?AwwD38k*|!Vg(cs+}(I6S;Tq;RnMdMVZ{?4=qOzJVYH$Ba>YbWn!3`g zoUf~^1A#zl<-sGDx>XBMAAP0L=cgw#GcyDP1Uhe6cujLr$%FetwYt z{(dkRytDJ&(9lpQFHVBW{fS$#L4yej4a>_JI|{nHh0{g{zJ2`V%Z^s0$Li+dQapPI z{f>x;h_|;l>(5zo#ea4k8F1BbgP(Qy{?!5$8`Ny0zrMbztE)fQxw*L&sDuxEi`|Z= z>Fn%mnHn2Ilf#Z1s%yicJv=+h&Cc!*fnMLtp|iF&0o9iunNS>>H1hp(7AYYiAvrlY zAz^w(#^K>1rL6Tz?7+7S1q5?K5|Xj+p9BR3p^yYSf}%!(276@x+Q-Mo9ZoKB+{~no za9t$v`=<=(C0<@$LN6D3Fa0AuY}IPz&Mq!cz}(d(wEE6d|D{sH^=y@K=LcHfQj3EL z4K`&dW!h*)39^v;8!zHGB0GBDt={A@ZlsDPo|gnoK@v22Q4SRg)#9-y$i&ZHT=ZdH ztNCF#j`eM4j|b#EJZ6yTTx27zd+g-JwupkMEf6fQV-I1UKAGqKBm^iY+gB@LWc0i% z@sJ2k?fC}u)U%iiHameYNC-ewV(SJP9cba-slt=7JV+yr6ybgw-BJ7YS{&RWE#yY7XJ8A-7CLG{e z6?XyQ7U|O#s?t<2T!{sEM5v66B8-?45VI&kO2zCigy%AOwK`kB9l|ZnkY%HRr?(S5~j(!50STW&GoZPO> z==B!GErjiZBtFJ8R$x2580GeJ^Tx-_%X6OEYv*P6{VHxB$XR=J%if^5Z(FBz$cDqH zf3Qg+bV2Vtw346d(hvIsM{h@JRRd_2DUB>7LyeJ0v^z|a?(dDu;KuREG6N+4c&x#V zy<fmEPwL4fgvL`7Vskl(_P0f}-;2C8?cwJrw*wftUHHkosY} zq7uZbAACrI%rfqp!Ac)d#4`54N-Si%s}F5ixsyuTr2Buyk8{_ZjBbxo1V@%Go+?=l z8<1cRG$`s;Y0osQo?8o!mt{!0nGW}9Ppe42?+>jtDdh&kz0@(#5q*Bov-OS zdu#9ZaV(r#BVB2@f2f~+ch=tM)y|yArSv}tbM$RilfOG)TgnM%bo4v~EbM_7 zS=j%rZa>%StS11@&gb~+$Qz75Y}YB1Npbu(W7mFbwK>C`J<3?^AtzCVF~Gm%u;K`o zA$B`hj1o=2US*%+kb@vP5f-)L{ zfzVWKf|<~VQ~;3yW?7W!x_YO= zwCM7?oJ&Vi zgM`6{cQX`L(q?lZ5#fdm^MV72i;)Wr>ltv$q(UEgc$^qspWP9V6kya>nJ)ImsG@00R8vXypjuHOPjxQ>l~&Pwx0-;bpU8H3oibOT^5lPBWT7~^3yn1p=@X`@klr6H*Xq3@S#6P9Etbz^_|Id^d zAXDR_6wG452kbG#!%|^!%XgsmIAo_VYj-_EYZ{QZX96|@k_ZWgo$7}!)ZDG5SX3^_ zjOF{Au`~0r9X@I9!C3MS8hTuMXGA(pHphEGal-7pDP7*jl?dM~N3QP4m;BaZYL1U( zzob^NUznvccUUkIW(Wv`BZ?9p_QWjY`0g_LRY;0Ny+?cN)B6@!f#CrNMMXf{Yi%%s zo*y9c$zN3A)7I2-JzA{BI4M$Oh!I&Zywx|>wK@|-w|ZP?Be@v#*AAC3yL`VNfyDTq ze3WvC`MZ7le}cJ*N&q5u8DF9=U3-*i=+f8lP$r_7qc#Jk6boNTRpYU zhNlk)OFnfk4U;RQqgj3)kn2en-6pdZs6u#7m3wu?)IAn6!`jtiq+ZUGiU>U~X969K zO;!?p@iw1#h#WV1n_;Obrs<1OZD`|D)02&bvu?)9vR`| zK+pb3g(j~V=y*Z3ZVG0!91GT%yX~l`vu4lp_OiW^IxyVScEm3^!kfJRpn|KZNwRY5 zW5|uRaqUfDJy_90Tkr^+k`-m|NGb&Cv4bSGUX#D{XqM?God_mysC-29%V{xMm8ZU* z1X`7T6lGs`ma|f|2!QXiK>!As@u}qcO@~k@jAn)!4Hq0Ls^MD9?w(A3RQi3QjnQ=B zY9Gn};_>^180kr|cZDtAu2-N!^sB2RVqT7Nk*oYnt7|DqIrBfGGD=;$2P=$+>eKwV zsv9}IaiJ?5XY*=Djuoy3E_shDj0ntV=v@4I^PH82{tz7!ofOUKx1a!yAwN*m+i-oN zQFhSR3tyh^u$s@83vwXppRiJ}&ReWN#z-0dLq@(br(w&hYIofLRH(;oQ}bFOUC*vBH^`%SuTbekTwtNU zonXVhKY+|}t3RQla+pf)9~L2R8+845HCe@iv=e^aOqO03tx5ezf0na9gww1pi*rZi zr{)EMBf(VW7UTO_NU&xzw7nVf1e2qgNFYyVxDJfjYW+n~9aoukp~eBHY4S5Ujxd4P<- zoIkqd1K>tUD$YWmT8p3D=TfZHs!TO~>@sA*cPNmc3TWPShvFGQkffa>Wh0fUf2D}O+RJG(5NxsYG~5Rs)Q|DrzVFQ0NGtJ_1!50dq@HK z$Afin${)V0YUc=KRX(d9;%K$H+uy5iw-yo|Dut}>=Pp+Ue^VB?yQnUWW7YSrwF1SL zhxL_IKiDwV@f)>@=Q|YX*I&?r9M9w5WtSGcCW6-u5B`sKBnYZ@Z_)L~gbnoyZ*@`% zjqn=U=FfFFl!*yjv*(HS|Klt-NXIebxHyWrXnRq@l*ve}6M#M@*$<3cA=oHw>}1ztqp{xI_NNWZ(>82;9$2B^rN? zQ;OZ!W{v!sYw&9>>?!Hc+GC(z^3Zy)p|kvCY~0TGYlk8w)L{a4`RqR>6lf9Uuvt&& zYM8nsEsmQ4NeG?ZS%kVj>LidsJliSpFFAZDP=Qq^bpQqn7z|gy5x7M~5}DAG$*`*& zg9)!IS&jJvpgklf9?U6%1Rr}P(TUe$*b&p9e|@Lak-_%IgS8eNyAOdzKr;-filoPq zZK_VhFpNIYLYfoLKmr$`<~@-{;;G;jHXWn#D|AM0ejCqj(#Vg*5Z%>@F4U{r!{hQG_|H2 z?S5pc?0;A!tooo#?uV^!CgzL?P7+PC-*-}8v5(W7NylIw3_G5mkI0e<#BYyC2+_o% zSZIIqxgE*MT?17!Lz~^>gOg_qW(9^M0e};$d?MwE;$;l2#BC8btY{}`dprN*?jR#3 zbFBRif~nQBjLH4uThDThC#Y|5=D1ma=E&ApOht|NPUKwoF`RnZC=SI?sD8!v3 z5{ZLXWDMgLx!6t(ggGv-peMYPN}L1%w}X{MK~v2XIzZcDS@!i7kV{mO6R3i%3&akLr&Qb4$MoU$j`pDGaVIzL~k>vPBkqT;Lk12m!R zwDuJRAMKC>gFufwJP$!oJj1(B{4cA@gi$)lJ$-wG*#3JnC;Xa4nlzm z8{&bKPrU-bZB;BWLlG0@l1%vRom5efd-M^BYhcCJ=Lps)v(Q#GWQ#$4@RTu$2Mn;N zxV#q*IP2gVi%Bc7Zd8qZ3rGIYgU-ErF{137C>{TR<>?q`C=!-cp!lj}Kk=vlw8=~k zY)1B{2kCrkKlrv!viZW_@?ZJLKLQev9y(0IXH|5g+9v-+0hHUgj$d)xl!;Ya3j}uH z^k@=Q5t+N9ADAeEaAKmMU=3Kqj~1-^Y=pIK0r`XQ@rs!=420&f`QfPd90y*=D0H~4 z@PZ$1P=bjxu@w*z{;XZu4Bj5yK9vf;{+Q)#SU#yY9i_P~{!eNgMuG(h{Fx7n$b-Vi zko~!QR|BMr2-2oDq5GX@--nDgknt6SVT70MmAUek+DRkujq>|5 zyK!x8nW@@oNaqHKlMGUzKUfzO%m&6(_!riyE#mpe-9GlDW4ON-sgU-@kcTmsl!&hL z^ic1AcuySyKr@UbA8Pf$hsW_$gP%b(An&1M;6p;F(zOK6nPVi51L3s5j2gs9fyl3A z9e?0QDFT%=`9b-bl``@mXC%&TwM!sGC^R%Qn7clx`;lsGp5Wq8zC|TW+Q8ub|ILb+ z{$;JOFpN_J%CFG`rMefY!Aag8e+t08*h6b}8h&D505kS`Zeg2ie*v}*|JHuL(SG<+ zhpj;5Fkg%6*PkJ*8tgDX1ClfmIOxP;eqx1g`i^u=xH*GK z@Rx$-XBul+i}r(tPH|4wYCUILpY^!QS%h_`%iM*0i# zI-0Cj1V3UA5lLA~+}o~BNQWVS@HZ}fJ{2EBKw{*?nI5~*Jlrbt7R!nR{|In996^u$ zs@a_;h=r2?E%P0z3<5?FB@)881(pEOoDw_JE%+oq&`7aA=Tt8kBZQYU@hibmTbG{B z87WP6Y2{m@QLFsFRmjM;EqbF*`mhJEwOyhwFqs~ez}h0-%AF8}Sv1O?LTr=}XGOdd zh6Ucl5rWv^;oSU+h7v&%jBTyH&00S5lNKY~RC=(v0mtw(o`-uL{_Yv<$FC^0abg(q z!zmZ)LcBWPYg@_t_&@Oo1wxsA&!1GkoOa%moH<;br@bKi#oDjl`=l6RqbUCaS)pui z2aMSfEY=@5-q0fZo?WoaT*y*(XqZetiLlS7oSOdaOAAiDVbjq@zR3+IL?8ec!1-cv zN_0E;u;kvQV!yha85$Acpu#oOR8m?hs>zkBX1qEJ#rep@+uQ1?rbVDVb7!h)Fc~Eb zZNmGKHhD7V%|@V}BMk9ZcYGc3^8AmY5WRU4vY_KUX}#e3=v4c|)zUdm#b+?0u*?R@ z-e+fhD9cG9^(psfyw2J6n(BA}m1vb=v=Hx&MQ43=T+La9 zS!*3FT4A5Xdvb$1Pg6s~I6KYru2(O($|mO@yXR2x7VU90(E&q|Oy!Z?iA4lbO86yA82W}!N#VanOP{vZ-SfUV7vjqUk-F*Z2 z$;Hn6Uyxx|BAH}(+>0o5YHR9?jUH<53NU?;2;aSb^PgJ+r4ze_@bxd~N}UGA!JnU# z@MZaFRIM?c5}NUI%8Czl9i{U97ndZqd4?RII;>7oQbN76m^0X;lTBr*7y74mjCQh$Rx(unZ zgA7fZNY5NLKrS#L^^bp#+Y61;0+cU$;A#_*kW?fuG7-+i-bn%P$>95~$Yk=hltqgL z^hG?-DT^tP25&I~Fi*0ge+LIRdEOEh~{;R#Mdin*DdXtkVpTXIs9L)qN)w> zpFx8`E)!6AoNv!^v8}V-B;hnW7T0U`h zGhEyjUi)$z-Ms2K>oj@dDhL@N71qM}IB;9SG0?WAa=IGl>t33o=Y5P0H8*K;e%$+D zNeh|7X-Cl3Z=}#&bE|jWO{p=M($8VgT^q3|U%K#CW=|GC7hR#DQvjtVH5OOHi<*32 zLnbGB_nSechifnhMhr#*3MSJ<4cmI+-{UF}=*h4oUvvy#WMOyj1mYy z<|}BWz3r4F?Sp9SU660UAC=m|xF@(V6zdwk$S98Tj%LIMq zv0@mi*$HH9cRk%2r;jXzFRwF?JzW-F54YUCRM@>@Zp!ApddVn%X&Y_&PB*AbBG_g$ zlDOEt+31;dlun?h1^55eFh_-p^LM8!eVgp1sbHO$?_)?_{$9i{(WA(zwGZsr5j;R zTI(=%N&8^t*n7ZudUSR)9HAh*aA(p;sci5kS(rzZ%pdH$Ucee(kriQO&@eODaN)!n zmP2Rs3|UhXHREP^q@25Jcid7ijZwqadyRN7?u5}}Gt0J3sN^{#agma40mkE0vaM6B z(s|T{jUgP-=5Nma#w7Z_xaBd4aPq&)N5ff?nh<%PG}JkMw+l7^D}EX0yB6L+6U*YY z{*Wyv%i=8nnNWYo)tX#G5@tv3PEc7DcgWQnuu|bw&An&{h&}emJ#Vc(hhqTq#FmuD zNcCNNSE}B_a8Pz_^K@Z$oqwq|Cv3CXbObNqmu2qjHf?+6ny;i*9D=>7=>x^YI0At4 z_+U_uZHWrZA|aa*O^!V$J=O4D?X1AyB)?L@d+NkR@e35`=!4%lXoSDv=tmI%`ej)* zhcTgB`o!FBR<@6u&u1GQF2{q7Z|ZTc&ZCXosVDj*r<(Q+kn_&zK#rJZD}e z9t?o~(x)+lpP1w6;hiU5Ma8$U;*#TryF?dyrr&M?;*}NKJek$R1@ZfBxuw(PM2gLY z46!!qf5_i|s=I^(W@*CW(ZgC)pg1Y#^vS1N?K$gf&$@^y%y5q13MgDQV=2ty_NzGR zi?VB~S`Vr6Vl`GUWd}Pcv8&()h0{ZWrHyxXZf2FCGYKoc|tE=rx zpz~y8;ha_DVL9WX3njRQr>W|&EieEckDnP2MS{YpaKFuh4G$1EL&Z)Uke-7ApvKIs zR!4(NvlqmiJZmd~5v4EK4vbZ$faUnwU0xAcffDH9bcw(;3IK#8$T6=%vaWyVP4?xZ zvfHChUW=#-ENXHoYT~A$?mb6VG~rk`p(Y*?6SDr?_Xst%2dVg4m<>sRF8GNIeh(vs z3{&?Hndczn{2tNeZQb^_s&sls<7gRJgK;m&-~FAmdMr%G_07qZj`LVx#Tzz}jm%i_ z-<%qI9&a)MZkv5e714sOl%flcJYTD_VAdZ74ou1%gD^4S#WMmoV!$1L%w~Ixudjw&K**edwyWMuu)PnCSH&_QaTk z4%`YTYU(cz{FY2IsyOn>wON7pleLYR5Jx3RQoA9RqkVWWd}{8PjtkCV^ZoLALm$Ij z1MjcLy5DBYlp+Q%d)PXv9{XQ5fLTs^DUKcq%q0!W6aI<4nr^h7WprywIgpr!LcS2j zs`i>YgEQ84t{OoSJVz%ZXLK7n6`ceHW?V#2nzpU?8fEbC10U+(vu?n&--R6_0WIj@ z*g|&c-74LE-1PZ0a20_SrjrGb|5NQO%TCp{8;;4;eYEP}V{}|xdo?je81!sI=+P3` zUAg~7j5Wc7LNxFH)dIZRncT^b-=P8fV)!(N{yhqBjUIwHB4Ee`DqiOyLGW)d zpTs~zlPH?@Xj|HksRs7>d}z-#z-Do?n021JYBH*Fl-H;v@ZVi$Me;CM_4+rpN|V(h&<-2@SM<{bTlK1Jm>8aUa4k88l1fBiAT=IBMO`PgY+vph=|T3JTMK_9x=o! zx*LHMN)##AR+>U3cs)VzI0E!-UvL%Ng?X;v2nMpU>$@(r|E&0dFvE`XAmm5&swT$^ zo}Iaq`zCeire7#$e^<=Y=Xsbp?}m=3BdViHRlWSgk)v_3tI+xSY02;9rW|inn^dsg z&w2N$Zu|L}po*n*vaGHv+%S)IzNX__QpxXiztP3}j&<3v^#Y@)X#w%@(_v%&9aw%n zJ89|#WBw1^|K$N`U2Yu@QFLJ>P?Q~n=q=2g7F;@YtJb0CCZQ6rMoUobzytiNJu@;d z_4taJz;H{k=3*w-BD6nrm4)iOre{pWUpuRhJ)J&teJ6}Pb{7g33q5TqQ0dQ+w67;! z1p3#)%xbPV8mZ3ItvYQaQxGC6j3a>v;U>96IIM7?s#2IIBx=MD^2R(Zu*zFl@5*{| zVq{ie-7IPa5>P{x$D3T(J=u+D8BgK2(Y`h)!2$VrQbHbPoQtC&cjiweihz99uO(Hw z$N*;TY60g1l{%dc=z*y&iVa*Y_V(;V$hUWx5+?7YPcMJl>s)uL@L)%wK^G3y9vE!I zNpeI^7(LV*x>%WBhm~$5h3D^Do;Ycp-Kgh_;4N7R4DzL?e(c|(lwz6Pdwi;SX{PrnZ z=5O?_`08&`p>=M}MI;XSC53|!R zm*^bfDZhD}4FRR-tHyM2W?o2dl)8R-#qU=s9O_|`o zLZs&v_AAh<<}a5J615TU}#E0C?1)t{Yf(3X*h$K`Rsg6t#N#*M==LsPto zU_z}F8aJ`^JXVp}EtOz#xXrT9r=#X!esmK^Ca(tnfD$e?? zdPTcMhbe#kQHYgaT(`R>3a0>dN;JO~0*)Y_CgB@Kyrids23VfN(kfqydcOjEd3XBl zFjL!DC%=LQI!=9`ztcGuPo1ez$Fuuy;C;$FuXZhSw;;%p8`$r=#sH>0#;M&)xy<8NW8xF=r!jw z;Kn1Oek77(xQw7;Qr{SiPvu*GmezkAAbG_!np+CJBrGVYs=>lg2%g=Yj)L{0ZIlz= zoIrK}kCDyki^^Y5A%ifW;uwghJ)ti6ilAiVK4_@PKF9+j{)vTeCXofDi#h$<4rQ6t zW}vuejL`X0tYyRN)gbxg74syY$EgOOIyyN~1p)H{X{44LWUBbvf*O#~o==?O4cZ<; zNPo#GEA^Zie)Znu$&%3No_qKoOy_Bcl8N4w>Ma^5KO3B@R&zwVV3iZ1lIC+Q*;pNd zgzmjZalyZB{v*^RZy~1!Erj#^CDt1prWKj-gPpG3bsTtcyM!ggo@OjqLs~$!;*WQp zGVy-R!@KR9uoc}wC?)~--%Ss460vHWofpQX(4SKiP07ygwO zPXHkjR8)034)-MY(agkzjDPj={Sutt+cK+)>xdpWlh&GFDJJw-I#T~l`cG34y|9#; zz^>aNE<(is?MVaIc~EL334eWlZ^*M>d&lB0YU$G9H1ZEuq~c^=2}&ocZPcAmgp9#D zws-H4vqOtabZqEwqKiz33Q~XajkcFv=&-s_p$%L$+@EV7`-CA7aEt_Df|Ri_DTqnWYn4#UWmJ2)-Y|P|Kkt!? zu=VcMRROMB)hnU#d-IAk9^Nx`Hu%mkv4w^!oAQ3L|g zq{BsI(K52j9)PxXC;8}tUQeVNo5Zq62YJ+GHR(4~deW@t)^>F14yG?Jg`eYH(aG|Bl>9|;>0J`-3EVtwpOks{-9_s89f z7VFBJf?z>&N6~?RV(*u2lnil#C+W2C4 zMfjxY6gUQ72&yKgr0hqWu&fb7jlVjSRtCmi#P7BZh0bI3~RT(OPNK2d`b=9Uo1K4|a8jM7s zMgYTY*xA{yy!~BWv5tV5G1M+ZNYvy1Y4$VW%Ghe=z<`)AN?)PuD?f^Q1P0r%tA|Ph9wPnDH*>~mbfw}rDlWNVuCnQ7? zHw|V`YH4hC$MrC6dP+M1I^v@ z;zAEo+6<45|9aZxsEfBLVi7a+CtTWDK;b&PcaB5!APS06HTGt=*e~98Zqvsa2AoNO zfM_i(;6Ly{MZXIRLbi|i>zXMqW;{fUd6Dk0j)O~PZ!>}GEQgkp;Lo{+8NuRBPSu>P zz7`tAZHZEgjGLz(hw4=9u%01j;qLy;B`@IVk0eEk3Z1#`_x*jK_y>s8F%n|_W1wGvVJwbL-l{-5sQ-HRdg@t-I!`ZarV!Yb@KH#8!YraGzmrT{N^KfxB`=LZ787( z;tej-y!O6NgwT@)r?Dq+*#AzkZZ*9(=CVKwI9S zgya!x<0@3WP%PBvZnC71J#Ob&6qst6zt7Z_mP)UZXI(Fry_~Inwo+mzs=8eN4;=85h3~#1sFRa@HOm3_b|7fSRB|spghR?i()s< z&2hswYt<8oteH3%X&7t4+l8GbM5sAiGH-${jEk&9ou&etClF& z_;EXR&AsWoH+8ZHCy(?x`}N0FWP6Xr;Bjae?TnPW%A2~N{u1$7;m$u3gxqx`n5Rxh zg}MSxn=S>*>xL(dDo7#5B8is>Kjr@gZ7h~Glhr~D;2kp%tYMlDWDm!e>#yK)&DqUabbiXXfH0duqh2Y#=vxE15V`kV|rtDkZ)pwEkZa6%N% zarD{tZlQ<)7!J;mG2ruN5C}~SpC*A<5dZ;qgbm6|VXrln&i?ej)G60VV9_5{Z^*^`zQ)Yd~ z>RvF6dnKqUURsCYi4`x-Yt!ebMzdC}TBFyfGD5*{{98iUL7=!g^Qf1BvRjQ^YWAW>7Qt}CZVo43~ zQT-kd2_43Q2Waa`WEp1?aE$^Bv}@I33YUSbWK$4}gHnHxHGg06715{BlV_Wno2o^b z{$||M1dBVl0sG4nIrM53{7fLdJ(=4+3L2w-9<@Ib6dW4`rrpx9`(slpXO@`JDG<7)Oq4(DVd>E=b$E@d2kHL7>PtY|XNJ3+Tq|lpV`hBU>BMU7l;-n^_hw|(;89F*Y|>7 zBFp7Jq2fnHMOg*?>8UT4ya>2p-D{A~WWwG0oa5q~GJ~>+i3cvQdV4`mC1C zyIl7#H`Pbeotadp^4B(0_U5ySZOqJQM`*4`mGY`BXNRJ+>}o&R2U&k|v~IHg4QI!V z*St4-?oGA!)xNRv>EztY@HSFE|E9VZ!Q&P>7xQB!r*2uf@JGOtAb-1&-^N%frog$| zGo2ByXaKetxUfx1l2GijkcftF6)pcQY*ZN3dD??TMHYoh6QbSpfwVsuQymaWD9<@Z zDL>6c2@Rce0-X{MVwd+bw-yYjc!_)fF_6pC*IlN@gdCjhfyVgo0TillesbFW75}SenJoavWIe4ACs%!S(eL0PUcs; z(FCW&20w`3-QH16DtYg9;r1P|zSo;;u^z6W4m&XI*A}mqs8M72Y}8(@I)PjJy_xfj zo5lG35}~y6G?Q^(kLtuNIx8W`&uasIooG2#Y!cC(16YXmhHOIVikPh2Ue)aNJa{R5 zL9)LI1Dg z%sD~Br$F7mxoJJ?0^(JL%?vxt_g@j2yaU&p|GOqlC#O46q!kMA0}N!3#Ud@?0B2gM zEM2%kByS_`;_yt5c=sh{Y`z8QY@AjqGO94>_ncq->&sO(dy|gF;*B+j9!my}W{ecY zs=byfrzV0Sx4(+%yfe$EBne>W`_-pS9{4>yq8kE6AWhz%4eBLIRkx7VYqae+*@+ZK z%(CrS3ZkFt(^zqEBpr~3WV=hhfsg{BJ)n!q?bUFT2pSkw6}eCx`8<`f4?Bz)ed+^W zsE&fINS(=TtB;w$Af7~Q)QAp~mXnNpelJ+c(Hj9)qPGpkUyYpK1GyTYo-Umid7f0D zal2j8F64EST5Oe}0u)pLDaYNA^;2wpLs@Ff!{769fC%&-;bvkKY2XSZp6r1WNhZ=V zovNU*GD~=rD_FM-{_BrR;$?1+7n#F(F*Doifn{K1lmBqLgT5xt^0kJdy5)Io{n?s9 zP|?{Fl#y9Rz@UVn7v#S+SOv-+00{4`!KD(&>+mB4F7+yAETn+n5#NN{KB6^?>;4Rd zlfkx5UJrAcw3i;L)OjhD6n{UDL&e2Y*Y?-exH^lLRq?2|0A=-t0Y|cPHB$R<946=O5I&A9L)Yp8P6kE9|>_4u79{w5N_|7<3B>G*e){k)1UxaQz3Z z2`q5OEmNd`n<8Y5NarSrMo=GBUh1m90fRu1j_$*bfBLmSOqInp?@h6)+;m{Whal~( z6V&@@X|$r{(KR*qul9pfzQSz|Y5Id7NyA11vciJlrO;%J;kVf4Ev{@OHu3sp=@GD% zd@#^m^RywT=dC#CImJ~FA<<2^VRHEX8Tw?u2-p(5pgs0%g*q)a!*;+vQI2}DS*%zE zNRmHIBJ?)8Qy7+f5oeFA zLhm70kJjwa$+t55W4M$5z=4AF37rNFz90S`Mij#EcDob6Ok8kiU{KR4ndjz8OnQP~ zVACo5vB>$vLQvmE4Lc#@ad~3IgGlBCOU{mP?Z2czfK#){aU{ zX4yl$7$Zfo>a>$js3&0nH;)kpCWHQuh{PxO)~Pdsn7I%>WFBcaF~!^pS@Ya7_`vU# zJTNqr_xvJ6i{@c(2Dh`mcfhl;n*@Y?1j~Go9LMP@Z1Gj2ksPBh5*RvEc^aOqn@od#Cj}8#tF{@_b2O` zln=j-j1LB%TE(7)?<0`DAzIocmO>vJa$Qpe4KP5iWM z&0*T4Q>`IKllI^*lpzOPP-h-{UA#4c^|rws=hAuPsKE?5>J%9q)ChAnz{2H{t2Ob~ zR}e1_H*UDTzTRJ`P=Q9iT#X5Du;t4~F!0Iy1U%G;zP>&MnluF(#tc;EGMo3tB|1z% zp{Z7llQepE%Xh%Tp$HU`SKd7;bY*JQfO*Tth9MnJ$voYFl8KB^iVRThrBh|d0bWBg zRAOaVJmNroNevuvlMZ^+;6BPjpA%TBTuruI4bYfo$Q@iiNKmL&YbY#A+%e*y0;k|D z0CYA0-726~1=34G=gAbAG99Mf{c-bV6*@r6IsfKZ^1o&^69;UY$ud+BWAWkCzKgQ~ zVEP5d4z3rG6;Q!`7@R!#4NwjBAsWTGtMgvSrYVR)9V)ZE?2!WQW$hS5rQ614-M=bk z3Z9;`J;Q7U9_&^AO|ebqa3Md*`ix;Nvq+5){Hc`CL%h_$!8vUA_4D!lL`MisqyWBn z6kOE8S$=*(;*V!YU=aPiyb5GEe~38sQ9#^HlFDdEoR^D!jw(HoJR5T;rbW+Lb8i}$ zET4w4&)x{DunYJIBa7(skV^?cEC=O9eR>(_^ThDsKa*iZPOF(+Pv8tfAPdmHR5Ua+ z3>k8z^F=sg2cL}V>EyoXc^Goz#Q|;PD%={>zISftZ6vYZ*y0bL`buhs!cQLhBKy#T z*M2TcP%!;l>w37Ho~B5X6dMW2)w>;=rX~zRFtjNUXaW8ji7J>u%~z~rhMmlMvPlX{hnf6?7G)?V7dRDnln4e_O(iy5n`ADN{&9eNGDAui zeFjb`5dl^9HT$yn+94H%2IXUYN!q=D&nVI-(aOiSMhRH{dy6MG)#{Zh%~GW>AZ-H| zNxpo*j|!Qj&v_@gr0N(le^y3k+kK~Fy$TROC>tsjX&S@{QpyhUm3#kDmuGy#?fLd? zC9gR6@7+u;!$}o`b=ET+8$7tRQVgE0N@IVlvtbUjCwnGogQNyzQus?ZW-I8rbngNSdjwRq0 z>~^7X0GiImrOe|0o4R5^d`X{sek2`2dH0R$@0uhy{jKm*Z?%n00Uza(@X z(2OK)1uh4Gk_&jBp8HBc+kU@(X#es`ERfaP^n9EBe{@gW=lJR-dQ)W~_{wpb6=@PD zkv;f2jEZ?YR4C%UPtgG-op`8PkvA{*GZlE4mPe6G$aA zyXhbUTlw13gCW1|MqRugKFXUQD)}k$Cc62+A1=5g?1V8R>}BVBhMxF`ynPEOy_Y;* z_N%M)>e@^nT>Z<88t~(Wb(plOHP997GUcpB-v-_iR&KU_`RnxeP*(Umaf1SBb>wWl z+>86&N~T>qiLc{qDzzZPeUfmHD=<)DcrWRk*y;ICL(jn`|JRm_{re_ttC6?D0ZYtI z_rUnw{JY+}1b)(WLT))Tg!7id7Y#Oh84bGsii6^uFOT_XaJ)akbkY;iWanyz06wzL}3*pD>2_HW*6ZKW+7l)brU~uc_A(B*q6qId; zreq)5FNd0F2xH>JGXj%PzR)5|DdGvVg(oIX%#(Kr%e=6IfSGPP>Z5OoSXhMgwvw|6 z3bXQHgNNhryX$k6Dgl_O7W9qr;B52xPr90rySG4Y_5@z-8Oyr=L)Uz1l=3P0%GG7s zCx`A5qdJ&xx8Jty8rDzgZF^JiHoEp!V(K+YHCEkkYcpBE9k%O{(!XA2e^J+3(#(8k zRskOmJyV7ZNc#2`1OFMr*vyAp{@w4KwY}Z5cVS#t^hfT6?1wf^dC29^wwm zOA+N!cNXwe1`#6rYp6+?5et}FQ3eY(`7J8m51L_16>#ewQLR1(x(Ch=$`aAcFqo>aI!?03Q9;7@f`^+*9Ovr(&ETEM_NK(K%Kg_`7FE`TY>WXZOz zS8O6W8i zR(vJNeHW_~1ctk-+~kKW&@Rp3x$IK?PrD>tnlvE&uCVA+e>W{(PxR$(7BlPi8;8Xg zCdPJ)gSP+fQCtJ~a7`#Ay5kG>%vmUu`6@8{P?PTfsgAz&!AOf1>Md^%75n(T2LyWvqXyF{wDeW>_-aCnd z9&eg!UW%~^hksGx!Y}n51f{`TPPsTxiim4&jzL^(WEg7v`@QELG>68@@Pqr8JUTm} z(5umtOT|!^ujF8Ipgf40M*LpjTO8`bEr!7a=C!`_ykc3M2`xS=LJ}t>x(>k`J8&&m z8~6NC-Gu!`O^Bbp*yREh9ma{MS{5DQ*`FpXg?i`<6` z>lVIkU7!sqpx;J-2TVfR1uhlfNAm#rtYb16c*(U5d&-jVXeT0Y?uQ7()Q8U;st zm|DA)3WTjT)Fdl~7LSev?8LV%#Xtv+vZR=m;t6cWi4WsfEku@-;6tYAKmcSV!pQKx z+<*-j$SGO4A7OD^17JdJ+l5SJmYZ%WzD;t}Z@&8(eiq`e4xsAgYV`R^XE~m`&|7hbw*5-{s3(=KJH>J>?*<*pJWgJS8y;{ z&Isd~OsMDR()qA+WVq=^KLqN~+)cWq!1*hMM%S0?sv1 zZ%!0%xl39y6=Jba6cijKYkFiF3AFoPYba7SIHAGz*|6A`y!ZBHZ}Qn)Qr?06uK`<- z-RfUs>cY==l-UMLtAGBs+-lTb}(k_yg-M@}6BrG)hF&urjsk$N3&-*hes zCcwx9@Ap2x+!NloYX^8#)Xa9$`frtl7mG7w@cG|6H|gZDTfGHMou04sIjk35{JEJ~ zZwXp%TfRH%A6mF299dU~i_?OG7WDdcAHB8Tcuo$u9TqgqKbO7Vdq_Z}u)|W> zoVa3wxt!Ob3BfV=)sHyC^j_#Ios2s!mMR(6X-v0BjfJ!

    w2z1Zph&O>c4>H4*4kU@Jz3z|8BBF0Vz9U;J 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

    X)JiToO{{qe!9u1BLgpzJCEf*IMKJbI`(jt zapXSD?{rCdL0orSD*?5`AZNSk3Ec}z;){@>WscfwI7=~g@% zKe;5v3MW&L57T;MDxL7WQrj#RMSKuRy3_d2p9M7V|mXM7F0H6l}CSiVuBWttFP;5GZWg!DdZ7I`;;1aL?;y_Z9_kOf~V>z(01QNt^G_YZgcHhNgTu{;Z zi`Frl#o!2UJ4}UQ;<3FZ}qd% z(t_(mkn^&4mMTcSUu7FDu6mRjhwX=$oSBsm>sG8)2C6XxQk_ZI-%CMAJ6` zA3ZfCKb*&UUjSxLHCk?lts0fU`TqPI_&v)He z5$(BNw1z=f*xx0ru>HMVglUf3>Reqh8@6v-LNC~)bqNO?iG!?qoMHd z#!isc?LeLRzWS^xPN8%uW9Ibr&Q%FD2j0 zmXs>is3An$ljt&Ienc*Ua?f%s-u*E|7UC`E3p4I!lg)5`mj^1j|9KQrnb&>!@|NEGON$Z0#w%x zU0tHQy#1j=*PY^jIQXB@Lizn4Uf7hJ@Y-5;K18+T4S)VYbW2KcJ9wS^keDEI9%C`Y zR{^DTx=tafPBcQsL=C22qj8`Jp)) z@80Zt?Qw}=V^TiS)UU>KC^(%FEbAsHKq3i59gsaIZ-94LynnIWuTc&cG^74-nK1AeHW?O;0Oeg80xP_>BVVe|ulq5r9zd(oRGk zB-?bVQs-6${H9t&>efNG0~)&F_-qwexsb^1^=*CD-@_dqDIFbKPePTSS{4hsI>*ib z?vkfVhloqWb0sl)(OxdeU;fZ`WZhRGp2!>IG81ABSX7gVNQ-Af48oPtco?^8xuIL^ zHt7^}?Ffq>q5%|%cR{>FWWRgwrz{nOsssfcOroZO3o*GR=4x{!p)pbGt$K}~S$n{c zznOK;kYMMy^uwyLZTY_UvA65#VRWnE!!QRvYNRO;*yvsYlX$ToCno%=!?(#^q&3-Z zJBl%pLIBdLo>@@fN$Mm($eNL7@x6B5sYqk)b84r{_Ld?~_g!^?an85fryZ5t9KCG8 zmwhQ9+iqcoh@Y_RQGRZu`7NWWs{fYP%WT*UnT4xV4x2$WQ5sv_-ZP z0}=EWQu-bCknSgb6Sk>T4U!((9ylR8^M;TS)9-Ka5B>X715LO>VN3j{=X-+n)qg}n zLy02arqajcKj?-rA~5V^VS{Np^g^Kszv*_Ioe7G<2kGP zMKI;s%OG0aSgy!Tizn5llmBT6<;hWOlR{iGdoYt3@n2}JptvSe*T#@cby(mz%3anQ zI7?FEtw{nPRTNOqocw4+la8f=t_WYVGF2F9Gn5yt+c`dHFhpmj0ybpI0yMj22N$1c zqGmE*0u44rltGNdi4kTP30{v2f$r`y;1Lakj$#a4eq>bLU}WFu0mfI+>(Se7I6;9c z-H?^rU7XRM0m}Rz26*sMVS?YXbAEQjM7OTXYlF0So!(`r2HeIZDd&qV&CZzn$(Cqz z9jtcL<%xL&G(SQEylk-%%XJz$zYvh@o;;l;<!iWu44ul9z5{{|_7Zq5-FI{rkCKM7tlmelA3B1i>yh&|{p7YCW zkQrXbB?>aKpFlFR1fvd6pi)u}#f*zs%)tKebSJ@YkV|^v3{H2 zaguLRCgO;qfG|k0T1_wtIwC^_@!==V%vCWtgHe7D`4it3lA;pp{v9yQ9R6OU7hs4Q zAz5SOWmxAVR9Wk-s)|K!kUT4Ii-r=67+gbGc(5cCR@dYCHnK&AgS{nqd))M)PIJdI zCx}Qh<3EPy?8KNB+u5p}9o1>!*drb}Q(>a3*28ewpbOKFh0H!UzKTxr|Yu z)s2XV@E1MdC%Hfy^_a`);+th@`pKJ_nGFLvwVSiv)_*6W7hnk-OetIc=^)x`KGnOT zjN7k6|9DCs4wQVvq}f!CJ4RM@f#o8$7nU;bDDWnKBEt04Fp;#z5n&Z6K{eTJTR=u^ z;a2NFaa8(LL4)F9gMi*r&ZS%2>tWcFjVxW7%`IEP!H1n^&(%Hhp7bbW3J2vI(RK3o zW-tyx6Red6qO!whlQU=0g6_ZoyI00sB#Vq<4|moob!jZ``dURMSpQv$CPxm&&49K_ zz~iuL=j9<*dIn~#WH?#H%?`_krc{ei!CW;?w0dLL*~Tf``#(G`CFUOj4sm_Z8mCqEhu0xci48xF7>v z!5x|H`v{m4I&G!u&|&*2v@e`#xV}y@bg3Ldr*WAIrHRWozr*}AwCg5bhA3;4m6W7O z?kv34dV6~#(1;A?fSx{bJDu+WcwEUA{U%<_(l+wl)>j=epF(ra%QIvdlG+|+3_6s% zH;cU3ue^AIlWN4vFnW46ewp<$3fQkKuaW0%?SlP}WV;d)m!9Gpnv6>|{YzNzGCIb~ zSL8xrQdmAF%ZG0&`1qq0G7}E$eIPOTfY}xSy_!@AHq5FM<&z5RwE6db2JlDRMzCRO zdu)o^Og3^!e;G9_DNShv7HWKR#0Iyi-|f3qoXx!Ff3Cp!IcKTepR*BIWcLwS5V3sWZJkP1Roojlh4r0}_1Ta2xexDf6Kt*l`kwHj-ibo=5O z6iun~vS3q>&GeA^Fj0b>!q&oBViw_$q{uVkt~gx7-|XNyo}=VXT*S>Fju1e6qu4ywS1;2d-m>o>83!sWy}k#c&8CoRG)XqPJ4TW${oKu0|;6>H?Ah{yp*s^ zF~(k}qPgjr>la95`c3NbFAgt8s*ghHc6|s~vRP*{_!?yM4e@qVRKih1WH+eF>f;go z7+yXqw7$ss9FT`hJrCs|Ff4Lfm^88AAOoR?*x(O{O20B= zLXgQnemeZ3$d5h=`T)@wKH%PZJn1k(U3*)K>+?wRPR%Zo%Dy1Z$vicZc8(jXMN)4-njg zy9WsF?jGDNxI=J<+vnszU)_}|sLBfud#}0Y9CHYK!@p9Njk6FjjB#3{Ad(v?C9c-x#pF-UykT%q10l)~7;?rPjgkMs~{RG82qdpMNFBNpgD3ITSe_-;-t zH*$b&DyXAW8gIfQivS?&CR~y@JGJ1 zfOg!37YioK88Le{uCXiy&(EKdP1&rpabc7dM$#A-N_%%U&)Pm|8xU0gSHFT*l?Zh; zWW_bb%TEt$cIUWM1$$fJPTs@Jx9Ip|3dGE8rR&#Y6|kzug+kdX1C(ROPN(4TRT!&9 z;XW!O5Ig4<5iHqL#CaASS};Kuv>+K6lgr0b2IS7AIjND8&N>o9Oy%9CqW=7`}=BEDV2^JO>cu^0nmD>3>%1{N4-ifnH-}hF`)B2vF063a@ zjH>|?mcU47(`3FKWT}6&YKqGXrZ>8>92E5c{pe^w+q9n~CvhMQ%G@MmnlcQVpzzrH zS>TApkvm#cDC1cm>!@`m0?v3w)W(N1rNx-;IM!Ay&=L_O1kJ>s&rY<*x5#F+)*)k@ zdYR?cp&y!FT6bD+gUC0)ls}?JAGK@0hc)EB9VzR9+r+BQg{Bjbzk~bI7oywI7KXYo zw8G8yX0TW9@4e;duyejYi3f&H-8*EiTzD)BRlYZuVOB0b20P}OQ~vE^=g%A%_;-+S zVfbg+LuAq;0?fmuE6NJKLGIHojYECJ2PwvnN-2M$wxm(b?>-c#R4?d;`$iJDwUx1e zpw*bY!Hj{wZ&LkL`&Wf|V7Fywf1x4Oj~Rt7fd(Bj<}RL8 z8Q$!asI-u1^>rnk?;Kq2OetgYC%2Z2`@Fxdwr8@XgkBcPQdsm2nYwP>IQ3S)oofrc z7yL+bJEf}XU~6gNHXc`W~64q6$qo1u_z9JlK6q$remMKBezfn-)%-n|LGHUWNNv&EejhuY&r<_}k7aO|Y`(A7li3L0P1or1Q?;sU$GCf^Mp8u%@ zG`ziwxyuyt_q*tPMKqyK+Q>OO!&IuW{`w>Pub|S^;uiSXUG6CLt8*=5B+ZO=Z;k-R zM^o{tufZt!t`G-MrDVxMgi$8d=iSCokWn&ns+))tcB$C-w)d>RQ$Iq(nM#Yl{U8VM z_m~twLra>}a&Gcsm-RluCdiC+Fa0(n0;T@JV2S7rx_H)|Sz3w)zu|AM&tRLcR~?Ve zO(6AAa52YNDTF0Nc_g^;C~rfL8WJl$@k}o!N_Wu7lS^TajXFaNKH$C;owrh3oHR6e zxGBm0V!aoB6!HpxpTResUH*3$pv$zS_zR5nP98WKqv>-$QKvOvwB4ijb(2c+NW?Bi zCPApz$?Zv${(qM$9UgyBN3 zvDHojtu*tm?V+QJoR@YX)$5BPBdUcuNTHE!EvxOkEiH#lU-6P&pCzfvi#bqbtlKHD zAbb?YP|z&k!UjIx5V;&q>2HU91`>j&W%I=)eF%`mwtF;L06G1Q#z=jRgYOebm8sI- zM^R*ZyRj0{Fu5ZLJQ0ScA3z7P#>~b7jX?$@uKHuOU!_W*WPnI{v`+Gwvpd}CQH6FG z;K$%DLWxO$zsD)8j=beUKd-_tAEnU^2ovF>18;8nETK{0MI;s=Z@IOIyL(9_ktzHo zd*8AT(o*Z=mwP{i>1W%`EpkjiZNg4XXm#Nn;o*VJ-^3{)R~eBX&g?jB3AEl-dEovj z?v;El%2y_%DNzOlu0N*q!~1~8bZqo?gPL^AlDsfaltmJl5el`zrq){97W@@srn15? zq?nv$0!K%9;86O)1! z{ug5mrPb|XO6*)}R22L;Nk|w;T4a1cW?^n1nr$LY&9XFa1H#0o4K~0^VqiC2&Q45s z>FWo4tT{>c85C4#N!SS^Z^}@~uc^C#d<`8wzN{oUI`u@IhTo8)(fY`BAvM4*{&cY2 z9Z>z}+E!MH_4z$rWP6?8UQd-8`g&XYx;{0`;zhP3JG`%NGA9!;L`Dh<+q*i}=^2?6 z0AD3~>J$9!#OSAGryKed^Eo|Ms&qHH=2!Wa4gUwdHQ|g=?(CAberyqnmw-OJvf3g` zdKWjsU{`3bDK1h21s^K|v`#uz zA@Wg(2F~E>5A3r%tAjW#gF=e{b*{+*+$Nnzw5sA3$^%c+B?T3cJuvh3)^*Vpyd87< zGF7hrQ$dmJZTO)n=ZQ#{ohvef-MOf!O^PMc|4b*3_w{MSo7Ag4-SA<+|7B9;@_Puc zWx3L(XN$65JjbWL%H!FlW6AH{g{ycR(EiZ6uJ(T^tMt0-_Ko?ShRo6I+vGaaC9bHW zTEa^6OGF40!66dD^WXBZr=!FJ)jvW7Znfk< zK~qxnT#2c@Kp_Z-F@Wq&Cw0V@N|7NB88MBbh_~~X{=7z0s%g|JzN#v|lBMaB&0+aM zF9RXu6%<_E-Oz8&E{dF?f|rh_I0V#}hP9xq~D0M1lJ^qA8# zrP^FZfQY;5NE6zKiWX8$Vg)Ee0Gfe?O`7J*jNl@z0}hz*%<%8O^7}OnU_~AURCcy@ zS|-g>2v={5VEV!LRn8;U^eZyZNU-^v_ClrrEUY9nGQS-aV8M2p0zhs|j88osAAuHV z#1jBzGJ#teFs&Aif^x0n5o15{W7%C>QOF+s-M0L~YL&m_mAVg{4elf>%#^FManiim#huJ6sx6c9H8VQ`;;xQs{ zgP164e^m8;x1NK63PkbojJt}N+?h*478c)0$R$S9PT=KCUjZ~anlDC)9!w>?wG;#y zo;_N_yhqVLJ>0_NSiZpHFiAfWmP>9x z37|!Qc;Z>0@+)$y(3yE|F?fq|CR6wcpVC-3CPEnGvXRiL!J8#AB*qIvV?mYrnsLq~ zO}PggSZ+vR$jdLd5XfRT-x)Y4dG})#LWe*`Mh0(n!8nC&XI%^F!ppIu-QcOkd`sp3 zfy=N>mp3pcV%XV;%TQBzqqHhN@WaLD#-pbzEfd7f0p06=Amqz%rp;1mWaN5***A^6zEp~A-L0RaqH`+!UwdIF!YcEaM{lg7{Ba`4jUDaK$Or{v)2vW z7hMewM%DRD1|>4|8vD7)cC9klVvp@Pab{$trGY~t*`oFu^u*mO)LPRgE#Sb2%IuUY zgoTqeFCTaD;+6ABNR6*I6Hey8pZZrl#;u4{RXl-rHKOns64C2wN^cfa!2o%F6&>0e zPqotzn?Z2^eSfjM_)zOMhF#-TtNf052hgCdT)SH|11w6Qw9+RZlZ`X&XnoM zqW=^fvl6SwT6lcvJm81`s}J?k-8NIKLQ*U;=_Xvy%F45OXmdU}^#_+;sXBN&mj|Y* zBCU7$%5*qxy_Ah%E#_Ji3%0j8URrmkL}&QX{lp`#{sm51ds{GXJ}`XyCDc^-y2tk^ zq(kxUKf$4wgWZ4@79dZ7{mq^i-IyNua0GQUAGWrPGDx7RJJ&; z8(mJmnSmSu{<$PiyeUX{MbsTe(gZ;gYT{IhPk_M4gyDJi3IkU1h{}qgJO)M8#V4^+ z%y-D!*1x;eN6FAJ_aMZijg0h+D3W#u{4N|!<}8Ba9Gh5ps>^FVI5dyab(;;CSXe4{ zTiYn#_iWzFEKdIjf4W?^$R_art)*qto{`o67bWN@LB57u${b!3vN0*7R;=F%g!|}{ zE*vwNdP=>H+LUjva!R8av;u*=77dlyCabMzCIxENrNuSb0x^JqH+gN!AT>_ajfiua zp&s4Ej++@d{N!)k67ovboa;^oDnM>Ws){1rBY5MVjuKuA*y%;h)mx{ zSfPy_4I}|7_)+APD#j!?^g9yIKW}Annxh#fShMVDHDY9bHxvcSz|*l37|@E|{}ihk zOR|{?n;tvS|H`8FcKLzs{8R5UP%yt#za_P$n&mo&9%e6TRIlIQEj3Gpqgm-gq#vR3 zLelIbn1Zy-;!3Fhbl7&rvjS#%!Z^EAF=3!XdDkC|ltHJE^Z-KM>%1*{cLz>5i0q4#bTB;(%qcPOyon!j@EMSNiUs9wXH!A^ z`EA0*sg7b35v};|cl|h~5l0|bm5@@qM@3KaF(vgJ`=e36ihwlZ+~FNa7c)qo=7p|E zL41aK7HEcKL4Z#rf&w%61ZSyW=wd&^3mdITr_TN{SA1LIscg%Z8p_0a(ZvUP_yG|* zREYvwEYgS?aR%&B;IPMK{lC#RkiBF)V$@Ahk-+(?5s#@|){QTU&<%gEE69 z>;0O{d^L_$`nVUahn}T+xsCdOtuya(jU=5Ao{R8O{{K&<6iz%|stChFhz)_a=QpLA zrid}yo}FfvusnAbM^`AoTG$@49SBfHv_e8*$+ga$3k9xDenPI-jE78Qv4=%j_ap}_ z&^p?5=eA^tl8WJ67$0YG6&pD!CS6KxJm^@aA8^v(Ik&;J)}?id_j}w$(_eChh#Hxh z6@k6#eI0x@ulqHAduC7On>d_saP$@qcKqd-gL%pG#VrYCgzNbCn}S%g5do*LRs$qi z#OeZtMP8#Hz`CR-ZUX!X)8VHNKtj+t8wP%~ZK)s3tdDtjoKg^_QLK_Sw^ffQ8mg7$ zz#DF$QAl7&$ti2in97ibd~ufR&QFNMMAhiq6S+lN&VAavX29jbNs(x$+9xJP#;>Az z;ANn3891P66^{jM^GTHclPI*av3?0+0)WzywkcMx|H;bsb1ln7Q`3K3fcC%8k9%ij zTos1*RSmA9(hD7C&ligWd-q($oPvUh*u;pF=5O7rq=cn1#zA%U~O{u8W ziZcYtph+ zuUlmx=9yj>acZK8kOdAFc2T8sQ?i&?>pVE&-S;Yk zX6c!^BH;mn6S3pQ^&`q~k_RFy&;_iJ(4i@32vLgtzlSVp+i~r_2@6Z1ZR)eO6$E>? z-QkBAZ{cls1Vg`qB_F?gg2CJ_uz5FDxUBtckCf0u|4yvDAzzz;0)9xiSXul!biq0W z*rX9mBE3fIKkx8gi$cGr*&)BZngYQFt$cGMrbA*J87`!&(2>NFs?;fl_FrBS!aB_f z)i7nOOfR7`Ont%quY+Bk(C|Q&Gd5`!hG*HE79_uk?^W7K%htH0pNH&(6##xLfMMgL zCl3!7N0NU~WaSS(^0n-VkcPzri01PWic$m(vSJtVpW`D$b?V1yvw|L&Ipu=7OFKWl zDNAdDZUdkapD_-ZEPVpB;bHbYv+uyVvRcE?V0d(uWVv?3nsexf;ykH|;>AlMa5wgS zzu_?K22z+^zVGL}==YY^M%-}PooT=s!7^*1I+8b6$p0oK3loMdD8(#ZbvkU(Jd6S@ zTv`(sPR6<18FX6+%*p%1`Z)3BTE@Hrg))5Ypv-U;(QAI#$h$vor&y-f0apW88o-$N zf5c^~Q5WPRjk7D9WDKjrlK z)T)aLvq027fcz{_VRj0lH~yP>>g#f#DP^dOj_jGrKQgQnMMJfige#aSFUYellQP$p zXoSMGUutNqIXwuZe;~4vN)XMBqX&FqdVD&qY_?6quwVF5`|i2qpcJcHC+RbG{ZHX;Vaq^J_z&1UJ(M&gh7Sp?{te?Tq?OLA zx;Wf!obnsL(04dGeX2LjKZJ;&dfhmhtv~=J$SA}Y1Hbs2J%pp-X&Q(G6ByHTke|c- zq^A}M+RrzFL~BTtLEh8gkp_A|)Q1|_0*7Fe$Si>L8r--1t zYWX^cQ(N;m>SQxMcEP4+d^U~KIT^BQu=uTOx*yFMkojn-${?jhV}ft+2$8jD|y;N;aLn@fo!~9 zS1n}G=X_V)(C$^02dX0vw@p8knSi;hJk8MuX@8%k^HgO>CcrHy zbbA-O+5Tk8_DJ^jz!xj@_&7e;>&(){yGHc>w8?xyy3)Zi`*70Lk`N`1yV1GSb@1Ep zb--WH{d^^{>t;)HBlWFg^O;1QO-&AbU0dz&1h!`*ATT<~Uszfh_+M3JXqB-+iHS+V z-xi?$I5@gs5PgVCCq#&(j0^R>$vSLFvjv{HVq~yu(D5>bw?Hm@iSW&>7lY~}Ux=Xl zS)z;p4(cJ2{vJ>@8-!d*Ndd6-uaO}Ktau?#kWk=9gySjjaGT8~LwtGovn5VBZ3*NA z>m9kc$ow9*;^V=LSa1*|Sdam>6nkPnS{c-76*5`b`{A(W|Dx3biaj6geCV)H35K4| z&ThNlt#>bdKkDkZE2nBR+FJ9nucSp9$-eQGI{!7Ma)6HRh4}^cmL?`W!T`;t>F|jcBUOOg(;4?m3ODvVPd~}dri*7VVGw+-77sh0&--$y1dh;!++Lp6 zw%6~;hA;O6(Q5_hq#YivwX|*Ti-LS;5Um@Efzh`*))0Q6OC=Kcf4dhy-ZVI{ zVNV{$ym&6XeFfAM40Li`LWX=zOW+JW+dj0VMq#0+_lvH)=u~Nt3Zd||IAyC4?|q;x zMrw2}ho6QItAZ-2y{Wtc8^DLkE*66x3;S9eB<%H}S~*G9aWq0h*j&$wHDmzm=8QXE zG|uxBVm>n#k$U)nLD?aj{b43Cu1pdbNPK}=jc)XGLqiF|Pu4Oiu!ZMIfnJ5q0rR_Q<|)M}?C#8* zPLjcapl8ERY`{BUKCvhQTK%mkFM-1IGnGy(JKC&Ld?<*BAvohE^u8JZf=Q>ElEh3%vNxtRb3V+tA^K@3mCjDPqAYltr7KI zzYK*3yI8Du9L4P~5c)Y7=IAre5ypL!jEXZmTmf^_C^rxdPJLFQRH@)Z5mPEkC`LPJ5&cA_Bo4M?(ZG(>$H;q&kluBVb4ct z2Kxkss7Qz1)lUIwaK%esvoHe7VELc6-)+wNz{@VmJTZ_Z@gR@F7;pV+VuE8@YEm~M#v|A6>5*!Ywd?ju(iV24 z8SU!(@XcI30pdx#soA*~Nz`_4gkcpo2>fOAkY>QWc1BLuWJo!_``OcTUDY+0Omb}# z0te(Ai#wBh0QL7hrPZal$KI`KjJl3G&tlb~UcAA_=(Tv5nbf6!Td=;oS!OSJ4hy>? zdi+A|Za!)xL+J2J!aEzL~lAPC<2@Svr|&G66p6X9)WOT^%HS1hHRkfiSS3Xz&sdE)LtzH zNe0kqaI?sYu!Z8`XjN5lZQl?Xzg{_aUz?j5d>Di<@_=56#!n7Lu&`f+W;R0}{ghx8 z2T6+G@Z{{Mt{ev-cC^v?t&9hBTkPE(^%bJkyEWy&f=h0G?O3N)sN54HGSrtrS!-{@ENEanwE($kc-8JM*XK1mE>!m5!<=c!<#fCz^H5N;UrV!}DVU!*oOaF*B*q zF!->skanw3ezHL~)Ol;phYPgjAAcdqdrVlTafbpQY}ZU%QAmi-1c53TquI&&!Us(B ztVxX3Ul(&#v6==0q1yRKF9|Lv&}cr((BgLF)kz^TyA_uRWF1y4j0(>NA{Tn%_QKxu%VRwNg(mZHqg*Xv z#K6HrV+qp=5m{DV5Mk`Bba^5uvzONBC?oj1FmPY(F#|_hF}JHqb;7_VvP%6Aw1*~M z*(np|3NH_=4YfO(jgJE)ohd6Znh-Z;aLB&Ha)QxV&1=w6mk6D4j{HN;16|vq-c)R0YWM^b$L=<47~h6 z!3Iu-d0{^K)VQ~F8r<$g+TlkwUVyf><+%xj3{TJ%%@#>~U_=6IJrqrw1tHdO_ihq& zu|esD)F@JV5r#Q-8!S{oK}M7&bP4M;0*$XlF1`+}9UqfVb=P%2)qA%6kqO)aLPme{ z3OFEkRFr6*`|-X~-9(w;*+u1760F;5lEfYvl-;~cNCOUoT}CM5f;5iwkE(ycom;^g z9Ma|GuIFm*paMEwZiWk z6g|?kru3;ENIu@=12Db<7!=+eIQwWhMSZFRlfxQJ)vzlO1mgd#ze-FQ#)+pOVOCVa zB#=C5pk66mHRa#KM|4yKp|$gZ?+#c&H|LDK1qV*YjP(44-@dPZe5IPDGonINt4U1% zmY^}B%y`0Kx}pOndwW>cQL94aF(qQ-f84i@SosTEsGJnzo+*i=+iBwtLe?{pLBlSc zADN6#ZA;9lV*HW^D$aOHb8-uJ5XLwFKvU!8!!X5pX`Y0y3{*PZg$UB^(-mLAoSPa- zWl&UO!XU7s7y}_nq6RFW@R+Rt_jqoC79$>5atgLyl+|hr*%sLLeqTrKeW!$>1$h}& zJ$E)vPXpmoP#LKYOIJacxm#is(jW3vU+#a@~Et?=G>}D4r(|;I=|GH@bugNhrDg$a}*(TCq zplsM>x&vyeP)+8Fi@@nTM%#=uCukia*6WsPKfnf7ldi?ghMhhQc|>{Bf!QrBkAc&# z`V{w-V-7>AM;&cahW>lWmi+n821@VJ;)@ml zdqp3o#>2?G``tUDTU)-I&CJc6uJ5#!nBz$fqAi6awSnRu@qG}ayc;fEje#_vM*<9}p6)I}#YU2LC zIRd@Wc-_q-qDTzB-YGUK{IIJ=PT7>cln^URw2*jGeh-rRQr=5GC6HnODwMGl2T=u` zilny?Gd)T-C_)1E7c-l>(#k&lod{l3_ZQoQJMWo0s09E;u}qn7scs3svaO#AT@=x6tjucBWWXKm&f_GJ6!Ih`IiwgkZXI{zJ_0{2a>PWPJzyqvCQXtGaCih3U2 zDv@`guPPVa!mhrq#>VE8`cho`#Z?Ba3t2~euKPFJ+gGEbI@E+&ErK?olw;S(MY3Xx zKn7bT#-Al#UYj0grgBa>Xwj+Hsi*(+kf?NUkW!qY z!;#!^f1T6R_u%jFGKZS3$*eD3JC}!@?9ntoy#ISTp$$jB^WA!P9jyaLpStC<+?%P{ z-{VSNdz{XWf{2jlDM}<-%!)zpz^Rz}Hnaq>ja>KG=9BS#ZCha1E zR&A&<%`dwT;RSE*n?BBUoE~Q(mnK7@@Xybi4})AnUKd#zT@QP5EM0Hsx|`QAnZ*A4 zFKMbnvC&zAJe+PWrqrcv7wxZ`4Lx}_hOKVfb1isP{CJ^T@l;Ya_N|RI=L}8r8xe_f zj#k~M!39IvME?5&c!oMz8EqbqqwEKhFNa|cT=1b`&x9BHU7p9|X+41(7C8d$N5|I( zgNi>HnY*r5PNoM3U*TgDq9+OphJ5xC^xeRTOZwm(^jqVduSQ>j@`Zv(Mddr{CI*8b zSQ!Fy#UP*AmV~;k1%K-Q{sjNRh{hi`?Me5L#2wQc2sx{VWK1Vt3ksy(P{6|i6RDa` zgb*(ZiSdPy!?db>R3LWnU;#h#F-Xw`mD7uV@m;iwturC+?Cca26woYB|6C{`^IHPj z{#_b447oRQF0^}9RrQyM3;7(pI<&tzJvQhP5oKT4SkELFE$pkNw&U*exl_+Drx9vO zc(uGX?_FRU_%plePcPHmqk%z$e~))!vLNMVr?0n_6+Hq}PE(Q+Yc# z7WUmkP!b6;u{iuAxw$c-7hL0|v<6eq9~kiwb7u(Igl7uJV{>M}Za!{ZZ_OUe7{0P6 z8U}tuJu$vvQ4Kh!hn{*3kchoPk)EE8)c5822~FwxE`y`M*_~A!?15ZWHL=WzJZ1|*|$}$4TzOo$0`x$Fv9_99SQ@&`(Q!~*qWXdoUqKBA#rhWdjb5e zSB2RqABL2_$M0}=UPu{9!;+RCcxtDcchlqvHLTkU`8@m?O=h4$JURGu!p+=bpm5+y zyoIrcsgdMy-tx<}$s((3`o|(^hG6rbwSm0CZ$WXXETDeHi9zV^o-NI?KAAGA=_e;ktZU$#vZ&hH zj3!K+CXP&&!C)HQzb}&s4((IM;z4MF?m*&)F)1&MDaz=6$TEI_5=nzqp?4O8clumw zry* zf;MC&>G-@5{roIu@V3 zvCabt$Ap25>qsJ*`Xa9|CE~Nlf~m_FZrd`QsSPb1oAUTPNqh^D4#`zLO6|(xd^(v~ zZYpprr!p}^QDY;gO@lDKgWuJ8@v8fN|Cc3uvlvZPd%mb3a)i~&q_tdw)wLx{U~o%I zi{xZ{XZFg%VC&|g%!+QzkH_p)>!$GGdmC-SA$nL>p$OwW&k?sA`D5PQPeO9WSNyRv zVdy2vB{8uivAv%k8@Q219P5DE+WNZs`Ym6!dXHy<@KA1mYTuQKL$X!U*Tgd4S{1I`)9`U+H*3>}v(BTQ<=e0gT!*raS!J?b>zAhv_sy=SqOp6y4t9?h7l+*QjmOhb zO@p-+Eq?%OO-qY`%^kP>^~+Mcq5suML-fOTNF75tgU!iVbA#Vmk){S7slqSj+dCND z$~#GhyZng;fU+W?S;Ll}zme<7+|r-9xu65nPk$1}?G`e&28}PKhF`|1x|A=@h_pO_ z*W<}mpBMa|;T?pY*B+N2=L6q1%&C@;RukPX?CUd&>ykJ_3+Bz5G%~z_?EG%Vj()fE znq9I**z24**3Ogv)c7z}4NC`)q$KIEy5zl1*`HQe#UH$}FP$d{63jUQxKE5}poT<` zk$pFZ#6$7VqT@ZMh05$o?!u~BAy0&-6(cW|5u#cT)Q|Df!jz+)#*_IaYa6cnVN!_O zm)QZw*^EDuW=MnN)>T`b860N0-*)>}-~JQ{y(hA~{x0F-!aLY}98s!z=^0aCdHEe| zm@VjhyiT;}@3PbPmj3SFw5jR0Q=rSWPz&<75qFr4-SKdAyjDG$CaI7NN{-4;eW4q_+&H2P?AG}e!KzJse6URpxoUu zG5=y=sd~&#p?0x)SzCGXdjI`rc)Dl#XvA$B=$#&&z0oPGptP|%4rN`*QrYC?ZLJ&b zy?-;ZL)G{5L|$crPanJ}wS{&@#+=6Z_FR~1M z@qaw6-4v)E{Az4k;H2cD7cC8ffFSxJBQB!$W!-{B|MG=ey(3Z;YZpF);o7Q0XkACW zGd;_&Mh2yz|huE%C4-*bWg$h>8S&z+}Pu>*us&?e{M7Twu!&K%p|scoc7H2=+@V zN)(I5C=$#db6_dD>rcZj#dYe>c+7fJOeu3lh*|0BgoMPU_b5P{U%R_W2cFr6=s{k@ zjXOXa&Y*vum2=VsPt2+%u&*+DPJNVOZ?PV}pxm^8&bn!}QsZQ$!G>hwi%Xe_r1p37 zmDm%XWvhe)Cz7UF`;#~%C^X)FC=x%uej)|S1qnoe&3-_k$(JyvZ|a3b1Up0 zyz3!@{nVgCEVbJl!;JfJ=pIL%*{l}35&jC{Z`br3pWK++FuB>Lk|KvjPpu7aX(`>=XoZc@l0#R2%tV$J_}noS*k@tm%W8O?m9 z93iT>#g90W1c5d2lMib4dlJ0*DSRsD_L4EgamF!T1_Er(>a-~FXI0oC*KSZ2J=9+upwS$5&q%D>%*hQ|18H8@{5He_x> zv6KqFl@7fnF{EcUf9Ljt<$Yr@$GyS>H6fsmxtQHB3Dvobl>QVVF7x2{Qb_!=&-39FB5&TpAE6vUE+E_iGVsz+ z0c2U=Y8%|aRlg&h+LQLdr3D6HYsX<>L3IhvJ470CajFh#T?QvaBLw~Ke%+%K_*E1+ z#Tt~4n%36?aYw|$7}1D>J!iV~GtG5Yi{i(c#fUE@dy<;jbxOO_Z-MQW9M=GW?Y+_J z9muiKf6norVOfyL*wD{_;i;Vly|S=hU-8WYx2$hyhf`BS?sOq`KEV{~0mn$o%Fi~p zD!P_)%7Wi*y(G@bQ`D3p`T|fFEyw|hb_fT?AQZ`do+(6(?muD*qwup4TZK+;UfAVO zu|zD}=-k3O8tt)1P5a08BOA~@IO@X$jR2+Op6jUy zjLwa^o|6cy-i~=)D8!)q&MulrU*VK`=7q%P@o$NpHLkEWT4YS6E0OnT$eOTJm&bUF;dbWp44Z81IwKc%P{6KL)csJ=ZxJd;_VrL z6v~M1cz@r~q2B_MxgjYgP6|$$aDkVrqk+m?u(*=g+%KQe81GL&L&6`XM5_6|XOJw} zu{gA3r|nQ@o5ldRTAL4ujbt!tsim}%B6(~d)&7nd4CVO;y>)_k=d2Py(i_JZX!j?h zg0I}O83RW701St3mxv@BLrZ+R8v9(>#0tZW{l<$+{ioEOncyf(u&f|k;*cbe!rab> zM>W`__7PRoe!P_loB-S1oGBWG#sWD=kN=Zf#6r~SVBp?26DxujPhxB43W@}D)04+I zaeNE<@<-ZUI~p~5WvUcx>zAB7uNt3CZjuQ}Hj8*j-XbK5!PB-bhC0y_lX`TKTKEkb zrBy8sRcOPo5WjgOj@P-cek@;s2L3LMLDW-X1_ z<8JQ7?rZMSHewaEM9Zpxb(%NkMk-V-!%vu`;`KExq>|IZ@9{u|shnXt=d6x6vXhvJ zy}if4K#JP0l7Hvnv+Y`Os7@GVKc&w`!e7%G27slc_;yV5)=$)W|)!& zX+)!O2zC-JiNNma$yrl-PF5-au`*Kv0uA8R4_m?&v~7>yDjXZ#M@yJGSO6Fgp~eit zW0y&wR`6L=nkg(kj$J7BBuj`p64UQ_ zXD`|}@m9dC#)$KjyD=YFP8%>;+y9~h4a*4cH)5)fe@M@3Uqc_wTJA6roHq@quKjzS zjLnKtIH@U{D|dEj=&4B!;s>=GhSw*im1Cw`zE*Q@6XV_PJ6oN6hG zQjEkST=n$iX?k|wOo;bXj8K3ufyeG?*Fe^>SZ??LE-RO5852|=#u7CHu9v!9O z8F=J@R}nNcUS3|rVdfSG+jQ1pX9qd{6l0iKlb>YwmwkRrl;~*xb4Z-D!)Yb%EMrO! zNIhHP6R6%jForhZi9^#?2U&h;LfuV3!)e3*+ZZ8;D2a>+DiG}N^iB-J z?WRzDnXp1MT-qShQoXm~G^Pl-huIoqH6t6T_&ZbWeZB^%lUaw2_okiW-QWrD9L3jt zho5h+&a});J72)EI(xUfxw6D2`*lJhzQ@=1ht8|{tC@t7IdHU;O{f3UP1?XfNcKi{ zI6M{$n6|vXukqbXJPq}J`G0qiiJ{`E?+Lu5Cu@HRX z$ha+zeBi`3_v!ufb6wth`pdagBH8P0QP=YddsT(~&q7BwZorrQ@wAMK^);={=En_h zbTUC=LSh|5Lw_K*N_imj?}>eZ$1+eyBo;I-z^aF$NS%SNxuJ zbP3$+T8Aw-!AVl#=C2>?q0VQFo?W6iV99;_^5Hj%Y5J#wQ_BNZehv$X4!ruk3nRIAXVWNf+t@Y$5~!71(RBRsL3> z`)vcn7+2>mG9sZMC(&JsTr>iR81E@bMct3_#zTEIq#NI)oS}X}S9t&CN#lmjM@Yq| z3^|QMk#BN9@G?hJJiG&^Dk*%lH08+)085rdy3!(n@jXGj;+dybj($Bbp><-g01As& zKXaF%|3ILOVTSr{X7LHs5{47oM|!KYL!EaFtrX{MDa} zC-|ZV#sVL5x}DnfilvXuDX`hIB*bA53!FyCCMqDIsZ6+GGu-^3UAaO*v7sZC)B)kh zm-Z6fFa>VRfNST8X;eNaDw9q(98hcGHkeMvCJ?V_mr=Z`nn4_vdHbbR zq0rbSXjnzANCfMX!6KMCcR{Av;jA5^c~+dFR) z13p_aMo$w52QnOai>5OJiTj%WtJl10OetD^!%UIG^1|zOX=`M|mu|uGECGNn^KzbKHP5ZuKzg# z%4@I_XilGzV94>inXJpQ@o-2(;qs{!r#Bk^NAn@8m45-9dE^7;2q$0V+Av6G%7~rR z5+I^IL_E9*CCz@|??fOTr<0nYVX07-lv#TBk`^UkUl^N;bs`R>Ni+#!_BIbieiI|` zvhoMSY(tLi%7hR625KLZH1mjHM2t!jG<&3g{-XNa#2eF~j-Y*8=MF&rZ^wpqwynyt zzus^*m-xLJ7DAgCK=EtHQnB9Tk1ij~1FfkquDB%3G7JrC;W;n@u6UvlB9xQ#8rC+n zW<*u#TlYvJRBH7h4In<44nC9~2PX8Ism$A!qsPZCC@lwH8l$`V04mTiD-4s1O-6pY z=@YtLd{3OtUe>?Y-%X$hnc(Z6fXGKD0g2_^XvqzVM2Zg+sO;nvI8-{8v;9t=AY~$8 z0Hny_-KB}i09|w#z#BOXjb0cgi2DXpfEp$gHv2S(0&rIv5#TuajohCxC6(U)csHss zQBrR$@FnT*pIKHXwd&60owVwo@+BT3W~VLH{FXml(P@zqREe3>bvu*hijsHo3FcQQ z!h0?ZK6rSh6QqM5wD3ZWGO`3cAUQLAc5j2(H^#uvu;`Q>zhMhBk`B(v3S_;7n&J8o zC!E^doEsPkl#uDaOUVmMaHOW?+WjnU7QunhLXzK-lDb(=kUw1c#zfE0xdVQhYs-L^ z`C)TUycdzL+PA6*&P8~v3-ER z5AolHki~DT!7$$kSQyEvy=iqLog}L2`ik$p3;&KTqoY6cG*ZpD=!3_nWgUq##8{@+ zjHe+a(O_8Fm68U#1r2RN8Ds;FxT-77G=rlEh1;Rsoc5vmFhU>(_sKlVZr`1U1BHMx zm}f#;d*;oeYZLM$*pOJU;oVc3zjezJc+?w1%679G*Z)pRqm6nI+de+=kLcqnaDuqk zTiHxx`^cpk&f$;Qk65m}Wau|*@xua8=0fBa>R+5-piS~E(dO_V#d>Wa<-_h>^8zlO z^>Vw}7@-E+(J}?LhNgc)FMQf=mub)N%YwH)fRdZ7*C^krtj=fGyl(Qv{?4aSaO$S+ z?o`g#1@CbkL8j(6B4YGkd*-!b_A#H)-lC>s8s7ahA@{ryDhq1rVhfu2{{^cFRQ9J2 zgjLe<33KcKb_(#&1h%Z4{>RP&eX9~+`gJZ)$OXnm6oH{Prfol4YvfnJpojp*&W9M` z%`^;H(!s#kvk}19E5gTQVA|I~Hw*h#ur!3!6@Oa9~3Z?MZ84*=IJ5#F{||7R+0Z>0`@o* zW1kv(Xn`Gw#y%BWX`dSVShtc{;kaAH_yV_*ZZUZ9;6WV6wOS1e@3kpG<^Voe>lZnk z&c|+k1UAxal>}=7n<}1iNzg-xk#Y_~h+z!~jJi7#*;&DOfc_H#qYkkFnn(tQ;r)uh zOo>saB0)bU0^{2vM%)` z2bd{;K`X`patF}ikXh7nIYbqbn&r1bRj#NQ`v+F8v5yIu-AadHD^=9ky=|q(r?Ev_ z>9J~T5io60dU|@a6TqJ$xSoXbCuUCwt|5_DH#dl&ffCIuVw4oxRN;xDVwis-prI@Q zhOQevxabF|4$Pc3X#&IjWdbvU1Y!<|XsqD-Yj*^b6apA;1ckH6I40BE+l%5r76<|& zYts+qauVjWGB+M}qq6u+7g$U?MVGS#m>F&|fr-f+<-km;t33b{&a422UzG`r4CZiT zAUE%ZETLH6D=1pA{v{U}$H8_4CfxIiim^{%LjEF@_xLn+x4?GP*x#kCgtWC)G`0ko zuqAdY9m1`|rq`@g5WWkR8kpl7%(xL-DPdeubBekm#pj}LC#o_T49jyzU}$2|wIXN= zMPR1qR1OUHcy(aH_7?#Yfgj-!3QkW1hW95T7l&k^5>SWUfq-Wlhhd;YWM-Izdqu!v zf%Tli@#lU}GMG3;imnJ)?m$&u*ib8g@t_W~X$MEAh-8)7uFc^ikyp$8xkqQv9KDKr z3?o-Uy-bOTy~n;S*9r3z31Ao;Gmixbj8zjyyz?Uq#lV>>xr)KS@RzzA*ykGD{Z-}y zE7Dlra=8biT#d!U2X#}i<^tol?QJWe`~@%}F?@Gf?o1QF%riY|ECS2b*vGw< z#Nhk=ZzYjuc`{oGv)2c>m4wC~&aJeoAOC%BrJ^5yK0WUZ*nw=N-D<3OOwrYe3X{8) z$mq%3?T`PitP-Ar%76SnceD5;ggz$gE>7DN-Y&Fig>jup8HUpov8yb_9ls!NAO)KMf2OLsUf}V3ru>I8BWe zLwE%-OLdJEzz%9F?WnN=80KGDW1r+!;bg2?jSzCt5hCB8!QIpyK?5z{CbC0w%&=C>?Yp zs{q3)5&_IC_`<2=6@l>=Us3*?-s7@l1cuLO0y7^|SW|p`w~CPq%#3V5d0-_P%V)mo z8jAu)jXgYDsfxymnDZVqwrDGvJ{bZtHTJM=r9-8$<-kN}ts=0)rm;`^R@%SD?rJNQ z{P^zy82TT%z_KhmcI=qSZB@b&N>Q*al34ovn#&UzD=|!D_KBL+r^s4`l|JaH;m9v^ z;fsJ#hh!AXzECy!%gfE{6ahoE#>!GrTw^{XzNmqT{36SffuZUYJtiKV@vFpN6D*h# zuB&*FN48^27%Bz^HY+NI+2LlAvgHE9_wNX7{~F7e;NaRS8Y{B?2Mf$>MBJyw;;)G? zA$!IHyp@W2GI8kh@61+u0zdu-wUxw=|KZ$9mYV3ZtlG*&S zTaEn!w^Htp|6|=sML+&xD^>sT7h7q^AO9j?W+h5)cg!BP5;krW{rGn^APH9y%Zc%U z@p_#OL06gsFD5~lXfqWXQm3OtgSBW3%LOJBf`O4i!%2CgWkfl*0LIjzBJ?M^?Qt&^ z0i({CSJZ4yCW&FM<-oYS7H6{}Fd=_YuP)560LGGGT2|A;6^bDmbsWdhByqb1CVtcy zn8^H9R1D;iPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RX0vZ$tGY9f+5&!@o07*naRCwC# zeRr5u#o72fbL#Ee8w(38OYa>)K*b6w7-PeRCYnUkG>Ij}_@$Zn`AcFnF^VPjSc0ga zVnabtk-GF{frVYR@4b8LX*2Wtr;GtY2!O>dEKQhM0RUp~8AAv$0K^y|)D0xsrh6RB3M5(S0Usa= zHgN#f3&!GR8k<7m+`HlToR>KT=mLcjD)#`}bq85z8k@MKd9>3+u;u_*_dLOJzsD?M zc#fM}MP;Qb9-$Gxm1HT_;wvPAakA#0e%LKk8+u8O|}2VxeQ-+9sWH+-I1IzP%!$ z-}Fs2s!Zq`N4VpoFJ~AGW6m&iNdkm`QotA}1%#s?9HoE|ujz&;07A$hOyEsWysjI9 z2*5bQAQ%J2h)~AiE{p*(2;(>lSOSzmFbD`m>&P+^1ZMq+6y@b>uf6oFvjBim5{^Wo zpC)6xC^1HfVIYh-j19v`Lw1M5QF`;uP3By>CZ6wf0AuZe04N&B5~wO*42*#w00YqU zVHM>Ejx~WO#G#Q-TzC?BM~UnYH%^YNtY z*t{S6AGhU7k&ua^f=E1;jzjX=eIPfuH3?=<|E}Lxq)zd zt|za(J>bc81^i)A;1J)Lm&1kp#T~(8#fACpt(bx?iHtE_lqp6|e*iESvB{2bCvc+M z+uBh)z!vD#MFBD7?(A$SDR%k&zMS0Lj`p_V;*uQCsypvK($t)n<0e%2+Xt)uvvnIt zl680pp_YbYPd@#0)#wTH=S&Yov_g;F7t#*zS?9?uEh;VT@cNotj*S^VML>*Nb`=Pr zP$+cd$dS_0QisEV;;2SxRbjra>!LmP*3%}xxnt+tQDYEM6#~_DH9#4cQ@F5d*u(F> zwZFv+JZHr%5809}+45Btgh1E8pkR{$0Ehva0XEx-0nR9dBT*iTG1zRNM1W902zVYu zv8#>(4oCDl6aj}F5CTI7O$Pwrh3K{&p)9$wrB8(;1Tkg{hw|FJ_Re;JVo|4(ZnO=| zv19_b-OlSaNgooZ@lCz7}jv?K=tnZORv60kAz}Pd7cl4!?R}1`s}mMDk>^i!skF4 zV*pbJSG=;d`rNT&-rc_GyXRl{;OaFK2Icce6eRKU+5`KWT0xZJP{jAxn={6MDgL1B zb^|bkK=B79rxOsMgwGH4CZAD4v``3P3;>AZ1yNALVT2GMEZS@cgBA=SUJxV^0EiNy z42yP|YMQPph~ouWj&+*;(@!ruW+Dn_0=CyCD1{8&Yh}m`CS(jhLxg0`P*Da0K*xc` zFM+=3l%y{h`lR6#CKQNIZTJEZl$BO29yRolb?Ycip*c*WLX6i&Qo!=hzOm3L3OvU} z!v5c^TC-&KylI05Xoj|a&#w1&>;{|7=_t6_?*U zdnU(>4|nhUsOAuGTy{ChmOd0pTZ>D|kJh)8lo&vK9#4B-PC;8+$mI$k%z#O%9wd6$ zozo_Z?m$F}1cM%rB1=Y83ypM1GJr9TW7I|%GB9Au!Zz6+G7L#JIM4*UD;Vm?^B_in zF`c4OC9b+NzCSpxQ*iMwZBJrNFbGjKH4=#g+S`=~88ujb??79r8%M%HZ->{$@y|Z} z>|MY3;o<$YzOX77dh9FKb-kdV;KL6;96o$F3561M`#YQ4E*v**-M;GKC1v-$wfcdj z*RS62Ar|<5f4*(>pdsO)*GKu`B}MyNJK{biba!!a%xZ-ZfZ)08;orV`({~LJG=+Zi z;XkhV)jg4*hItNvQG+0kV}t+z!kAHtc^-gK!$6obZ&Jfxj4?`chYUUQwjXPLKVaUs zchi>lK0EIxKUPB#4z&0G_x|?!_65KEm4DyooBy*0fQ`FiS&lRK!NbpuxbV^`7o8ny zuK)1Q59$QW^*d2lX|)j|3*Skq@Qm4j&1yZ=gFQ{8ae75&S_G|4x|B$XHbSf6GkSg8 zHsI(8lG%WJm_>V9=B$r;nA>|(z(NWea10TN_(xqcLS6Nfpu%FrP2SOopl?zjiIjra z$PxPT=^JkYjs$=B&0GF*;b~<*x}~urwEX)&xpr!0&aFQTM~LjO+c@lP_k!K#lBIxY zvO?G;@qu7OvfCXz?&$D>%_j1K77l`B2ciK(z+nIYqJwRKcK;oVA9+-g?W!7Hy=lj` z2OfOn^{0;N(htr#x3h8YWsg2xIb!yKU)*x-Lw|VY<89Y}bJ>&MJTL!8w>muKpZ@sU zKYQtAn=|j~$-@`?zlRyelOCIb)LPk;;&_7gHSSJ&IGI;YbdTs&1)WLd{xwNDn4~~b zb(g4i?uRxaRg*M!fnJ}c@5sF1c`#oa(^$)KKq&wN3V;z15;c@!6#YslO@f)OB>)(U z|7n6n2q<;S^2~u{Z8N0SlsNlL9S4!7fvS=2eXpNb5U)eN>Po&DUOh+UX81 zwC3S|6px?&o!3{~J8J5fC6`I9V>iF{4gf#Fm`;c%1T9|HM1gnto<2xb|8&HR4)Ym^yLGO+=lDEgvPfWC=^=;7rb zufP8r3$K3ueOc@HxXu<1hvrT>^Vet2IP8zu4BwT1eeB8q`Teh-`TNeJEw^9w?IU|W zI=~A4e8K!f{;-P$E`4bE+%p#a@yr=2L-{tC_ooM%f+}Ea?s*QjG_Bsc71Fa)FSn3OZZ*W?Nwl45P=AY!w`-#od82U^HIS6MNs{c7E1ZF$NPMzoM+!cOcr( ztPr=_Nz$FGR^7jLtzj7Ewi{ti4f{L%k!M<3bi)9~7z2b6Fow*XL9%%X2(>X5KPrqt zmVq&|Q&raib0AK)=zFPVMfGkQMZeG9O^z+~R{0r`JpV!A8%ayd(fwpm)?27 zqKd-j9{yzW9cRtEX8C_^oHSzUYfpuPHNO^MYI)h6i!L0I`z$Xz_8zQW`q$+*-}KY( zP91;G`=3QMJ%kJ`t9bLapU9Hz?`*x~Z;v5B7$LwI1iWU?zDdJ}zSBTMfws5&8$P#6>ICj~qmuym1c^sTXt$SQ| zag`IjpAr@I)}M)w66MQOmD3C|apg#qjFTcERo98Ytw>Ha_cUJ6X?)Hhna_5ru6y-@ zPVC}Kqi>wp8i!xjd($FG4gX_xDC$-l~;F0Eicr#yugf zWcZZvg5hs##*)NsfAQ)3fdfjXse@;ZU;oU1MxQawHE-$0zun%6idzO3m(4>X&z|e^ zb$tAf`}QBfKYH$$EAM~Ond_p&$QxWWnmklGbW##*$ z&z{xkn6UfR7e<~oEZlbJZwnU9zWK&$UwXZ9{p&B^b)V?4r{TzndkU6}KSpO~QDa&W z!BUGgEU`(KLm=y^V`Ool%X%O6q#Q8ECjS22b*ryDW9!}q zhaf1y@L#@vhbMIGwm058bL=Fy&GzBOkN_;pV{aZ@Xg%_IyK_cO za7a9l(cb13@OYZqd?OqpK$l{i<7yk~7X9xZK{hwCm@$SC0?YxWLko+xZ)xWFp*BJM z<7=y$fBW-q{^kC2Pd|q-01~z$)(bl81)Yf(bRzIm zgudn?9alL{t(}R9Aq{;2GN&&#&3MRS#}aI|nzd_B|Nc+f_irTx3=l8*%l$@Yb6d?J z(IIbp=9%%|ySGGa*|n+Ws;B;`w>S8X))QSbblsp#w9C30wO#Wz$L~ijZJnLU{yTF+FXH^oSp4Z(MNkR3z8K-qLpF+?2U;&j_xd&KFHLJoTZje@k zWjt7O0A15WJ@5DEE_NqwMhUZqxEZC;@%EU0A|4X^?Ltm`r*SV>GSZw7`X>KNL0>C@ zzD)WiGIW6xY@&2v@8*&BJqT{6O%wq0lgrB=|L6k+31iF3D5DVezObkH?e8tU`;B+O z<#fK3$bqQD9KwTmyG zo=aEktaAvwQztOEE+ExXmxj+~ zvb6L%9&3~IL0Rc5_peF%1=4yyRd=cI)>nmahD6EyX|El9ZRwkajtTdBsGt!5!ko?H z+4!@p)@$K&@y4%Se z3j1Y@0T7m*c2nXpl=WnK=~|JD+{1x!or@-6+x$ zWNunhjT~-UZtmWfo2oo$!>^IsqB-+S*>H*lCgaP087-~I^%$s6d{+=zhZf~pQYx9MOl0sL8Q&7Ut_ z{JjNsow2)~`p4e(5E6xSDrm?i;>afAfZpl&Uqs)e>gDvPNW9K~zUc0f606fM03$l# zc+OB&PLvoWnB#O+vw1vvC}0>YziPzdKmK9G&DR9{ny#p}+#D_72gCyq%n1lFLnpi_ z001Qf5ay+*3EEH;z?>k7L{qh}B03$0qHvN#6a_HH2^`T0$73y`$}Sh9h8B*9c6%lq zEo%cl)os8rZ{yx`lj+5NY)(>mM|5B5C9Tw0x=B9sEt@!f)1wdg+QXbENKOY(%F8xD08C_*u&(9+fO($dc@|T4^E@XA3;+wF z=)jCp(e9vzE;t-ODPthocw!LQ=lPTZUms(M?C%Fr@eL9flNxlNg3%eUv5)363KSDXw2@{lrw1EVcZd%6!`o`X>Kr83{{BMfv5^H}MNZ zya=ZMrMW`OGG!Ea5##9a7^Pry9Xz)Gxo!JF5&;^Bhy&K;l8PmXG6o!n>~@p#)EaA%E!mPSC$yluOG+}{+%SZYp(u#s zIe|}*YK}+H>*WhiBlMi&<#<(;eV2?+c&jXZPau8cCE&~@Bu$Iv)$3J4>IZ33NgkQV zKv@YmD*-J&p;8 z2{5{WXGq`vg(3BczDZTkmQ))_F#F}xH?hQp*v188#EKw5Vk(SS)T0@g*zYwMAZ4;G zQ&2Y34rtm5*t2jP5(H)ytkdNAN;*z62qevXGYmsA2Y_*WXlZ(Sr4O?)0a_`QbTH{5 z#}fS~jn9D$Y?-ly6(;%82Oy;ZXxbpMDv*;__#V3t$jmPwO#ocdwyAEWf3p*}Lg_a< z)00Qbq`53m{hTziBwJnFg?pS8T3s> z!K4#U&w5TOePcCw9`f@cRg$UR6<7!efwnft$pJ~~vwup41!HJ#t}HCPY0hb?L5>HK zz~Su;$6nm95lTyee~eK z@{Wt37(*Zckq8tN9M{^3F|@Q~m&ud603)lAYbM9)ilzvKLZsi^p=Yt%Y&_4i%wMUb z`{E4ur|CoQGwdrvi6Ijyr`O7vTx0?~)nwC4Iq54Wop}0=GTfwp{piav##<}%JQNl} z+T+i9=lCrx;BtZ64JYVRO<)o{G&c{<&;QwZ=NYPcT#y9e<;|O4T>BB^u`_5M#Xht+zTlI{1^5)jhp3 zxi2q2gMLAYc_E#EF`OVcU~wWtU&ToJjZ7;_|Bq?D5T!w@Dc4k`TJsG74?qB@#UU-N zG0f!AQ8*L;0nvdNQSOO_ZY5+=bqMrk_v-3`FiJEnq-l&XggMNK06>Y(sDThNtq_#P zEE3)Cfb~Ra8)J%YL}8jECnS1!s(ET`H!5%}qev1JixqECU4jSzKr~=o_J*X%k z*aVYq<6^0XQz?@mA!#C|@fHEIg1NwB42+sKmE;L4tQuqMi(x|M`5twWW{I*+4Z2j& z-3TORMsWa?QsZbH%t_kPWlQ%0+-1fC#$?7maX4y45d)~II%e9mYaf4HQ&oICdnf<^ zaM*0&sZ(#e?Kb;~I%@3{ET^WWec7`KCFbH4{3KoHyQ38N(P4 z&&{>*{MM#pU@*V{1_2HOLr4@7Bmo8t0mFd!|2_DT7lhxHPtJF_2D=*CR&Y z{*t_sLY_Xhy&Cw0HQ1mNi%X_gmDKySM@J4={ns4}rVR@=Hx3^*TtGM&@duGyl_RgI zIplUahUMms_P7*=pR3++*_fFd>T1s)F=peT+B1g@TXo>jfq-5-;DYkv>ZW=kd(N#Kwt4TioV>ClVc!tZZg;xg-nVmW zn=kQb8qC|p)_uolv1D1=kx% zhM}8^yG)>&04b%0-i;+g*BPaW^NOK85g?^B5C~98DW#D}I1-7(5m3{#q+=k2XqpxX z1PCFFF-nP|D0&w*2qDx$vbgD(_o<=lN{AYoNkCmw4MKEXX9*2y3iVfF&GdDWVkXtT z=QxX^D3NeD91bgyuo8*HJylh8)acPqJo#i2#Q+knQg_Z6F(WeZ_WZGzU%Y1{=DD|P z_O7XKnOan|@mRwdgUVm2J+i5;Zggqk2v1H!Sg{FQ3UQ0tImi*P#(+nHYUtZrTJju) zvJoiCEhv$t7i$hrD99b1pU>3LyT{tr)ExfS#F5^x;u3|=57#){?kx>Rx3qf|LJI8m zq>?&OHB2Iy>EV{6oFLil_L-B0z5UJy+m8ftoKo$PW6ekF!wz?;N1QfgR8gU4@x0M{ z4|ydqVRgay!=|R@fWJ1t9}Kz;+P;qVJ?(8(`GtcD2F`YiA2+rVLh>ArWS;Wa zW3)bh{_H=MRqQF6Q{$LDN5%?cJc2U@4tVKs)3_XY&VYf-ckG!naBy>=y)rlNUpsaj z34}_Wj-=a48=+T>7=C&|*@6KTSB@DCx?bn=**N^#zFlK0Mj7GuW&;gzIora45yj<$ zZQ``zqQgN&*OXkl!+g^d-YVh|+|NwE{)=Y%MANZ#q0k|(cUMPesZFf*`mP)~;*Exm zsd@Hefl$8F0W67^dzsC4X>swJ`}beHVMCrME~4~52M^{ra+ZxAXM>0e_&TAs05Q4C=Wj2VVeUS59Tg%@g?W~!hWCA`hkzHMdT;96J3bPmH8 zpM6mr z^M0Q%qUsaJj671`5Q#)YQHsTt7=%_7+pf8A+_X_;G!m@$Y5-`_l5ftKGPY*VuGWrD zNfHAAKVwJ<2PtrVZ~M@3lSQSoEvQLdA z={MJJj^pwR3r3Eq+PQrvaJ(80ju<<^(6x^CHiWRMss^EkuBw^=jQ9gVn@vvKaJW65 z2mkul_3PF-a`SJz>DIZkCU4!izS--SCE4HE5z_GD3(nZQb(=w$EJ?Ag7$Icfz=31N zjQPbcez9xUE+rCn=9gZ6={L%XTwAy9P&8w3dAXt}nr;}n8VZJV!emK^Ap{|0Xlm}z zNu$oW(Eu*cbO5&HR{S`%l_Y*HPHo_=OHf-7z0MDIr*F^XKs3R<>Ye~{NU)}PUP^bYEwA8t+j1p zLH;ZI_WM+=T~!WveKr1|4Uq%BKs1D=qXRr1kR)ILgiOdE*~AxZ?f@pB*S2mBit0Io zhd#dbQ&sdFYB^RLQinOEAQF#x+jjc`t>JK|s%&gH#tG6DC^YgErK3yji5EATp9Xs9#?El1OYxOqz^9GOES5r52#?%ReJPPFom*(dd z+~r_Wx*WV-a=>a z^?e7oYSQM$rp+xKXO`x@bg*GtYy0#f&tp4x7CLh_96j2mXeDmv?zYxW%>ax*Q6Lb2 zq9XIP7%oXg99OG`YlDHt4&N7nKtW!?;kMTLh<3Q6MUq|nTN-wD26==w9yxeS)jw}; z%jH?KW;6%`g{KaYpUcJAOM=Vx`b zLyJl`x3rhpgnhoi(orKH{Ni&1^HFy&MS;9LKnNIUx;jXA4stqqO@ICHp0)yhSAE?F zM_US<&U{(?`_>)vN^&0Bb7V?k?z@NUa%5*iI7k2i#?aQ*Z5580!{d@0$L_@arFs;1 zKNASO_LUw&U)!dda@>%TP5}~c^(5qB9WOhXa4h_{|p9$ zrV1Ki-n-+q&f52}vq;gzF-v~&($mjPKWpx`k3Y=G^;92hnLKLnmfibh%tlT;E!4Dk ze|_hT-?~vigfV8f+t;mIcgroe*zNYHTxf7lytKN!e6T+l&ha?r&zyYAb>}_%_zOS$ z{&#oPw@)2W_QHxa*I&KlleHV0IvV8MsxwX-7Yv3tBe3%QFTQ)@(ifh4>7q+6+P>+N ziPPt9*|Mc-XvJfXJRH^mBg7ap47z0g;9$;d3K$>#@Y6lbIu(BY%R63q{zXG{-FWRc zAARV-`4@bn_0aahs+qN$){LAwFC6j?8#Hw72XDOf!KacanDU(4?S6apn}_@?uXw;+ z*Dl<&ZKtM0etPfy_uct}%a(m-Y-Q2Px7RPd>WU4YeKcw8l+`O=+P1q!6a)aEjODtx zg=Y?KY~$~^Zpr#DYH#`7@}J&u%i7mh9&HPM|7Uj}-LXM-xqS+rH+ROrUwZk9Z(OqC z)qhW!Hm}3q?&RU|C!PdOj0wu4Mvc7w`fD{!l_dF{ciyeuwPX6+b0&_gtl9qQ(U5ra zH5dQ(j}I-o?&`PScx}Lt%Ff0k&ax3Dc6G;*;2Glw{QABJc|owspy6U2;fjl%SpL|BSKfGV>-xOnLPIRnTlYWv%A2w*o6W=F@Umsg zuDRx#qeqWQl61>=zCB{*`O^oWcRtxMe&*a^1$6Ch$vtnq;2bh_VpYK-k3Mzzb>H6n(c27B zKanO+np*wI8ymJB;4tc|ir!i$rpO_LV2mlH3;-iU8AX5?1FlQ&M|*0^W1cRQMR%w) z7ChW_TqtFX>q>pq+Saja%ApjpS`I&6;O2~$&Bbx&nC(M7$7cc#Y6yr!O#G6(V$PW4rL$; z000~ZyLZnYUiIFsw*(Z$L=h)B5GNdZ|0%(dS2lTp#3NNz8Nw2eH9|Rr2&INWY&OX- z2q6?9pp@A~@!wmvUi*(nVC+~B#TdQZ2rVuyeER6IXi`jbj)dlUJR*XoP9I>dJ8Ws! zE*LZjJRV?BsI`AOMF-jeM2VDoAkFJq|5GAeG3k?l0 zc5JuvR7|&oAZi)qyF6710fYf4P!@%38q`e`VGIaCFbIbZ!N`&3_QHW}KQ6rBx#mv~ z!65+2Okx++-w_Ht2RZ?s1H%A}qZ4EdcJGFYikMq_KF=2f0#kVYbxn&n9E4FY2ogo6 zYrye92yh$_BFU0!7yuX$1CEELCh&S;*f792O63TQQe6?y4!a_N5C8%MU=Uyo2?En~ zB=Af#KnE>8H;}HW5d!&NODs5u`nhHO7)i#Mid}qoTP#Wpe($$M4SF^#vuQ zdPjAKHxN|mvZV{}|HH$VFTJF-Q}-S|Sl@DV)W|Vy?Hy%>IZ5RS#(+_9iAWa(YEZ-p zhykGnL1Xz<=G8zfI&t3qawU!m-<>uvvn>u2f3ni>jsY7Ml5E~0e6q`Hu&DUNXJAVAU^Dp|>-yc40 z?!3c?j*P4v*3x{iIpk?t@mR&YE7m`{eEi&*z&3QL$8cw7=c_NjH220I{ig>0^8Bis zFFkM5rcE5j+3j|RO{{N^+;H8ZAKm%Dca|;Kd!VkUFfS&yGRg*&7T)vg8$SP(UuWby zMwd>Qyp0p&DU&A1Ez-8P9&wIeI?Uc2Y7776k!ODLgKxe1^z&0spZme9uQ~<}8$W!2 z!|4n~G;{ILG;R3ss;N_FghFAr+vWEMHf{b~lpNdFzr|IZU3%=ZhnGJy>9q434s7Ew zS2ccib^U>g(vsafHoJK7SU@jv%gtfJBXdSvu(SP=Z~x}(i>`j=>0j=u-fGHcm>0)X zjr`~Ge_V3e?HgA7u4Klya=63QM~{>gxMdDm^o98H%P+64uD;`rJDz>^*}3!2+*@1w zZe94|tG`oh)U7|zDRdn5q8P5oQzJ$)y9r~uu7j>e*$u}5 zA!ZoT;XvtOjJ9ZDKu$oDfEqn^{c(Clb5%C~>pB=l^zd^)tGu7BYTpnYyG;TE0mm^z zkJ=++%L}tOS_6&dh_?2EQFnZlu4{&YEV~n;h5*>$c~>w>sG&xT=pIYaC;-r|7e-Ze z3u{8=mIX8o2mwN3-;1BIr;pSF#yujkFzN{Sqb^Rd)7{NIN7sB?aZcqX1W+8!`^gia zBpzuP0U=QjEHkr2^gae%k3x$%En9bcu~t@tZX7v~WlLm^-vkH%03j0iZT-IhivS!z zLa>=Z0Ciwp)gF#e%6ao=Ep$LOc zykYIGpWpq~8!P03AvavR=m$Ui>92nG>(#HVoPWVZn?K(a4zx?1kqDpzyK0s!JbUBD z_Z>EahV}&beC;a^_uzV8(5lj;1_QBR;-rRLUyazLG}qVd z+_r7g#~- z_S>s;-QanyskzlA+v*S3(tscB+^DMh#plm?{K*$DS+dx#9QgQ+XE{OIwqr-09qp@Y z9$a1+R1MrUDmBu1-qk-p|C=|jdGDi@D_07b^1SG8Yfu&cv29x~|K?TC|LeYUzp?Dd zu617!2HFZ_5D(FNx7-Iy$MdcOC zLdF;%V1RM_$&8i&uGkVAd(fp@?gnMI+g7f4#qG3vi;DjFPIE9AG?fQEh5_KV+ZRoo z7;Pg6P+XkUXqVxh0t^G3PRP#(o9$$ANsd!^eoARcMAM9(A=PuFL8;3%Z|YRn zpg~BW4Ce z0YQ`iAz9=jiW<$vj}XSZC~(0*kVSb@R0VD8ios9~xZs9+3oAw-MtPzv|NX5r+^p!t z<#JJ?M-)BB?dtIQTy9q=7_ixF2yu*21i*1zAQ-ee?7$E($`~~WV~pAz4s2m|jIoH$ z49XUaaO*nTR3DB6d=#+D zJn!8P)|z5aBowqcoZ(HecrxX2Z7?Vz) zS6uX)9S(tsl7uh{_`JMi<1nI>sEX!vIXXN24u_NDIbBr<1BcyVIpiLN!(qcP%*6m> zWV6|bp#$Q8QG_5Eig?^Ee;^>sGD4V9$`~;Shyqr1;&M4r*HUC?;fd#buW0DZcOJb- z6tD@<&^3lQ4AdV8c|4wApi_|S7%@ZF5y#uROvolmolYmu^OGk}Ub}WJLWmf;*Xy%6 zT!`ta&g?ePAWT!jSai>sKK#9pHWwA-#9~9uleTzAk-Kzkq`fxcJ)-G`Y_kE;ef|*U zu+!-bboykwi|UF-s9lyQ!;&P#*?{}S7%gjdCTE}Zlj-3=AV3)qVhB8s5OO#itfwu% zps?`TrAu$T=9+G9d;Fo6W}e8CDWf2c(+KH|M2^!VoiQfyyvJsv{mwmdV&@x6MR~$7 zbs_+skO`V9@#CM`$;sT1EnN$6adGU77deFunB%ypG{(ym5ylvgc%A45F%q4elZGM1 z*?^;dSYbak43j-OTseuUi<4UN5-(EO|I7+HVF&?_QBU(kLSEn0<2T)Bgs!klWI0`j z5fV{Uhr^zjTG$}W8!&x|5yp`37EU0COzxnbB)4%qxeYZ$3{`UE_U|kW)4N#HG+CA* zZJudOH$*{50YV4FBZQBWzJ0X;r$SwN#Abr_K8S#-T2xf@+H0?+c>^=?){Yab`}i7U z8b+8t5-dF-lA=A$dz*@0sRovwOiACXo(BH-I!Q-(LSh2@^xC8$O;U=a3d`(Mm}tL0 zv@CslrFeQi#!>5rA{7klo*MWCN?Rq z6=RIY)}P7M?5TQ;{S+)~Ne{GOY`5F2fiB%Tb_@lcZa0&-Sfdj{<5W{l(})vooM_81 zGAETZX(|cQlR!w5b`%L2lC@X*W{9Hn^z9SmRA}!L_OcuQY{`~v0RTRK*s$0Sk+DH` zyPf0AOjxC*rSwE(mH+@ssm*4qtgMt{hbd)CwtW2xA*8stIE#mD$(C#Z0OakNU0q@f zcWu=*P3!FJJW(l`L{ap3JS^)?mn~oKLMiR&=rFZM9L63&IKlaLP3P)t$(B=Lfk7ys zssKQ1XG^x6 z7+FtIrVbiZnV+wB3Bimp#*o_`0B8fiUq7UD5h`kVlxOKrYazaiEI}k#DF0{(G1&~ z1{{wtV%ejhv!(Yv4DM)c$2Pk|fTs4yz_J1W9wGJU!G?iDhX61D<>W-__DAJ(JT+65 z9t$v~G(SJz8s(WS+4A32%naUvKp@R0n=I#Z{3o8+yhk?5)YXpTyGH=*r#a1gh02Bg zeGjUol%i5k-h%S7cMtAs(ima{V~$b62opp>(=Ro!7}$K_@P; zz1mVTS3$=igipMi{yf@j$(H|?Pd$x@45xq-R^kFYTlVgAOf1T+*oIs)8@FyCMc0fO zQ}1n+B*&6L#f%y|eW5$1Ojy2a=e#`Er$OpsTAs+y99XgONZq=IV@aZq5QsdPRb;Er zTcGHB&ka?--0qO_iY63z?88R{m@vpwkmD(j=-g0`1Lq8woXdUD;v4Gn91VEwyii@= zG;Uy-FB}nhVPbjdON`kZ?i*)JeSJsuw4sAV4t==)$bE~?|I=GlIY&KnT zOdM2RQc}Ni>mCsKZZ;P8KdGfT(HMun{NuB?-*FRTarqlKLl~Jv8u9}Mb#X8 ziehzos-{`b9 z&c1ym?mT}af`PqX-!RDKN(~iM6~b`%w28jmv>hl+9atfX;kuyo13>So-|og!i;w;oj$G5=^jzw(J2N1MN=KFyvrs{xnRuL%7Vg6 z#*J^@YhA_rnR=DF8C-!yLEfaobY*^(`3OQ176`>YvDE}Z7?j0`L-C@C)) zJ9>b(Jz$fCb?dekl#~GwNPd`okDJHymk8b518p|NL5@zD=L!SNgvUa zNWN6l>=S(+dl<%pPh6@?g-At=kq?eKdU zCjr$kFX!9Dy7mr?xg5JKq=YFF90Ceyq|D=P>hvLm6~idc&GjphP(+bMA*5>Q9HaWA zv&-cCjN@^_O6p3TVZ$`?dQu`=2=P>P3S~3xFAbkVRF&08+Y> zCsQUz#ZYsL-fLI@SdPx@a@983RID265{Rw$ktLOKcZHb4Mpvf@A==bbK!|MC;p4bu zD(;z-C-y3K^eT~9rD5x$p6Y3@UBm^jW-^kvCh6DOGz&)h@$|fdQt3+q}0Eerr$0k?u1gT$Yej4v)@s;_GoC4 z(TMDhrclsaQ-ivB+AACh1Y!*ib#|H;Mw&$)(P~Amj@bDYGDU4Ik)c6Vz~;~mLpO{= zstSNYN(3<15eit9b4NSc0RW5$0Dv9}MnV8U8SMy#002Pq82|uv9UUf91%P_5*K8fq zvf^*Hr1^rn-+xhxCd{|X7yyPQl?hSrHpcGpR_ zI;m{Hne2R`allDkOTc=@crpp5R|z=%+K|ZXtiwnpS0&|)NmrxHSEcNga;npBc?WWuMdH8pB5%qaB?8Y&8;?a&dxeEEd&2%(O{2Xh7u z!59%O;&1KD9Z;flG`BZ;2aFjRdv}x4t4|VehV)HDMgQm<_fnlC`lcdlhPL5ecSZfS zKxf)Kdb+y?qWGpb1b~`b=ZxZjlh=tY!^A-7o>~CT35c3Tu|7*kY1~@U2wvHeE%8D~ z{0kbBYrEbc>hic4qcKBlsz~OfKV#KWg<_?T4omZCCjN}ONEMEd>}x}iCJ{-Zbenjc z)N~gIB*SpqM1ZND_9`JIt(;~giFV)g5-lSH03Mk)cF(pW0I=?Ncdhu?5)oMVAu2i_}9(<(^37wYxg{`|IHVky7{N3NF0ar^zv>hn)a2xNpYAtedEBM z4EpwIGoDlmkHbK!!S@LR{o_?JnG#THCXqhMHpUO4)es;69+~^M9#3O`iFe|GB)d+m zX1$qM(^@U*qs05EswECDP0jQW`q4J&loR=JueeQ*_Ds+c_e!At(l>Dm{ibhRg_Il> zb)7;R6N{0#Hg#zV5o5^oU9t$5DE4Rh8CCx>7H!q_vxmSPgVv=(j@GvTL6-W~nmq;? z17aCokN;-ZT?2r)VZ>MmpMJxVNx()LrEVO?`xNP66+8Mdm^9YqUS+1l9(xQ70VCST zMT@sR{oJUDcSVelv#h*!^>c^zws+JWnYv^_dpnwN+TabVHuL_Y*y(AjYoE1b)|(H# z=n#!*x85~$d=&t7msica?s`Tk!g#Mvr!V{NfJ%>BeqhVnn?^3YaMw%!nYD06+mU^q zA;Wz~4m$@7nSaN3+YcO!ZW&Q8gU@_Jng*q5lmVwKeKSPDDH?{9M)}pJOjxFoEh~v; z%PAoCLRSjt6k$jyl{o1?ti+8I^p<+0*Dp1Fu9Wm$rx`<1$s1CIA!SQOERpC^*(kf} zKeBaePWjkYA1SOF)qHGAU1LM;&=Ff!KSi3VM=!djW825xj*#!@{?>z)V=ujK#0b3Q z-R(oiR{?OHbvswx`|C(s+gZPP2xHKd2!O{`Tw34Wj&lc>W2Is5Ufwa()~O6#c!ON@ z@tZ%pJ)#Pi{q??Va)T3Pjye^>kQe|E0)(8%=}`&;2WF|9Enj(|2!XCMQAB0}=wx9? zUvnq09R`CTx3T(c8yOn9zaVwvF{mO^_uye(0NWj1& zL(#i*{)WA{a^XF{Cc4fEKy*FO+@ue&fBfW&iynLF!+Za8`mH~E>Km7QZ{2$h_ddSi z4|h3cU3%f49(dw{vw}J}g-rFm{qur`%uX`sD}5pLfej~?zL~6rr;Y^d5QJeB6}h5# zfXo|6dCI1U3K08FXr zImpcBG3PHcK_;aPA;6diAcRniajH*0jm9dGbz~*rzN=L*0uU-^%_;l!=ay)f#cB}54iojp^j0nS-4{gN}ctz0wt%B!6vMRs?IoI?hTa{~Z?ZSaJO zHTV62sOrGEiz?@zyW`yz_3QBLJAa#(Cl8r5C%W@Cz zb=l=-=6P(g-M;#*jTf9h(;yl`I2;PO+&LRQSU+m^v@ILAoi%?lfNt7i5teJWZKVS$ zs|o}_90OKcQ(ru&NJPMK7-Jr2c+H19&RH;>Ql+ae%oxF#3x~skAP78q>)kKTT`++$ z2m~YbM_Wga9z+?%zyJxl78WH5fFgj1Vo0)}DyrS#I9{{iy?e4se$k^d`WJ@OD|IrVZz@clg7l5S=`{|xuM2P*mCx}kz>G1(^QfS} zw3C^TIi5!Vgc#-?JWX57@fcY5QRiQN?&VB+Oc9&;T`Z~@83pGoUm=vwlUKt)$iIVOyS>3n1{URMr2E{M*z3Y9j-iQxkUbLgrQo5=n!=#V`Mx`= zo^|dCL6OYj+uD66*};5?N7%#z>Drq>Pw}DqGVxK;V3gF^Zt@ZL zGJK#TsPTqw%s+RU6B!Pdi}2#eK?V7R9)|GInj@Zq{J}%Y=AJ%r!`e+(e*1zC-rZSI zmN$INpinU4u-gU>A2h(tbq19|qeteDP|kpIhm4`yH$0Y#GJ1B2Y%eY?^|mz&4j1SOFUf+yaTv9>cIM@~fia8`V+>JvUbh;Au0dN z35B~_`7@@Dd~5aE3orXd)86&Fn|UtKG;6^Hg(dmse0vC3y(v!nR448LRhCQxltwYj zQrFA`Ncw7!fgU)eEiM^0(p2t~3OW%>nGh)H@G@_nXot*@z9{22BvZwEZwoL$FQ?z8 z5p^=D-w%%&27o{Sra^B5v(mQTD(F+i3Co%ZGU-$^Kb5`LI=$Y^Fik`zBS}*;{Y^-l z8Kc+fWHO#iP@3T!Q&r1+$CfP!fj?x-J8xn8k-hJ~@utmFF#U`LV8H5sKfmbm%U*o# z9YZ(9PCwmg4^oCi*+v0X3?D)286_IZ+JKMSn){_1T)!qZ;6BP}scHdW#*D5e0zw3U z0q~URC;?8I4+AP&&!nxZ7^K?NqP<0|2G8m(wI5`Ul6$(ov$~BwNxK8ci|IFv7ZF za2#hCq{HV6hJs#y!0!(*%C&a1wY9hTeVtx^r{5oNyIdIKugV5|YOl3jTVjln-40O+ znA0P{%^N?7Q0c;NURqgMx@rB!g7U%tpS?GYlH|J11MgcRBKORytjt=ws=9hZ?+t+1 zSArl3k|Jf2mdue4HPmAJSn^0Z;+YwbWS^NibB^t?Ey~vD99z;@vNaMdQUbVuBmiP1 z(CBUe4fImI)xIxTxv#Ol_vS}bW=G``l~s*iKvw*yla(3q-ix>0cfWh@cMlyHzIgu9 z{-ehS`uqH$NG#s#m#wq!Uf6Tjfk3z;6!e8Vqmm-m7w({wN3}z^OY(ynwY(EpuAc4D zMjipwKy_c+U<6#J-9wJu2%O(L^o7PYZ$MTY>cb|7mpW*ABQ{cd7bkF9mn*I=F9LEh z_c!#<^&1*916E<%I>IN>bQ;tUU{}beC92jizK!_OhW59x+@mUtzkwRoIf(XqZT#$% zHg%I{gN>tV19mp6Y6HfmVU|m}0AVt&tNL21=np8Bif$QZI#)r0m-EFpPF>l(yRTBN zD2nIYPfjfhf0q~i@Wr!z{c)Lss#&r`i-j`dkW8cnk(p@#p@mG&WY{uwLS@^<;`C3> zeD?>Ze3391x<3^7-t+J7-`i~&CY3xt{Lx9FnHOf0{jnejQLY#s#rNtfXMBM`xug<_ zrq?p2AU==pyMOuI>*p7DN9F(L&%VEF-*Ch)r;<5?0kaH*aH*^@lT(W3#+Tl?GPAav z?d=YgDuzdqYnctVW&>_t{ddO!HhnOi&LV^aAP@)%5C{;)_45|3Gt$EP5F7}=|3-AG=I;X>6;sqN-&L8~`=Q~vNyrQ!yj!q+zqw4MzFfD=Lsr2+-|#s_bI z{)taso*e(fKl?A|#x65WUrQAIKK}22|4;wk7axR>0R;d{fKOSSn(K~t-^fJT(lo1G zA5jQe2!Rk*Bq{)OT}Om?C^eWR0Luh3!MOn7oN-R5Bx7VS4!{9n!MRuu&Oo;mf_8}c zmJnq#6YMR8pqqI?Zw^7%Ib?n45VY&;Z)&36-uT{h2>OP-pkI681wq5g2^(Yx;%@cqrRZx3 zg2Yo#-S@x#?l->lwJ%;edzmmz*Dc9UuqXb=k?^1V<;mmspZMx8JOQA7`o;|pC@Y=#^I1rhiypqbY-~ZqL@ejZAVkiQ1Pq3`sL;MsmZC8h57VXzWU$~e=z-pFWmhX|MkZm5%k^%i~TXLA^V4- zT_=u&-np!MeX2sdGndZ~-TmNapF9M>glK@Ew`AG9sTW2VVGtYv#()4L1Omi$ZB+mW zB=EWfb~q&}UCL(ptZkZA_hZ~lFK?O{05vUa}zkc`cW|!wLPK{-=<^S_P{s}h? z#I0ne;P;@AAM0iKcYpN1;Gi4`1x+tUz`fwTy?i&DW)_FYns!ykJ)b<-J9TM>1Bv%~x_bhIODFcnmiO-!lm-JHZ&&1V1G}(Znwd=u zC=_EXnDykBo_XtsKmOuB`YM3-g`a<?7nO0E;?Xj@(>J_7RP!H9t1Fkhhn;AJ@C-s>~cQrJrIaS39x}(U515J zU5|E!#wQjB_6-4871hk-iVr<>;BWr=%>7S(47hRV=*Up7FA$0j4@R$zt%N9g^Yql< zo&&+oP%e@C#Lo_9RNJ8 zWo~f*XaXVZz&UMSf%2ut~0=rth_>YgMBclJhBdS}_-=>sBIX9V@a0su0yK z!8KRPDwyPWN(ccM5VAM}fPAJfx3;Eg#ef|Amw)u{i{8r;dJ08Gbn5HaI0K_bVP}wqcDl4T@DG&(inx=Rp08lHs*B5%> z#Z#Yo<`Dp`R8#{&?@O;<`1B_pG4zbAc!3)x$G}a2Fu|A*3_w-2?DhJq2|T4!r_Md_ z;9(Gg5Ud%NN4ALuMX96(0v-TlS_}gx)c5=gr$7IhM}?@EhKZ;o5lPooMNx#Xg8+$I zDN|Wu7V~&~hM~!_1OSF%T9)PW`KvZ;)UFrwtrx)AT%js7QIj3JswVP{8#>;I)z}u1 zssM&sDmVMVR=TgvT3S<`TLI?V*ljljTAc!T8|oc667p;S&8mhaf-%B~!@BHcoC_h= zfqMryC)PvC5hg^}46UO6_{`~&sZEVejLuJaD7`dsg$kT6sT7+Q2d=8!-JSOxdgQGO zFU*dwXr;0c7BDVAND4JeYA_O>ygYtq3g8b5>%Q?~Z2`RFr?zwbbPHfj)12#(bEpa6 z>ds?pM2g`0b)y&5CB!C?Sn8Nh@lu3Jzo zbA3m}NaEaZ#+TaUlueu0ENx<~h3f*?Rvzyl2pXKk5<*n%kI4C}5CT_&`t8roP5C+- z*mb9X>wX+)V_(=^>5OS?>IBrjbA)?zZ!2uMXS#br$Kv)}pA^KYM2OBKJ52%Wz-Glhgj zD0nH#7gfPbpO3Dj=bwLLNg|AK0~5h229_~UV3r90nBdzxsWye6U8Z3>xg8sy+A0Ly z>R))YQz8olje{%G?6z3EZgB`b5&(0P}0ZJP(Ic2J5o|8+mqwrUUD%sBp5OTNxr z<$i>PJ0_05RZPdm0B>8K3WNxNKv?G7#8_TeQV{~+HCWUc=#G&BU;vmHO8^`poA{Dp zY|C$_{asXD%GO!Z9kJZTb+FLku#d4bxX3;Sm>Aa_%fvb*wGd8<>*^y2<2ouz(ddM? zo{XUtxzDY?uru^~-H5v(qW!w9)K+utz(nBPv9T+cM=vFlxrvo@Arl#!nhQl^zw)JL zWFTN$*lPzxfrx}N`TQGioj!Z@(#ld|Wnqbfnahf7F0WuvBsrB{%bVO{T%nN47nu+q zg_@?uDjJeO03uXk%o3ad2Ua%GZM6Y69l@H6J>_JlqhrrBO*J9+IP%8z*h-yhbN#luvsKi7Qx~>P zq{I8$zxCzh)Z~BoPcMJ^?|+;pmxM3+?pyCa z{`a0PWXm%XGynaScY5Lj2k-59``i)){YwIkwZS9x*#%V+nj2S z<8?MLfH?}RiJiI|oZ_g7sG?gv#kU!T)QGG$KG-xYxH^icl{9j?4Q~PUZ6@SeO{`Yw z>Kff;TfOpDHQ+Y82sX>jM=8w~i=&sWoV#!#q)2z|9mr&J*;Gowu$IdnKR7%$we$zy z_>(6;^YQ=TnWubI%BAyH7v_qlu`;*(^2t}`<`>mMPBn~(B9~1yo6e~fO{RFo(gD#* zxgtP-FlAXbO@o;_5?t~qrmBG@1Ovbz00Fmc@1hnU+U7*sGG|SL@Y@oQ;I1FvnskJ1 zD$O^qmTj+J7k;8v{`t3Te4#aK_lKmwi7i)~Iid`|k z@zC9tu6IYgB^ER_0N_3aB}>vTeCZ($BINTfS@7_~hweQ#^ur$}KL5xrtyJg;d3O!P zy%Iit_g$Fd`MK<&!*`X!7L$~iPpmGk^$c`34ZUuq3Omf0b!4M%+H+$cxNFiI2|W

    2{&KC+sStAq>MNBu404z(~GLS&r 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

    H@z_9~klT*5-2YlXG*FdgVkz{=K>^WJM2YUN- zW?i^=K_IekXrOOk`0~|D{*I8u#Q5Zrz=E4be}7Ldlgt+kB}h7hF@srQuUuBkMOE|r zyoRNEh+=Y)%M`sqzan8Q@bYq6H>}!m4ikhC1`u2bvC(%r7z|EMPTEArE=Ml+AWrx5 zAGAnlu_+hyR;ehrB!IUBIoe#%wQSu*O=CMOlsnf)TmB-gREl?YLPI*j+G-*QP1{ab z0H$Fo9;H%IDFFc#3#+Uep>RM`HA*E+F=yN|bSirYM!K#^iWj(LF+nLV7t8)&PzXT@ zE))tLkB7>#U|a|$1mes>gvzp{DCE`WfBe`ppJJBDIR^n4L#bHu_8eT<#ZGez z2!R03O;y!>J|8B8b0IjFWC>$b$mJEUA0vSYMF`YV$z;MK!==&j2OfRM(DgMDz=JKnv2l|#$8NbJ`>6LuCSXMm14B6w&rV0YH3N~b! z9y~CVOXug7lT?-l1|!_UD=RroHxMA;UF9CquFb;-T>_tb-loiBXnIqaGqQ@%em^@<67l_ zty4juA>XX~`?{y4bvD@LPO%klh{oDmWvqpb41bNo(F*N^tv64!SCn&nTP57AN4zn% z-%(OzE`-PHskVp)6%PO?UZ4F0#)L|e{jB2kA%uX)L;?T^M#8mXgW<^fM~tg-O}6vN z=%#q+smBe|k|@E|Ap2k>Vn6Hg`|HhWK&k9mcM7h?*f9qQFH*Sb6ZiBZ)+6d~Bk>CwBb! zJxfb-`0&X;}zi&ewAp!yOrhbf+a_sJk#B#axbA z)`wNB?W+=uM1)Oo)800{Y29dB_aoPDnwGPrMz*rLp{*2!T&r&L&MghzrriQJ&`aAJ z-y3;_Rw@cqDR#AN7T>~XY@3ovyE!FuE!+N!FveJCCsGufsp1X_Lu%Bmp;-=R7nVmS z6zo)XogUP6GT4Q0(v3pWRUWkB2@ygdKpZ%w^vbodwY6j+vl8(@cf50WXfWCt%Vu-u zRW`f4Y-r_J$iJFQETz&!A)Ru^?BWtdaQyH=Zy-3cFvoNwAo->imb^qddgN#}n_XI5 zsu;#Y_uVbYNY|`hh3g=Bg)kva43UmrLy(iQL+CQDgnC9PY6clX2!$@EHv z1tZ=^9yq?Mw^u@z;*~l&f?XZnd_}F8R$0?zna<8G1_J@cL?9^39CF!Gbte}HA;m*Y z)4~9paS(_LE=fp{$sHSpbf;;+O+dVIIq36MQ-ksK{jHk#dVMar=3BILkJOH$#d0~+ z(ZQV>CqNTLs+xQ2`cHKM6^?(!#z5~{*39~3SsPVbTTgNVbaiT06Wz{Pva<~~-)y4> z?3fcxJT@FnYVy8y^U%>+=WmUA|Mik<`OBJ44@Zq|8gP|L7uDT-Jxv*)2DH;z%ZAr< z(V<(9Z}a`m+5YMTfHu~ibD?n|_V)IopH(^zj4`kF)|NG3Xphts+NMiwwJ*a)s^?am zu63VXxM!Uv;YRt|G$WzA#BBsuo0`n8w;3ZOfMPngyz<5yuW~ir8B`Y6l6N0D+S}7d zs2uWphx=n=(=&uyFTMNzPu@PGn+6ehWT-c>mPA4%GugzoE5Tr-kk81nH{|gfoW1kT zyS+U<-LZ~vC^SDlv6#xlqd}%=L;d|Pzx_eEnEAi{x3AC4POm1`a*|j|X73vAT~1}x zioUX#AV>tm0mEwjZ7P^s1+g?1Ti4pAV!QFxHV9+;P>b=qr%s-H=S^6J&D-uQ6*P|x7V)oWu@6XR>e;=ZBb%aqULRIT8^Enm{b3&HL})*jY?Y+1a;$6XrsanHLbMzczp*tnunUU zzv+uOGoM$rUgYvf7-JhjWSrms&?CnV z9oV;bBxp&g7JL5HH(z}B14~#cXY+G&l!D(wJ$^6K%4OYr|Kf#;TG_vQ zSN}j?rl2NQ7FJeQ9{t28j~+O@mMwhm`RB{|Okypgm$cJo&K1g~-e~ZvU-?oxm7bWI zo|~F0bJ#sF*te^9HCe6e2h>4J+R18;pBB6cvk>&!-G^cRqNcs`!bFtb#_80G zt)g)nxbrzQMgTXRQFZk;rHp9BY0z2^mi646H2hiL{?BM-)rM3tMr(-#B1$yq`=`JB z_y57K{no|zPCoMRBj5Vlzx~{ozxvvbp8NdgK7aDu*iT-3_80!)uS>FGS*+=fENqf= zghchTov}nzzk%vE>mQtV+Rs)?yUsIES3;G7KvcnS;kdt6@_Kt}#nuXOROBofHdX=7 zn`^aHzlXZoYfY+atzBrP?_gUfj`dwa#}IbzLiU z6eYGaz8gD4Y#iUl8=8-A8%wfot+}kS+qHh71;dF8O-fVB6qh^gVre_>MYjfmZWY$) z9>rVt!9CoFH=~JYOpnzH@phKbG+@*v6(vGQ2!xRkNCX2x3RYMmJ<(_~7JdEX+smo+ z)WqbmW5+KnuKHv-7LBMCBih$h$mg$3&UQt7$B!H>7K`tkyDThSXYh+(`sL)>$`8K( zy^%e`0e>KuFD4S1o}P|~*FV^ca)koIbaHyiCrbwp9h#k;4=MhlnlsdhHzcFHF}a+i zgqk`F1^k6#IhR)%Kr|NW1(=viN;2*44CQqdBjNEVKEIO8 z6^W=^=!_d>Mk$dbQ7#*Ky_Cu*n84NXnNq1742EtO1no{zv8ChrmK5u4!~wf(Sdg`5%AG_zo`STxqWzxc-2e*J&q zYUchYpGi-TRw^n2-h}YZ(IC_sAg!r)$Q7cjbGB^q)5f|s3{$gapv@p?)U*Lj8&-F7 z!-Q*IjK+szo-)0bWJqog2Q|4Cpgj=wF zZzLUI`}dHqfBoyuhWh<}N-4CC0|wXR(%_ma&>eO#O|!8gXyy-9_kB~Eo4TY9&>~}Y zU7S^&46fstY_+Z171fGz@=$IBs{tW|0HszJy%IJ}^~%(g$Jo#uK99vsi!N7(G`vsz*K;YWgSTec7Olx9#Ze=a8XV<_3_Z`n> zvmS}6rb!Xc4oKNuH4ZPR@F+rqyplyA`v9@ z_xB{yd0C;lZpC||g0ozL&hPw=*XwI#;BQ3xKdd-lUDtJIOx}lK1HMTR79qs%_t)Zp4a*V;VT>!K zk|N838NT=db@80OGNDMRmC^U2`yY`cDhYjZx%AI|`!~W05=!XaV~40GaQ8j;4)n$! zd-REyU;4p44?Wi3(=|9W*w^20GwbQ5=?ezA5Vzk6%K^7;aKds4Lu%!ORn^08j}um7 zpeNiaCoE@c?=UAUgpg&Ley_K-a4MCG&9v-pC%SnM^vzqpHv&Ps*?=1r`8F9D-Mh^F zg*oRK(`xp>>oT&I+NhD}(K!rG&JCxw+Vr^KLY!2q>$-8Jnd-cWzg5#CSas1T5=x~q z&%Ji0qB9IgtyH=?!wXBx1xh6<8@irPX959VK;Vu@=(V>_9yzf0;DOz_VrgYH74&&c zflVVnGc&L2fJYngN*+uhMoDruCU>6!W7cob1F)ZecaOK*R0+2@sk0ka?w zP`r|?R!WEfaG(;=bqfFkm;k`A;-PYHtb25Fi80=E4z!vZtYeQc?I;|B zV9|pgM}(#)c1OE)gupP&yC3@agHL>_Tq=M3nJ)lv#>COPA7G4eW|>UE0N|{Vn!l+U)ve|S+HKLK=(Yy9? z5KGHzoSXfz&W>oTySMKrC*SDoh=%?Cm9=Cxwbt1c>yCAHgomf+S11(-pyE*&!WNd- zlBv#)(4LV2OoSiU)y1`i)l4E=*ge#J@6p4fSFdrbZ~?k$2#i(3DCbKu#{RGeBdTgv zS+zPleBnrRxUc*Di({oyv7+fm_VurEMJ=91&Gz@kzhX0agIsaxO}|H*2|UzH z2(=1-YCHj;76Qqghh$SW;HH&=3n1U3LxgL|&_?rGwFGVUNYftJc5a)WsjDp}tfo?Z zQ!i*}!6?~kC*@oq#A~20=QZa5RL2V0)PCI5o4WDWI+0v=F~$%=k|bG{X<4S=8~`DV zstGbc2qXkxOkg81NSzz@2KdJT)SbI><@HxzTV9y6EL{j8D>NR9Ai*=~Bxi7N{~iFm zu#&(ahWmT4*9)eZnqR(_&k#W4lXJ`{Kl1Q{2M&y=s+vxwv-x6AcO>YKq?4F^7>0su*-ibA3tovC!z zGC&T3M2SFLk|kM|Tn?d)fP~B0rRjm!-8=fDC2s59#nAP%D~i5V{E5|d(e0)Ha>W1u zAOJ~3K~xGuYA5Vx)2B9#@cKuy6$#`A)y@})h!C(rgq%ha&aMWb-%zE z+g1kK&Cp3L*$$LZ6R~ybmlKq3gv2@Lm5PcnSQa%5gL7`9#s~o+)J~ah-^@5e7z>06 zp-r&>_dp20Q%4-Z`T^zI0~k#36*kXRW%G@`GcWuVAInx0k0g5 z#|h9>zN{`SbwssAdh-u!I1DKmZ6?CZ@>%kk97<#7vVXl4-$( z06`E!7;z>{-P8^9HcqEavmv!94%-C1ZzLO1-DR0(&#qk`?vk`EbEv^$daIeR>JTHx z_bolDT9xbwZE8p3{E(TjstvvkOjxcjzP%c6l)FdUwm~(-#tqr4^Hr&bu44Qed*GqaXoSqGwbJMbHX7F;k#04W& zGcd*ifn6gPLaJp+vN@(PLPBs#3o&1q2p5`trl0MPu>%E{BG#>dCBas?rl$>(K- z9^AjXQq236uJN&}m9oB8F7E2@d+d>iS67xY`CKFrER@R0G%Sl1VdbciS+Gt8PtD(}|rkV51(4u8U?w zR9#D@GlDZ)9utBY~V0ZtZ z&*Pn#ntuGz$4{Sr>%`H6Gc(?^m!}RN+;8Z{;?hDosg_EGSlDl9n$M#IJid3&y`M=J z@7gzb=*WJnT+9_qhFbJ0cr}v``)D8>nV*{;+_Sf=mP|EYDY0~>n9dZ}lBs=tq3-)8Xx_W6s_Q+nzgJn`GX}Mg<0YWjRnOYr1CG zuFV)D%d8zXgd|Y}8~`knt)Du%Xh-?GEmV|us23$dGRBr=?U>Pau8;H;ti~X1y0o{q zkbkPYpf^3O+%hUkCO8%taU_ti#V{ZQOaKPP1%jHR6CglXNZLX5Fy2#wQK8vqdF z7C}^F#>(2NT2XB`XAlek3joV9h2WfXh6y2HnI^_al4JmZ3Gyf&fe>SMKol1OGr>S` ziP{)G!X~B^OVpbwmfn5;gKJl>hJs4igG+@%zFcCuJ~KaW=<4(w?(q9U9#qT=%hEbR z!QCUrEQYSl%&#ubf9#$UrDD0iw|`>nO1`L0&dmn`zN^=+eC+NMl~SQQ7E^UYRn2U6 zwNNU2`mskVW+j_SElrON4D3=%IZdFbLi+m$ftj+;bL_~$g~gPiK_*+&b*3ov*j)p| z{n4-_og7>KgKzw?!NgEsG!hO<7#B+wwWwy(`Cur(5$o=bB$GMDMPe<-Ev9JMEo$I5n2fH}u z-j?=!xC{0}(|}zv4K!vZsN3B(H7vCw-5anA0e}P-7$Fe$KL~^X3_@^Q3S$I<3rFOV z9dT6S7!bDc6#%&4NDu)$ozI( zN~rqZqF)tyIdDvR2kr zm2s<7Dh=)G@9FfL2xSslxm5n-Q%@C(#mkpQEsL4Vdhq`Hdb|5hzH_>-r>CNtrm6kh z(@&Pv%00)9&&{ulP0Y#)z3Z;ShYt;f14>W-U^cxf%f9Y-oDk{#(Q8BfafzGpX!M

    +Yiq@HUe$;N731-2N?@8S#NzPdk@#x!-k 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 z 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 wt8^n?FB<{907*qoM6N<$f=3D}AOHXW literal 0 HcmV?d00001 From 0667a26f2ff1aeda80ab2fae2ee49007830720a8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 26 Feb 2012 16:51:18 -0400 Subject: [PATCH 477/484] Add documenation URL --- docs/topics/customization.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/topics/customization.rst b/docs/topics/customization.rst index d02c96a485..83ee7eeabe 100644 --- a/docs/topics/customization.rst +++ b/docs/topics/customization.rst @@ -33,3 +33,5 @@ people without the menu icons, for this **Mayan EDMS** provides the .. image:: no-icons.png :alt: mayan screens with out icons + +.. _`Andrea Franz's excellent web app template`: https://github.com/pilu/web-app-theme From 1f1b9629e58492cf1447d81b78c53a1f75261b76 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 26 Feb 2012 16:58:49 -0400 Subject: [PATCH 478/484] Split documentation and translation chapter from the development chapter of the documentation --- docs/index.rst | 2 +- docs/releases/0.12.rst | 2 +- docs/topics/development.rst | 31 ------------------------------- docs/topics/documentation.rst | 21 +++++++++++++++++++++ docs/topics/index.rst | 2 ++ docs/topics/translations.rst | 8 ++++++++ 6 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 docs/topics/documentation.rst create mode 100644 docs/topics/translations.rst diff --git a/docs/index.rst b/docs/index.rst index c7ffad1fde..0079a21776 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -67,7 +67,7 @@ Customization and fine tunning For developers ============== - :doc:`Development ` + :doc:`Development ` | :doc:`Documentation ` | :doc:`Translations ` Credits diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index b0059814bc..d382caf9cb 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -12,7 +12,7 @@ Overview ======== Aside from new features, the focus of this release of **Mayan EDMS** also -been about improving the code quality standard +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, diff --git a/docs/topics/development.rst b/docs/topics/development.rst index 8521d397af..84f4389653 100644 --- a/docs/topics/development.rst +++ b/docs/topics/development.rst @@ -51,37 +51,6 @@ To familiarize yourself with the technical details of the project read the :ref: .. _docs: -------------- -Documentation -------------- - -The 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 format other than HTML. - -.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html -.. _Sphinx: http://sphinx.pocoo.org - - ------------- -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. --------- Debugging 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/index.rst b/docs/topics/index.rst index f650be46fc..b5ca990d6b 100644 --- a/docs/topics/index.rst +++ b/docs/topics/index.rst @@ -19,3 +19,5 @@ Introductions to all the key parts of Mayan EDMS you'll need to know: settings customization development + documentation + translations diff --git a/docs/topics/translations.rst b/docs/topics/translations.rst new file mode 100644 index 0000000000..0dc2daf1bf --- /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. From db741b9e8b09593ef8202626937adae6ba8bd0cf Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 26 Feb 2012 17:00:51 -0400 Subject: [PATCH 479/484] Fix typo --- docs/topics/translations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/translations.rst b/docs/topics/translations.rst index 0dc2daf1bf..65910f7025 100644 --- a/docs/topics/translations.rst +++ b/docs/topics/translations.rst @@ -2,7 +2,7 @@ Translations ============ -Translations are now being handled online via the **Transifex** website: https://www.transifex.net/projects/p/mayan-edms/ +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. From ce8fb413017d3e3ba77695074aad1d615363fb01 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 27 Feb 2012 10:47:31 -0400 Subject: [PATCH 480/484] Russian translation updated (Sergei Glita) --- apps/acls/locale/ru/LC_MESSAGES/django.mo | Bin 4087 -> 4963 bytes apps/acls/locale/ru/LC_MESSAGES/django.po | 32 +++-- .../locale/ru/LC_MESSAGES/django.mo | Bin 5086 -> 9199 bytes .../locale/ru/LC_MESSAGES/django.po | 120 ++++++++---------- apps/feedback/locale/ru/LC_MESSAGES/django.mo | Bin 563 -> 4086 bytes apps/feedback/locale/ru/LC_MESSAGES/django.po | 53 ++++---- apps/metadata/locale/ru/LC_MESSAGES/django.mo | Bin 12249 -> 12290 bytes apps/metadata/locale/ru/LC_MESSAGES/django.po | 45 ++----- apps/sources/locale/ru/LC_MESSAGES/django.mo | Bin 12097 -> 12184 bytes apps/sources/locale/ru/LC_MESSAGES/django.po | 26 ++-- apps/tags/locale/ru/LC_MESSAGES/django.mo | Bin 4314 -> 4366 bytes apps/tags/locale/ru/LC_MESSAGES/django.po | 10 +- 12 files changed, 122 insertions(+), 164 deletions(-) diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.mo b/apps/acls/locale/ru/LC_MESSAGES/django.mo index 424eb9acbf82dc34649690c9af52155f052185fa..728a991b2b2651b352a62e660df5066527ec98e8 100644 GIT binary patch literal 4963 zcmcJS+iw(A9LJA%uXxA1=n*Y;v9mk77BDLdC=?{N+O&liuhZSr-I3Xu&74_E)kI38 zprFM2i$+X*@bX|qD+TG6sDHqWmqZg|d@;W2i*FjgzcaJlX}gOBw zCBRF-B)AOBfg8Yna3lCi#BafSaK8*nX`db7Qt(mmLU1Q|4Oj*7kG+T=()Sv8Dfj`{ z1|9=9f?r2G7s{ZTZ2|F!^?;;*AbS1~Ncs(s^zQ`8|8bD)J`9o_A4ktmfLG)GN09XX z4&opCGveRiD%_ukAdy@eBs=c|N$wGl)(MdG?*z%NC!^C z8V2>Fj?s=m*KHvfwK)02F_1=N0vxpgv%H*l~Hg1YM`BCZ0oR?=bS7<0fP$H!N2eg;8EI3fwCRUJ-8Dl+tu; zzM{ROahH%Qc+oX%PZUC}9nR1bBJU++GOn&*7VO)-MQKyE#k6#CcF(3BseaTJdCQQv z&F6)bJnz_^>sZ_}rH6;E;G<5J%W5iBI<&Qt6o_PisV!ZLZ1t?b!!Fvjs=qjgoUbO z0~L`s4U27;!j)`?2}70tYSzT-(8IY^L?&jb9io?rgll4p*zG7Y3I%S@hM`fH;lc$k z)#I>m>p{#%d8%ijl__D=m4bPqb;FuG9%TjL8Kxzfs(e;5WUPf*lswBA5*D+KvXB)c zFIc0kV^bNQb7L2@8bcOJ*?~<9)0$Yke3*~+4n?dB)6M!^hfWY}TS41_EaJ$?@?K-q zuzC09-hsA$QE^;P>y<^bpxs+7N^KC9lsvDJO{I#aSE>#r^G-SCI?`}W$4!-KZ3>51 zRmir!2M0CPAyBJrHawB#89klR^o*9y@bv0zM%VN%U5B97FLs%<{XDtMTCR6xGi&b9 zakcdr($fZU0!oY8F3SgmTNI;wt7UoyUssg7*6JI}2wKvuu7|W;tQtk34GN>2<^5G0 zsc@_#GJj-bB&#BM0E4AZ`w=Szkwg_qktxJA3GAxC=-3s>v5^G?CEi&=ixkm=2uo8@k` ztaW)2 zx@f9a=RH>V-X)Nncx8P-&U5W8dJvCU?vjnAEPpxExlx;Ol$t}_&%_l zlmOwPBUIX0ikd{(JjeWZP&=(Ukh-%LHvnP4GF8g4UW{5l)~Kh{I$xZto}m07$VzuG z-uPm{wZoJie@bL`VD7RBj<1fBuY8R!TQ5dMZ#$S-}j;CXl F{R8VxxYPgu delta 1198 zcmXxjZ%7ki9Ki8s>2#Yq|75e&a+X?7*-XjI5+{mU2-b?gf@qC%88?q^^UaD@^dce< z>L_|uy{H!v;fuZNjqfBOh(HNK0t)%SNhAMSUbd!Bpl`F~&AHk)#vYlF}T${r7(%wQCE;wjvRS8yEXu@^t0eCMwy7{W2~qu4L?P}*5W zs;U({i|g2feSX$o9(2}IDm+8!@HIB!63Pl}IBsGyc@GCewkG5_h;q2j;3Pgm`#WTT z75&*;D{b#5_7Xb?Ie+$yW!d)-9YiOwi;w}d5t3vUGE+&iHCsuxMN$pH*z8o#okMOX zS!PMHdXgBAo#f}LCR*uVwcABX1s(Z=?9sEms)dk4x0U2%%i)yO+D^!7$V%)c*iIUm zHq2ma8cic*KV%GHXn3MU&7{egk&c@)M(~(fCt8%?I-GkQ2- zq^zIbTvkt2D4(tV=K2rmjF0yK diff --git a/apps/acls/locale/ru/LC_MESSAGES/django.po b/apps/acls/locale/ru/LC_MESSAGES/django.po index 46ce25ad4c..6ce319b72c 100644 --- a/apps/acls/locale/ru/LC_MESSAGES/django.po +++ b/apps/acls/locale/ru/LC_MESSAGES/django.po @@ -1,24 +1,22 @@ # 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" +"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-02 18:20+0000\n" -"Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" -"ru/)\n" -"Language: ru\n" +"PO-Revision-Date: 2012-02-27 04:26+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:14 msgid "ACLs" @@ -66,7 +64,7 @@ msgstr "Роли" #: forms.py:47 msgid "Special" -msgstr "" +msgstr "Специальный" #: managers.py:116 managers.py:128 msgid "Insufficient access." @@ -94,11 +92,11 @@ msgstr "записи доступа по умолчанию" #: models.py:109 msgid "Creator" -msgstr "" +msgstr "Создатель" #: models.py:112 models.py:113 msgid "creator" -msgstr "" +msgstr "создатель" #: permissions.py:7 permissions.py:8 msgid "Access control lists" @@ -152,7 +150,7 @@ msgstr "имеет разрешение" #: views.py:185 views.py:279 views.py:528 views.py:608 msgid ", " -msgstr "" +msgstr "," #: views.py:186 views.py:280 views.py:529 views.py:609 #, python-format @@ -177,14 +175,14 @@ msgstr "Вы уверены, что хотите предоставить раз #: views.py:199 views.py:542 #, python-format msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." -msgstr "" +msgstr "Право \"%(permission)s\" проедоставлено %(actor)s для %(object)s." #: views.py:205 views.py:548 #, python-format msgid "" "%(actor)s, already had the permission \"%(permission)s\" granted for " "%(object)s." -msgstr "" +msgstr "%(actor)s, уже имеет право \"%(permission)s\" для %(object)s." #: views.py:281 views.py:610 #, python-format @@ -204,12 +202,12 @@ msgstr "Вы уверены, что хотите отменить разреше #: views.py:293 views.py:622 #, python-format msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." -msgstr "" +msgstr "Право \"%(permission)s\" для %(object)s отозвано у %(actor)s." #: views.py:299 views.py:628 #, python-format msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s." -msgstr "" +msgstr "%(actor)s не имеет права \"%(permission)s\" для %(object)s." #: views.py:355 #, python-format diff --git a/apps/document_indexing/locale/ru/LC_MESSAGES/django.mo b/apps/document_indexing/locale/ru/LC_MESSAGES/django.mo index a0d6bd05b166b2e780cb86f2cc88d3a6694f62c7..7652baf180fee61af3d2f82ff5512a774f6dbc3a 100644 GIT binary patch literal 9199 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 diff --git a/apps/document_indexing/locale/ru/LC_MESSAGES/django.po b/apps/document_indexing/locale/ru/LC_MESSAGES/django.po index b8fcb2f9cc..861a51815a 100644 --- a/apps/document_indexing/locale/ru/LC_MESSAGES/django.po +++ b/apps/document_indexing/locale/ru/LC_MESSAGES/django.po @@ -1,23 +1,22 @@ # 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" +"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-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" +"PO-Revision-Date: 2012-02-27 04:22+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:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 #: views.py:280 @@ -30,23 +29,23 @@ msgstr "список индекса" #: __init__.py:33 views.py:74 msgid "create index" -msgstr "" +msgstr "создать индекс" #: __init__.py:34 __init__.py:39 msgid "edit" -msgstr "" +msgstr "редактировать" #: __init__.py:35 __init__.py:40 msgid "delete" -msgstr "" +msgstr "удалить" #: __init__.py:36 msgid "tree template" -msgstr "" +msgstr "шаблон дерева" #: __init__.py:38 msgid "new child node" -msgstr "" +msgstr "новый дочерний узел" #: __init__.py:44 msgid "go up one level" @@ -73,17 +72,13 @@ msgstr "Достигнуто максимальное (%s) число суффи #, python-format msgid "" "Error in document indexing update expression: %(expression)s; %(exception)s" -msgstr "" -"Ошибка в выражении обновления индексов документа: %(expression)s; " -"%(exception)s" +msgstr "Ошибка в выражении обновления индексов документа: %(expression)s; %(exception)s" #: api.py:96 api.py:111 #, python-format msgid "" "Error updating document index, expression: %(expression)s; %(exception)s" -msgstr "" -"Ошибка при обновлении индекса документа, выражение: %(expression)s; " -"%(exception)s" +msgstr "Ошибка при обновлении индекса документа, выражение: %(expression)s; %(exception)s" #: api.py:150 #, python-format @@ -100,9 +95,7 @@ msgstr "Не удается создать индексации каталога msgid "" "Unable to create symbolic link, file exists and could not be deleted: " "%(filepath)s; %(exc)s" -msgstr "" -"Невозможно создать символическую ссылку, файл существует и не может быть " -"удален: %(filepath)s; %(exc)s" +msgstr "Невозможно создать символическую ссылку, файл существует и не может быть удален: %(filepath)s; %(exc)s" #: filesystem.py:71 #, python-format @@ -126,27 +119,28 @@ msgstr "Доступные функции: %s." #: models.py:17 views.py:40 msgid "name" -msgstr "" +msgstr "имя" #: models.py:17 msgid "Internal name used to reference this index." -msgstr "" +msgstr "внутреннее имя, используемое для ссылки на этот индекс." #: models.py:18 views.py:41 msgid "title" -msgstr "" +msgstr "название" #: models.py:18 msgid "The name that will be visible to users." -msgstr "" +msgstr "Имя, которое будет видно пользователям." #: models.py:19 models.py:50 msgid "enabled" msgstr "разрешено" #: models.py:19 -msgid "Causes this index to be visible and updated when document data changes." -msgstr "" +msgid "" +"Causes this index to be visible and updated when document data changes." +msgstr "Этот индекс должен быть видимым и обновляться при изменении данных документа." #: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 #: views.py:195 views.py:225 views.py:265 @@ -163,7 +157,7 @@ msgstr "Введите строковое выражение питона для #: models.py:50 msgid "Causes this node to be visible and updated when document data changes." -msgstr "" +msgstr "Этот узел должен быть видимым и обновляются при изменении данных документа." #: models.py:51 msgid "link documents" @@ -171,17 +165,17 @@ msgstr "связать документы" #: models.py:51 msgid "" -"Check this option to have this node act as a container for documents and not " -"as a parent for further nodes." -msgstr "" +"Check this option to have this node act as a container for documents and not" +" as a parent for further nodes." +msgstr "Этот узел будет контейнером для документов и не будет иметь дочерних узлов." #: models.py:57 models.py:63 msgid "index template node" -msgstr "" +msgstr "узел шаблона индексирования" #: models.py:58 msgid "indexes template nodes" -msgstr "" +msgstr "узлы шаблона индексирования" #: models.py:64 msgid "value" @@ -193,11 +187,11 @@ msgstr "документы" #: models.py:75 msgid "index instance node" -msgstr "" +msgstr "индекс экземпляра узла" #: models.py:76 msgid "indexes instance nodes" -msgstr "" +msgstr "индексы экземпляров узлов" #: models.py:80 msgid "index instance" @@ -221,19 +215,19 @@ msgstr "Индексирование" #: permissions.py:9 msgid "Configure document indexes" -msgstr "" +msgstr "Настройка индексов документа" #: permissions.py:10 msgid "Create new document indexes" -msgstr "" +msgstr "Создайте новый индекс документов" #: permissions.py:11 msgid "Edit document indexes" -msgstr "" +msgstr "Редактирование индексов документов" #: permissions.py:12 msgid "Delete document indexes" -msgstr "" +msgstr "Удалить индексы документов" #: permissions.py:14 msgid "View document indexes" @@ -249,80 +243,80 @@ msgstr "индексы документов" #: views.py:68 msgid "Index created successfully." -msgstr "" +msgstr "Индекс создан." #: views.py:92 msgid "Index edited successfully" -msgstr "" +msgstr "Индекс изменен" #: views.py:98 #, python-format msgid "edit index: %s" -msgstr "" +msgstr "редактировать индекс %s" #: views.py:123 #, python-format msgid "Index: %s deleted successfully." -msgstr "" +msgstr "Индекс %s удален." #: views.py:125 #, python-format msgid "Index: %(index)s delete error: %(error)s" -msgstr "" +msgstr "Индекс %(index)s - ошибка удаления %(error)s" #: views.py:137 #, python-format msgid "Are you sure you with to delete the index: %s?" -msgstr "" +msgstr "Удалить индекс %s?" #: views.py:162 #, python-format msgid "tree template nodes for index: %s" -msgstr "" +msgstr "дерево шаблонных узлов для индекса %s" #: views.py:165 msgid "level" -msgstr "" +msgstr "уровень" #: views.py:186 msgid "Index template node created successfully." -msgstr "" +msgstr "узел шаблона индексирования создан" #: views.py:192 msgid "create child node" -msgstr "" +msgstr "создать дочерний узел" #: views.py:213 msgid "Index template node edited successfully" -msgstr "" +msgstr "узел шаблона индексирования изменён" #: views.py:219 #, python-format msgid "edit index template node: %s" -msgstr "" +msgstr "изменить узел шаблона индексирования %s" #: views.py:226 views.py:266 views.py:334 msgid "node" -msgstr "" +msgstr "узел" #: views.py:248 #, python-format msgid "Node: %s deleted successfully." -msgstr "" +msgstr "Узел %s удален." #: views.py:250 #, python-format msgid "Node: %(node)s delete error: %(error)s" -msgstr "" +msgstr "Узел %(node)s - ошибка удаления %(error)s" #: views.py:259 #, python-format msgid "Are you sure you with to delete the index template node: %s?" -msgstr "" +msgstr "Вы уверены, что нужно удалить узел шаблона индексирования %s?" #: views.py:283 msgid "nodes" -msgstr "" +msgstr "узлы" #: views.py:316 #, python-format @@ -339,9 +333,7 @@ msgstr "Вы уверены, что хотите перестроить все #: views.py:364 msgid "On large databases this operation may take some time to execute." -msgstr "" -"В больших базах данных эта операция может занять некоторое время для " -"выполнения." +msgstr "В больших базах данных эта операция может занять некоторое время для выполнения." #: views.py:370 msgid "Index rebuild completed successfully." @@ -359,9 +351,9 @@ msgstr "индексы, содержащие: %s" #: conf/settings.py:22 msgid "" -"A dictionary that maps the index name and where on the filesystem that index " -"will be mirrored." -msgstr "" +"A dictionary that maps the index name and where on the filesystem that index" +" will be mirrored." +msgstr "Словарь, который отображает имя индекса и где на файловой системе он будет отражен." #: templates/indexing_help.html:3 msgid "What are indexes?" diff --git a/apps/feedback/locale/ru/LC_MESSAGES/django.mo b/apps/feedback/locale/ru/LC_MESSAGES/django.mo index 70c16f79685167da158ae837b41d45e7d59068a1..de875a435ff73a2a31a0bba1475f658c49684dfb 100644 GIT binary patch literal 4086 zcmbW2-ESOc6~+f>`7r%}a>Ylb7o$coc)hzORjW-LL(>FR#A-+k6_?}P*Y@DqnbCaM zT`5$FLr5xzSXAN$(LyA|4L7!H*PGaJ;DQToVCDt{Nc<68ATE&Lch2l)*P#uRu{>vH z-t#`^InO!o*}p#Z$d4SZPx1db{clS}p`8e-C z$Btk(uo8a{`xw~2#r}f#KYYY-MzP-|_-C*`!#)kyJ?t^w|MW4qVxIuy&)6?w|BihW zaN+e&>|d~7c&yClU)Y5A*9dkI`#0=QvEdVr)4@LZWQqGaR&+SP3eNAbA{j<6+z(yQ zQH}c_k-;Ga=PCY4L371ut{=t|Eld`XTdMrW0l+wZ3n%#JFb8ON~1hW~o^WS9HyVP|HSs*cqZB6v~f70nO2uFN_<3 zxAC%#$4%1@vsTp)o31}@7TvhDB49~mo5|R;b2^UUn`CosFBNFmw~w1=k_qRGwXHd~ zx#W-xc&6ngTnLR97+LCNW?ac6gM|s_hxx5|=^`t>7c3dUmn;;s zw{f~3aLL-JA1z4TW=aI1=cZm5$gaMF$s(1)O|4P%mR+`f7_}*1A~g%=ZA@~BiLH-Q zOT33mG`r|RMrt6%8;GH_=6gC!IIk?al-Igx7F%!+W#y)63`MX72K*#-X@)EjQ7I?5 z%`iy37JBqQPCpc}MNcUuFKB7qY?2Ca7JvadUjg;nk#8l@2f)w)#UMP%Wq|*^YUS?Ism@y`br5EyB7c zTI?hqU2DotHf|L8o*OhRslGSYD2tnmuFC$XWAaY-6%ksU54;aIBoS%btXP zz;E(7Q#;mpw*I9W*T`8nNh`Cl8zgjj7&puX8!sUE*L*K^&54C%`MKIxB;$!VJBfF& zkhu%CGHcy-!<^5O1a-~P9{rV-l?hs!mYuh+P6RfsG6qGAq#BiZRBWrAR2hc~Q;oCg z*vQOFGp7eq)hB8rr$SmOfLA9X!PLGAkneiIaYLEn#HLf@7sk%9G#K>dq^HcS@ znKm_pJMSl_Ci_b#rjE&@?x>xp*UZI>cI>m`?UL-K~iAK7=HwV@n+A&Yf>E%UdE>-cPnH-#XUxRaASN=|oB4>)$y z5o_fSDcm+?St`hVU1)C66uZR@C;tf%-VyOkDL1>y3aiS+nuH%H{jjpqUV@<&AXGQM zr|nwy>~#%6V6D59cuPxDTtfmW3YwL1MW5X=Z9eZv`wmMD1jVHdpteW42l?$@7$JIH za?=oK^=_%j_Ts9FCH=4MtsCiLMY~H-8isqX+q*pU1SNn}>n63kh6801vHAz0CzGIE zF4Ln?E)kH#q%pUMESc`WSPAUvT}r)5XvFIs&uuOJ+eEr5>1Y^Sy7_Hw8Z8|h??P-% zU54}_?OSrv*e7kmQGkyWmjhFF%C6LO!pVOuY2pMscu5qPf!Sl(9Re*2v&pR3?sM#A z*=47UgF{7=k+D+q36C5#glALNRF@ITTDC@F1*p z5c1OUqT~(|yszAJXv)F3t|ve!YNn_w!fk5@YL>!dUzP95wCze6cX(&0>Oj)t`@e)Q z=h@YguSP9fX$v4}Cuz$=*!?M>oTOE@hRY*ES0O|XvGlOLG|KeB9R?$P5%Bk&jq5gQnLIh&;Jn&;k^Z{duEPZ9* z$Dx)InBoUiXh#MN9}Ykn;K)!Z*7$YQO_Ct(R;)Li!Tixf!p3rz3jwNH4ur1rZ_uBP AoB#j- delta 168 zcmew+znR72o)F7a1|VPrVi_P-0b*t#)&XJ=umIwpKuJp=4N?OGlTWakO;%-dVK*>R zFto5Tnq0spVH}j7lv-4huMm`9oLH2ZuV7OI5zs4w2, 2012. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: \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-02 18:21+0000\n" -"Last-Translator: Roberto Rosario \n" -"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" -"ru/)\n" -"Language: ru\n" +"PO-Revision-Date: 2012-02-27 04:51+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:9 msgid "Feedback" -msgstr "" +msgstr "Обратная связь" #: forms.py:16 msgid "" "What features of Mayan EDMS attracted you to start using it or consider " "using it?" -msgstr "" +msgstr "Какие особенности Mayan EDMS побудили вас использовать её или рассмотривать вопрос об использовании её в документообороте?" #: forms.py:24 msgid "What features would you like to see implemented in Mayan EDMS?" -msgstr "" +msgstr "Какие особенности Вы хотели бы видеть реализованными в Mayan EDMS ?" #: forms.py:32 msgid "" "Could you tell us a bit about how you are deploying or plan to deploy Mayan " "EDMS (OS, webserver, cloud/local, hardware specs)?" -msgstr "" +msgstr "Не могли бы Вы рассказать нам немного о том, как вы устанавливаете или планируете развернуть Mayan EDMS (ОС, сервер, облако/локально, спецификации оборудования)?" #: forms.py:40 msgid "" "What features of Mayan EDMS did you find hardest to understand or implement?" -msgstr "" +msgstr "Какие особенности Mayan EDMS вы нашли трудным для понимания и реализации?" #: forms.py:45 msgid "Would you be interested in purchasing paid support for Mayan EDMS?" -msgstr "" +msgstr "Вы были бы заинтересованы в приобретении платной поддержки Mayan EDMS?" #: forms.py:50 msgid "" "Are currently providing or planning to provide paid support for Mayan EDMS?" -msgstr "" +msgstr "В настоящее время вы осуществляете или планируете предоставлять платную поддержку Mayan EDMS ?" #: forms.py:55 msgid "Would you be interested in a cloud hosted solution for Mayan EDMS?" -msgstr "" +msgstr "Вы были бы заинтересованы реализации \"облачного\" решения для Mayan EDMS ?" #: forms.py:60 msgid "" "Would you be interested in a turn-key solution for Mayan EDMS that included " "a physical server appliance?" -msgstr "" +msgstr "Вы были бы заинтересованы в решении \"под ключ\" для Mayan EDMS, которое включало бы и \"железо\"?" #: forms.py:65 msgid "Your name:" -msgstr "" +msgstr "Ваше имя:" #: forms.py:70 msgid "Your email:" -msgstr "" +msgstr "Ваш адрес электронной почты:" #: forms.py:75 msgid "Company name:" -msgstr "" +msgstr "Название компании:" #: forms.py:80 msgid "Company website:" -msgstr "" +msgstr "Сайт компании:" #: forms.py:85 msgid "" "May we display your company name & logo in our website as a user of Mayan " "EDMS with a link back to your website?" -msgstr "" +msgstr "Можем ли мы показывать название компании и логотип на нашем сайте в качестве пользователя Mayan EDMS со ссылкой на ваш сайт?" #: forms.py:90 msgid "" "May we keep your contact information to keep you up to date with " "developments or oferings related to Mayan EDMS?" -msgstr "" +msgstr "Можем ли мы сохранить вашу контактную информацию, чтобы держать вас в курсе новостей разработки или других событий, связанных с Mayan EDMS?" #: views.py:20 msgid "Thank you for submiting your feedback." -msgstr "" +msgstr "Спасибо вам за отзыв." #: views.py:23 #, python-format msgid "Error submiting form; %s." -msgstr "" +msgstr "Ошибка при отправке формы; %s." #: views.py:28 msgid "feedback form" -msgstr "" +msgstr "форма обратной связи" diff --git a/apps/metadata/locale/ru/LC_MESSAGES/django.mo b/apps/metadata/locale/ru/LC_MESSAGES/django.mo index efedbd631bb30e50210a02fde4e5996268ab8c13..c0c818435144006367672731ece49f5b11398d89 100644 GIT binary patch delta 2141 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 e=tL~^YpoBG``r diff --git a/apps/metadata/locale/ru/LC_MESSAGES/django.po b/apps/metadata/locale/ru/LC_MESSAGES/django.po index 7b8e7aafdf..851c2f577b 100644 --- a/apps/metadata/locale/ru/LC_MESSAGES/django.po +++ b/apps/metadata/locale/ru/LC_MESSAGES/django.po @@ -3,15 +3,15 @@ # 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: 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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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" @@ -139,9 +139,7 @@ msgstr "поиск" 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:33 models.py:58 views.py:353 views.py:398 msgid "metadata type" @@ -259,8 +257,7 @@ msgstr "Ошибка при удалении индексов документа #: 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:102 #, python-format @@ -291,9 +288,7 @@ msgstr "Редактирование метаданных для докумен msgid "" "Metadata type: %(metadata_type)s successfully added to document " "%(document)s." -msgstr "" -"Тип метаданных: %(metadata_type)s успешно добавлены к документу " -"%(document)s." +msgstr "Тип метаданных: %(metadata_type)s успешно добавлены к документу %(document)s." #: views.py:164 #, python-format @@ -316,17 +311,13 @@ msgstr "Добавляйте метаданные типа документов: 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: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:281 #, python-format @@ -423,7 +414,7 @@ msgstr "Вы действительно хотите удалить набор #: views.py:538 views.py:556 msgid "Metadata types" -msgstr "" +msgstr "Типы метаданных" #: views.py:594 #, python-format @@ -444,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?" @@ -464,13 +452,4 @@ msgid "" " 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" -"Краткое имя служит для выбора из списка значений в результатах поиска." - - +msgstr "Тип метаданных определяет характеристики информации которая может быть присоединена к документу. Примеры типов метаданных : имя клиента, дата или проект, к которому принадлежат несколько документов. Имя типа метаданных является внутренним идентификатором, на который могут ссылаться другие модули, такие как модуль индексирования\n\nИмя это значение, которое показано пользователям\n\nЗначение по умолчанию - значение экземпляра этого типа метаданных будет на начальном этапе,\n\nКраткое имя служит для выбора из списка значений в результатах поиска." diff --git a/apps/sources/locale/ru/LC_MESSAGES/django.mo b/apps/sources/locale/ru/LC_MESSAGES/django.mo index 363361635b71ba16256fbbb830126687f84dad06..4a4717424c047d12397031fcd9d87662c4a99a1b 100644 GIT binary patch delta 2713 zcmZA2drXye9LMn=Hv#1$h(H2zD32l{AdsMo>mV^*hgVp5OKRdpOlN z?DBpWA9~PG28dMRT!=9vxFeho%GF3?X5chtD3;(cOu;Ek!{AxQ zWTFG-VinFt7xJ9fbWus-!XOsoJ`BaPs2_fgYw!mQ!}O>?Lr&Clt1ucHFah1D0S%x! z_Tnvg6qn*hsDWR_Mf7hRJe|yiN>qbx)Bpyt3?E0$=p+{4Bx*%sV*=k3v4-!}$SpIB z8t5yy1droJ{0h~sGu9X_ZWgA}zsaYPftyerb>lpI7PIgus-Z7%G2TRVw3y{#5~c{} zV>zmwCd|esaS^_S8sImm70HYXOspQg3%IbKiXME&_G{Ei+`zRsC*BwaZ#H8gdXVik zhfp2Aj7#w}I`LP`$K*MImDqrKz8<+{wjpU`dgrkIs_f)~mUIvDXP)Cj4IjpIJcU}i zOUUHS6lw{tp_1w^Bt1+5383FOY@MiF$U<#N0cs#CP|sH;u>QJG#|15^3)NsdCgKp% zwmF3SnK$^*KtDz`a2ECa1=PSUp(Zqq>hOkrKZr(ke>Q4m9jFy7_EOQFu0!orJ8DY~ zqV{kcwPZh{_WC+%py7;8GncTJMakBV+Kb;{d#+;?4vS* zrI<_R6=5gdjjy7T=1)`-I>}JRVCwO9Y{5btK@I2vY9f>9#t>dA8i)tWum_i+5BZ7L zT&ALif_PhKDT`1eT#ssa7&qZ(=)yD-<3ZesWjKlIFqK5n0LrluYmhOUuck#sTp zQ7dvBv+x9##$t(oidKbf zH@$?L&~oa9)I+EP4N6O1Lxd6<)T4xsu!_U_3`|nTStXL#N<2V#>-eZ3wh@~Nm3(3g zp^=h9Rt|vKK%@}L_Wu_qYTAi(`v#}dI@bD1;#;Me&pU}S!bP;{{A>3AEy`?_5aJ=L z7C65TQ@?}QNNA5$SbgiY+=11)Kt!mjJ2G!pTIPDdwEOOz5_LN<#0CJVHsT1k-z?n}{NGVo0-p%Svj#bCI5) z=;qF*{&r7CpQCTE%j3(ObtWXVwzI?IyApFOJR-lykyp4fzwp3IiAgC9o}L!ZprfL# zwa@J+Y3Us($}4Mkx3=Z<^dI;su_~g?-OZ~H&gRsZ|k{eX*a`Yz6UVn*1Ae{5p6uOZ_~^xsXn9XkL3 delta 2651 zcmZA1drZ}39LMo5H@O~B7dS$wIeUvr)-1+G^RHw%(s}PObHf?|D7^&hPx5@AG}0 z=Xb1gsw41iTI^Ay`H8!TPh!lD}#w@ddZKhMjg`F6Sub^&x4L9Pu7>Cy}1Lu(+T3m{m1D9hu7NH*O zMh)12OVNiVco>!NS-cnLFq`o$ji=~=MW_TeqZ{i{Gnv2&dlL z3zg_TEW-WRgeOtOoJUpoCa%ErRG!cHwwBH^Y{NnvL_Odb7T{;dSoRB&wB5$LF_ALq zLHSsWji{N8pb|TQs>BU+W9DMBJbVoGy8{?d=S@1Qz$9+M86-)|Ni(a&LSz}O6E*N& zEWrs}g&&~{zd==C(US1*Gm%TS3fVSR6>$@)l1)pfKYiQAhaTLAx%dKVDNZ4iwf9gZ z{1~+dK1H^HT|wP98*vV`2j)?U{E3>#U#QH$Yk4|o-o*eTS^K12;T8TtM~wCOc4TsQ*>6 zGpMybkIM8SYGzka1AZUz20EkJRH*y2vsqtUg$Hm9Tk#fZ;3kg5OSm6vF_6H{yPr-y zw&OTz^Gzeqv?z|ieVB!n*o;c#In)dep$CJg1Txs-Zd{4w*o}N;M^VrD09C;sk;DS_ z2OT}Qp0~wT9K%k$guAhXjp4>ar~xmc68IfE@D7rz?PBAs#}QPigQ$s|!wH;2Ers71 zPT(+Z)cJpd&a-@RHS$F}M}nNJ8&~2ul8e2Kr8tEf@mH+HHQeMzFDk+J@gAJPI=qc* za0?fApdUBj7dXoJ=3oO<;Xxe2Db&o%I9rYQBC0Z1P?aiJZT38NAeZbK`Z0mg$;rlW z8=k=J_#3uhLw>j-ucJ2g1q^7@U81A&d<(Vt^4TeRb*@LP)pjhz9^8UQB3?$7ekosS zhLxz__h1>0pib3kOv3Z1J@Ps7PO`5HslNvJi3=Hc6ZIem3s-|1kmPL?U3e1L;WTQd zsbnw9Q4idPp#)Hs89}OS$0OILQ1@L%E%9tI^;ajF>1&`|RK|6<6FaaC&*EluumNN% zlB*p>4K#^L)1G!l9tsj>jG_< z*c$3_L{Vp6t&Zp+sB~!W>_ZQs)<>igIz4Lc(5F5aKOypuj?6AX>!;%}NHh^Tt3!m7 z(C*hhQHu*>4`6hp&jAWG9mjGakBBE8C47X7$RX5tBZmj4e%IqBYbr zdk7yVN(r472eFp$63Ik0!9M-BRRymn?uiQaC7+847N(w#Z!32>%hy%ADvHWzNll(% ze@VN~Gc-Kl@q2yM&NgpXug~wrVUMrh>#XsGFO>Si7fSoQL!+L7-cfhopr?PJwA(xQ da!OW1tiRVY7~GxpR!nepPGCXs%!;2Ke*;;?23!CD diff --git a/apps/sources/locale/ru/LC_MESSAGES/django.po b/apps/sources/locale/ru/LC_MESSAGES/django.po index d7d3588f4a..9683a35df2 100644 --- a/apps/sources/locale/ru/LC_MESSAGES/django.po +++ b/apps/sources/locale/ru/LC_MESSAGES/django.po @@ -9,9 +9,9 @@ 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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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" @@ -76,8 +76,7 @@ msgstr "Извлекать из архивов?" #: forms.py:35 forms.py:60 msgid "Upload a compressed file's contained files as individual documents" -msgstr "" -"Загрузить файлы, содержащиеся в архиве в качестве отдельных документов" +msgstr "Загрузить файлы, содержащиеся в архиве в качестве отдельных документов" #: forms.py:43 msgid "Staging file" @@ -235,8 +234,7 @@ msgstr "интервал" msgid "" "Inverval in seconds where the watch folder path is checked for new " "documents." -msgstr "" -"Интервал в секундах, между проверками папки на появление новых документов." +msgstr "Интервал в секундах, между проверками папки на появление новых документов." #: models.py:237 msgid "watch folder" @@ -330,9 +328,7 @@ msgstr "Интерактивные источники документов не #: 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:163 msgid "New document version uploaded successfully." @@ -408,11 +404,11 @@ msgstr " файлы в транспортном пути" #: views.py:320 msgid "Current document type" -msgstr "" +msgstr "Текущий тип документа" #: views.py:321 msgid "None" -msgstr "" +msgstr "Нет" #: views.py:328 msgid "Current metadata" @@ -512,9 +508,7 @@ msgstr "Ошибка при удалении преобразования ист #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" -msgstr "" -"Вы действительно хотите удалить источник трансформации " -"\"%(transformation)s\"" +msgstr "Вы действительно хотите удалить источник трансформации \"%(transformation)s\"" #: views.py:689 msgid "Source transformation created successfully" @@ -529,5 +523,3 @@ msgstr "Ошибка создания преобразования источн #, python-format msgid "Create new transformation for source: %s" msgstr "Создать новое преобразование для источника: %s" - - diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.mo b/apps/tags/locale/ru/LC_MESSAGES/django.mo index 0a0bc49abca6303b1ee385ef2619871fb03d989f..52c652c98d35699a2f3f5e474600a1f8aa16ba21 100644 GIT binary patch delta 1180 zcmXxjTS!xJ9KiAa+MJg(O_Nf)9PieeF1J+Hg{VYU5oA#>y&P(d*)-dx<t1wr)vZO6ko|Ihz+e*fD!pDS-vCB7CrZY!=< zo{c;UHl+eMYA4~Eawx^Erb$ZhDQ?HN=*Hhxxi%|P?!*n$4-xq zs25~bQ!$5C_zrV%3G49>=A-7!1ahOadodgL;AU(`8SpG}t1yYIp%=?Bj$801O8?2U z38m)A$jW}A%-lv)u^c6!7iGXUtj7IFS9K2aup8InWn`{u1lQm#tNj5={|T(XX_UC{ zF`x0(2Qu7hkwiLvLz(#!=HN0)z`t08c~r`dRGp1Y$1_> zJ5W~IiE`#$C=(qnmjshL^Z5MDK9`3p?}#3YyH7;*o>)YWUx@m(O9g6k0diHhe;Yee& zFIkft$cgAZp*}qnOkKpGG-X>yLgc1-Nta41s*N<5)a@qMsVFJ`)exY)3}@ZyGWBMBA1zQoJB9?Ii$T{ zUXj^G#Ucjr9eQvLd+;|lqOZ0x&^}aq2%v;eMROGq~)u|3i(_+GNZw3}Q15 z;Ss#l#Q7^U(@w)9)CBW5h>NI?@~2}pjXJ{)?7%(+F`uZ z=ML8>cKxL>cbh*-ZY%l8XwukH(LL%~TCa0eC1deG?C4N@Aly%CxM)q~A|qLAaw=ox z?Cek=Y2Qd?b2d&{*>O8?JX@)VW-ArZv^|-(GO7H@^n^8@iQcp)N?o2|cP?d3EZy@w KsVyaZU;YE8^LLp5 diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.po b/apps/tags/locale/ru/LC_MESSAGES/django.po index a51cbebc53..4ac1a23f22 100644 --- a/apps/tags/locale/ru/LC_MESSAGES/django.po +++ b/apps/tags/locale/ru/LC_MESSAGES/django.po @@ -9,9 +9,9 @@ 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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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" @@ -56,7 +56,7 @@ msgstr "ACLs" #: __init__.py:34 msgid "preview" -msgstr "" +msgstr "предварительный просмотр" #: __init__.py:38 msgid "tagged items" @@ -246,5 +246,3 @@ msgstr "Вы действительно хотите снять метку: %s?" #: templatetags/tags_tags.py:17 msgid "Add tag to document" msgstr "Добавить тег к документу" - - From 8e395f54eecb87f736d528b53ab8032d89d3f81a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 27 Feb 2012 11:07:19 -0400 Subject: [PATCH 481/484] Add section headers to the customization chapter --- docs/topics/customization.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/topics/customization.rst b/docs/topics/customization.rst index 83ee7eeabe..927bced0d3 100644 --- a/docs/topics/customization.rst +++ b/docs/topics/customization.rst @@ -5,6 +5,9 @@ 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. @@ -15,6 +18,9 @@ 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. @@ -22,11 +28,17 @@ 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. From b743521cee4399017152a9a51b6cf6c65b81f340 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 27 Feb 2012 11:07:45 -0400 Subject: [PATCH 482/484] Add descriptions to some settings --- docs/topics/settings.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst index 5d17d1779e..ae395a435e 100644 --- a/docs/topics/settings.rst +++ b/docs/topics/settings.rst @@ -520,6 +520,8 @@ Controls whether the search functionality is provided by a sidebar widget or by 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 @@ -527,6 +529,8 @@ Default: ``False`` Default: ``False`` +Turns off navigation links' icons. + User management =============== From 504a215c22ab628fe2a9f3054201cdaa92a14fd1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 27 Feb 2012 11:16:20 -0400 Subject: [PATCH 483/484] Added another example to the debug section --- docs/topics/development.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/topics/development.rst b/docs/topics/development.rst index 84f4389653..5ef1e680d6 100644 --- a/docs/topics/development.rst +++ b/docs/topics/development.rst @@ -57,7 +57,7 @@ Debugging --------- **Mayan EDMS** makes extensive use of Django's new `logging capabilities`_. -To enable debug logging for the documents app for example add the following +To enable debug logging for the ``documents`` app for example add the following lines to your ``settings_local.py`` file:: LOGGING = { @@ -90,4 +90,15 @@ lines to your ``settings_local.py`` file:: } } + +Likewise, to see the debug output of the ``tags`` app, just add the following inside the ``loggers`` block:: + + + 'tags': { + 'handlers':['console'], + 'propagate': True, + 'level':'DEBUG', + }, + + .. _`logging capabilities`: https://docs.djangoproject.com/en/dev/topics/logging From d84a42769fa8adc4023bc544adb492d9c3ea44f3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 27 Feb 2012 12:50:46 -0400 Subject: [PATCH 484/484] Bump version to 0.12 --- apps/main/__init__.py | 2 +- docs/conf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index e437a2ff9c..97aa7458f4 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -22,7 +22,7 @@ __version_info__ = { 'major': 0, 'minor': 12, 'micro': 0, - 'releaselevel': 'beta', + 'releaselevel': 'final', 'serial': 0 } diff --git a/docs/conf.py b/docs/conf.py index 06e2d962ad..ded1ddc7f8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -55,7 +55,7 @@ copyright = u'2011, Roberto Rosario' version = '0.12' # The full version, including alpha/beta/rc tags. -release = '0.12 beta' +release = '0.12' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages.

    7qSb@Z=svbsqnR}8M~CL*}1G`l$T$GpLP8Mvc-Xz delta 912 zcmXZaKWGzC9Ki9PNm|=jX;l(!leX8^f1zHzOM{g|v=GH5+Ej`nT|Dpz0li2r26XV~ zCPHzzNf!sZh>K7tC=?e_M67OcsvszIa1jTc^!saaJl^Nsd%wHi@4dUF3m-}^vhncg z4w31U$dHJ%(jo`&7f#}?{UR~eXYhGU#9?uq`5y!y!`_U@6rRA-=%IrvsBvF$1Y_B@ zW2kv%(Z;2|_n3(MnSyn+|;9-hIEcolb#wG&oQ z<04GpE8K~%ktXlxw6Lv^fyp4nd0oaLPUBDDcsDU, 2011. # Renata Oliveira , 2011. msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-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:21 __init__.py:23 @@ -36,7 +35,7 @@ msgstr "adicionar metadados" msgid "remove metadata" msgstr "remover metadados" -#: __init__.py:29 models.py:34 views.py:315 +#: __init__.py:29 models.py:34 views.py:316 msgid "metadata types" msgstr "tipos de metadados" @@ -52,7 +51,7 @@ msgstr "excluir" msgid "create new" msgstr "criar novo" -#: __init__.py:34 views.py:415 +#: __init__.py:34 views.py:416 msgid "metadata sets" msgstr "conjuntos de metadados" @@ -60,7 +59,7 @@ msgstr "conjuntos de metadados" 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'" @@ -93,7 +92,7 @@ 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" @@ -145,11 +144,11 @@ msgstr "" "Digite uma expressão a ser avaliada. Exemplo: [user.get_full_name()para o " "usuário em User.objects.all()]. %s" -#: models.py:33 models.py:58 views.py:352 views.py:397 +#: models.py:33 models.py:58 views.py:353 views.py:398 msgid "metadata type" msgstr "tipo de metadados" -#: models.py:48 models.py:49 models.py:57 views.py:467 views.py:513 +#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514 msgid "metadata set" msgstr "conjunto de metadados" @@ -169,7 +168,7 @@ msgstr "documento" msgid "type" msgstr "tipo" -#: models.py:76 views.py:303 +#: models.py:76 views.py:304 msgid "value" msgstr "valor" @@ -177,7 +176,7 @@ msgstr "valor" msgid "document metadata" msgstr "metadados do documento" -#: models.py:91 views.py:581 +#: models.py:91 views.py:599 msgid "document type" msgstr "tipo de documento" @@ -245,74 +244,76 @@ msgstr "Excluir conjuntos de metadados" msgid "View metadata sets" msgstr "Ver conjuntos de metadados" -#: views.py:40 views.py:203 +#: 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:51 views.py:143 views.py:215 +#: 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:86 views.py:250 +#: views.py:87 views.py:251 #, python-format msgid "Error deleting document indexes; %s" msgstr "Erro ao excluir índices de documento; %s" -#: views.py:98 +#: 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:101 +#: views.py:102 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Metadados para o documento %s alterados com sucesso." -#: views.py:106 views.py:267 +#: views.py:107 views.py:268 #, python-format msgid "Error updating document indexes; %s" msgstr "Erro ao atualizar índices de documento; %s" -#: views.py:108 views.py:269 +#: views.py:109 views.py:270 msgid "Document indexes updated successfully." msgstr "Índices de documento atualizados com sucesso. " -#: views.py:119 +#: views.py:120 #, python-format msgid "Edit metadata for document: %s" msgstr "Editar os metadados do documento: %s" -#: views.py:121 +#: views.py:122 #, python-format msgid "Edit metadata for documents: %s" msgstr "Editar os metadados do documentos: %s" -#: views.py:160 +#: 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:163 +#: 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:187 +#: views.py:188 #, python-format msgid "Add metadata type to document: %s" msgstr "Adicionar tipo de metadados ao documento: %s" -#: views.py:189 +#: views.py:190 #, python-format msgid "Add metadata type to documents: %s" msgstr "Adicionar tipo de metadados aos documentos: %s" -#: views.py:258 +#: 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:261 +#: 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:280 +#: views.py:281 #, python-format msgid "Remove metadata types from document: %s" msgstr "Remover tipos de metadados do documento: %s" -#: views.py:282 +#: views.py:283 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Remover tipos de metadados dos documentos: %s" -#: views.py:301 +#: views.py:302 #, python-format msgid "metadata for: %s" msgstr "metadados para: %s" -#: views.py:319 +#: views.py:320 msgid "internal name" msgstr "nome interno" -#: views.py:340 +#: views.py:341 msgid "Metadata type edited successfully" msgstr "Tipo de metadados editados com sucesso" -#: views.py:343 +#: views.py:344 #, python-format msgid "Error editing metadata type; %s" msgstr "Erro de edição de tipo de metadados; %s" -#: views.py:349 +#: views.py:350 #, python-format msgid "edit metadata type: %s" msgstr "editar tipo de metadados: %s" -#: views.py:364 +#: views.py:365 msgid "Metadata type created successfully" msgstr "Tipo de metadados criado com sucesso" -#: views.py:370 +#: views.py:371 msgid "create metadata type" msgstr "criar um tipo de metadados" -#: views.py:389 +#: views.py:390 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Tipo de metadados: %s removido com sucesso." -#: views.py:391 +#: 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:402 +#: 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:419 +#: views.py:420 msgid "members" msgstr "membros" -#: views.py:463 +#: views.py:464 #, python-format msgid "non members of metadata set: %s" msgstr "não-membros do conjunto de metadados: %s" -#: views.py:464 +#: views.py:465 #, python-format msgid "members of metadata set: %s" msgstr "membros do conjunto de metadados: %s" -#: views.py:479 +#: views.py:480 msgid "Metadata set created successfully" msgstr "Conjunto de metadados criado com sucesso" -#: views.py:485 +#: views.py:486 msgid "create metadata set" msgstr "criar um conjunto de metadados" -#: views.py:504 +#: views.py:505 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Conjunto de metadados: %s removido com sucesso." -#: views.py:507 +#: 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:518 +#: 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:576 +#: 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:577 +#: 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 0984aefc046b59605366b9c1772bae880d2f7ce3..efedbd631bb30e50210a02fde4e5996268ab8c13 100644 GIT binary patch delta 955 zcmXZaPe_w-7{KvItq~eo(yXQCOv}plSIvA?vS?N$lxazJuy?Vx!M3;Fy<<4CT>?X@ z%WgqMH|Y?Tf>0;xQfG;f4&K5;5FI*&(f85q^7%c#z3=lpzvuTpn_QioZ>%bMD@8ip zB8Np}Y@bLg7Vsjz!08H+b^KW+a>pam%l>H7*8flN67e^@g{=q4fe-OCu3{g0nnk+s z8U}F|6ZoN7igJ!cn^!hX;t=s09Kk<0i04~GPT?ag;xZa|=8(uR-p70R1+}3*PVoR| z@Cv%xME2r1MlgjZ@Le0(CRnVo5kiA8kXurC6rW-PE@2O@piZFXh)5J8cmwCq!OC`# ze$3-_TtpYvkZc#$;Q+Sa1)MCF7ju|n<2UN)F|9Ki9PE^M(xg}9s6mXm3kHafFz?KWz8uv*!rwUnTOwpm!Vp=}rUj~V@0 zur77!phQRquihk~qd`$!JVc%9P!x6R(k&{Y?=KyO`MmdL=DpwV_ul)=LS{MatAB0~ z83>AWib!yW$UYpzG0fmC-Y?;IpGa4$$Pvbycdx%cg-QC4@DhH-Nj$zsqo+VHT3Pf$zWeL!S8mN&eE`r|xmDc_=&a#N2;1mmdv zD@bhe82j)!a?1}Mnn<`;qzU7w6{sg^Xl6605iX-H{0s?F-XPm9Kk*PY@s}=`z@2yl z`|%-a=C803edhXtehkoWN1fNi!*~=2bT?}>bZ?fBV<4*=enidaFY1E*q@!DtMa|?c za^7SSwZyBahwUZmS!p0Dwp|?5j4z@FFopX4?Ek(`Vnxk$t=NJ*owoPs;YS@+&v3f18K+3ID&B?M`tQ6d8sq7dNxpF>t u-8fnBs;)7VuT00Rk*ls(=quOeIztm%Qf@I{bMs8dz_rkYl~18xE&l+`u6{NE diff --git a/apps/metadata/locale/ru/LC_MESSAGES/django.po b/apps/metadata/locale/ru/LC_MESSAGES/django.po index ee4c61ba94..7b8e7aafdf 100644 --- a/apps/metadata/locale/ru/LC_MESSAGES/django.po +++ b/apps/metadata/locale/ru/LC_MESSAGES/django.po @@ -1,24 +1,22 @@ # 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: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2011-11-04 10:20+0000\n" -"Last-Translator: Sergey Glita \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-12 19:24+0000\n" +"Last-Translator: Roberto Rosario \n" +"Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/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:21 __init__.py:23 msgid "edit metadata" @@ -36,7 +34,7 @@ msgstr "добавить метаданные" msgid "remove metadata" msgstr "удалить метаданные" -#: __init__.py:29 models.py:34 views.py:315 +#: __init__.py:29 models.py:34 views.py:316 msgid "metadata types" msgstr "типы метаданных" @@ -52,7 +50,7 @@ msgstr "удалить" msgid "create new" msgstr "создание новых" -#: __init__.py:34 views.py:415 +#: __init__.py:34 views.py:416 msgid "metadata sets" msgstr "наборы метаданных" @@ -60,7 +58,7 @@ msgstr "наборы метаданных" msgid "default metadata" msgstr "метаданные по умолчанию" -#: classes.py:12 +#: classes.py:14 #, python-format msgid "'metadata' object has no attribute '%s'" msgstr "объект метаданных не имеет аттрибута '%s'" @@ -93,7 +91,7 @@ msgstr "Тип метаданных" msgid "Remove" msgstr "Удалить" -#: forms.py:86 +#: forms.py:86 views.py:541 views.py:559 msgid "Metadata sets" msgstr "Наборы метаданных" @@ -145,11 +143,11 @@ msgstr "" "Введите строку для вычисления. Пример: [user.get_full_name() for user in " "User.objects.all()].%s" -#: models.py:33 models.py:58 views.py:352 views.py:397 +#: 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:467 views.py:513 +#: models.py:48 models.py:49 models.py:57 views.py:468 views.py:514 msgid "metadata set" msgstr "набор метаданных" @@ -169,7 +167,7 @@ msgstr "документ" msgid "type" msgstr "тип" -#: models.py:76 views.py:303 +#: models.py:76 views.py:304 msgid "value" msgstr "значение" @@ -177,7 +175,7 @@ msgstr "значение" msgid "document metadata" msgstr "метаданные документа" -#: models.py:91 views.py:581 +#: models.py:91 views.py:599 msgid "document type" msgstr "тип документа" @@ -245,73 +243,75 @@ msgstr "Удаление наборов метаданных" msgid "View metadata sets" msgstr "Просмотр наборов метаданных" -#: views.py:40 views.py:203 +#: views.py:41 views.py:204 msgid "The selected document doesn't have any metadata." msgstr "Выбранный документ не имеет метаданных." -#: views.py:51 views.py:143 views.py:215 +#: views.py:52 views.py:144 views.py:216 msgid "Must provide at least one document." msgstr "Необходимо предоставить хотя бы один документ." -#: views.py:86 views.py:250 +#: views.py:87 views.py:251 #, python-format msgid "Error deleting document indexes; %s" msgstr "Ошибка при удалении индексов документа; %s" -#: views.py:98 +#: views.py:99 #, python-format msgid "Error editing metadata for document %(document)s; %(error)s." msgstr "" "Ошибка редактирования метаданных для документа %(document)s; %(error)s." -#: views.py:101 +#: views.py:102 #, python-format msgid "Metadata for document %s edited successfully." msgstr "Метаданные для документов %s изменены." -#: views.py:106 views.py:267 +#: views.py:107 views.py:268 #, python-format msgid "Error updating document indexes; %s" msgstr "Ошибка при обновлении индексов документа; %s" -#: views.py:108 views.py:269 +#: views.py:109 views.py:270 msgid "Document indexes updated successfully." msgstr "Индексы документа успешно обновлены." -#: views.py:119 +#: views.py:120 #, python-format msgid "Edit metadata for document: %s" msgstr "Редактировать метаданные документа:%s." -#: views.py:121 +#: views.py:122 #, python-format msgid "Edit metadata for documents: %s" msgstr "Редактирование метаданных для документов: %s" -#: views.py:160 +#: 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 "" -"Тип метаданных: %(metadata_type)s успешно добавлены к документу %(document)s." +"Тип метаданных: %(metadata_type)s успешно добавлены к документу " +"%(document)s." -#: views.py:163 +#: 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:187 +#: views.py:188 #, python-format msgid "Add metadata type to document: %s" msgstr "Добавить метаданные типа к документу: %s." -#: views.py:189 +#: views.py:190 #, python-format msgid "Add metadata type to documents: %s" msgstr "Добавляйте метаданные типа документов: %s" -#: views.py:258 +#: views.py:259 #, python-format msgid "" "Successfully remove metadata type: %(metadata_type)s from document: " @@ -320,7 +320,7 @@ msgstr "" "Метаданные типа: %(metadata_type)s успешно удалены из документа: " "%(document)s." -#: views.py:261 +#: views.py:262 #, python-format msgid "" "Error removing metadata type: %(metadata_type)s from document: %(document)s." @@ -328,105 +328,109 @@ msgstr "" "Ошибка удаления метаданных, наберите:%(metadata_type)s из документа: " "%(document)s ." -#: views.py:280 +#: views.py:281 #, python-format msgid "Remove metadata types from document: %s" msgstr "Удалить типы метаданных из документа: %s" -#: views.py:282 +#: views.py:283 #, python-format msgid "Remove metadata types from documents: %s" msgstr "Удалить типы метаданных из документа: %s" -#: views.py:301 +#: views.py:302 #, python-format msgid "metadata for: %s" msgstr "метаданных для: %s" -#: views.py:319 +#: views.py:320 msgid "internal name" msgstr "внутреннее имя" -#: views.py:340 +#: views.py:341 msgid "Metadata type edited successfully" msgstr "Тип метаданных отредактирован." -#: views.py:343 +#: views.py:344 #, python-format msgid "Error editing metadata type; %s" msgstr "Ошибка редактирования типа метаданных; %s" -#: views.py:349 +#: views.py:350 #, python-format msgid "edit metadata type: %s" msgstr "редактировать метаданные типа: %s" -#: views.py:364 +#: views.py:365 msgid "Metadata type created successfully" msgstr "Тип метаданных успешно создан" -#: views.py:370 +#: views.py:371 msgid "create metadata type" msgstr "создать тип метаданных" -#: views.py:389 +#: views.py:390 #, python-format msgid "Metadata type: %s deleted successfully." msgstr "Тип метаданных: %s успешно удален." -#: views.py:391 +#: views.py:392 #, python-format msgid "Metadata type: %(metadata_type)s delete error: %(error)s" msgstr "Метаданные типа: %(metadata_type)s ошибка удаления: %(error)s" -#: views.py:402 +#: views.py:403 #, python-format msgid "Are you sure you wish to delete the metadata type: %s?" msgstr "Вы действительно хотите удалить метаданные:%s?" -#: views.py:419 +#: views.py:420 msgid "members" msgstr "элементы" -#: views.py:463 +#: views.py:464 #, python-format msgid "non members of metadata set: %s" msgstr "не входят в набор метаданных: %s" -#: views.py:464 +#: views.py:465 #, python-format msgid "members of metadata set: %s" msgstr "входят в набор метаданных: %s" -#: views.py:479 +#: views.py:480 msgid "Metadata set created successfully" msgstr "Набор метаданных создан" -#: views.py:485 +#: views.py:486 msgid "create metadata set" msgstr "создать набор метаданных" -#: views.py:504 +#: views.py:505 #, python-format msgid "Metadata set: %s deleted successfully." msgstr "Набор метаданных: %s удалён." -#: views.py:507 +#: views.py:508 #, python-format msgid "Metadata set: %(metadata_set)s delete error: %(error)s" msgstr "Набор метаданных: %(metadata_set)s ошибка удаления: %(error)s" -#: views.py:518 +#: views.py:519 #, python-format msgid "Are you sure you wish to delete the metadata set: %s?" msgstr "Вы действительно хотите удалить набор метаданных: %s?" -#: views.py:576 +#: 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:577 +#: views.py:595 #, python-format msgid "members of document type: %s" msgstr "относится к типу документа: %s." @@ -442,8 +446,8 @@ msgid "" "attaches it's member metadata types to said document." msgstr "" "Набор метаданных это группа из одного или более типов метаданных. Наборы " -"метаданных полезны при создании новых документов; указание набора " -"метаданных автоматически добавляет метаданные набора к документу." +"метаданных полезны при создании новых документов; указание набора метаданных" +" автоматически добавляет метаданные набора к документу." #: templates/metadata_type_help.html:3 msgid "What are metadata types?" @@ -451,25 +455,22 @@ 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." +"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" +"Значение по умолчанию - значение экземпляра этого типа метаданных будет на начальном этапе,\n" "\n" "Краткое имя служит для выбора из списка значений в результатах поиска." + + diff --git a/apps/navigation/locale/en/LC_MESSAGES/django.po b/apps/navigation/locale/en/LC_MESSAGES/django.po index 8c2565fd8b..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: 2012-02-02 14:17-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" diff --git a/apps/navigation/locale/es/LC_MESSAGES/django.mo b/apps/navigation/locale/es/LC_MESSAGES/django.mo index 0b9200fe378ac5ccec6b7631a3ed2b5bbe7424c5..7ab9cf55c5c6bd3958daa761e8c05b0b601c1a33 100644 GIT binary patch delta 19 bcmZ3>x|Vgq2M$9c1w&ISBZG}UwlV?$Lgfb0 delta 19 bcmZ3>x|Vgq2Mz-x1w#`nL-UP4wlV?$Lhc6D diff --git a/apps/navigation/locale/es/LC_MESSAGES/django.po b/apps/navigation/locale/es/LC_MESSAGES/django.po index 571dfa9788..3079e51a80 100644 --- a/apps/navigation/locale/es/LC_MESSAGES/django.po +++ b/apps/navigation/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-04 16:58+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/navigation/locale/it/LC_MESSAGES/django.mo b/apps/navigation/locale/it/LC_MESSAGES/django.mo index f83dfbbf5e6dce47bca0cb45d79aa338089c8276..bdb151f775a9c4983122370c95c27ef48b741077 100644 GIT binary patch delta 19 acmZo>ZDyVDfy2;9!O+yo$YA4-Zbkq+sRmO3 delta 19 acmZo>ZDyVDfy2N^!O+CY(0t>MZbkq+vIbWG diff --git a/apps/navigation/locale/it/LC_MESSAGES/django.po b/apps/navigation/locale/it/LC_MESSAGES/django.po index 2745af0b09..957fcd5f25 100644 --- a/apps/navigation/locale/it/LC_MESSAGES/django.po +++ b/apps/navigation/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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/" diff --git a/apps/navigation/locale/pt/LC_MESSAGES/django.mo b/apps/navigation/locale/pt/LC_MESSAGES/django.mo index 1ab3336d64afb5cbba1efe23d67d02c1c919097c..268de030a2c09cbdd2f0eef32e421a352042925b 100644 GIT binary patch delta 19 acmZo*ZD5`7fy2;9!O+yo$YA4-4n_bxHwH=o delta 19 acmZo*ZD5`7fy2N^!O+CY(0t>M4n_bxKn6|# diff --git a/apps/navigation/locale/pt/LC_MESSAGES/django.po b/apps/navigation/locale/pt/LC_MESSAGES/django.po index 36ef8d41f7..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: 2012-02-02 14:17-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/" diff --git a/apps/navigation/locale/ru/LC_MESSAGES/django.mo b/apps/navigation/locale/ru/LC_MESSAGES/django.mo index cd3ec3919abe5b4aaf74ddbc315108798d17fc13..fa4dd7336e05f9f099b1b512edab919125e439af 100644 GIT binary patch delta 19 bcmaFE`i6DF2M$9c1w&ISBZG}UzAyp+Og{&X delta 19 bcmaFE`i6DF2Mz-x1w#`nL-UP4zAyp+Oh^Zk diff --git a/apps/navigation/locale/ru/LC_MESSAGES/django.po b/apps/navigation/locale/ru/LC_MESSAGES/django.po index 225b790211..dffe342d8a 100644 --- a/apps/navigation/locale/ru/LC_MESSAGES/django.po +++ b/apps/navigation/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-19 21:05+0000\n" "Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/ocr/locale/en/LC_MESSAGES/django.po b/apps/ocr/locale/en/LC_MESSAGES/django.po index ca083755a5..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: 2012-02-02 14:17-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,61 +17,61 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:31 __init__.py:32 +#: __init__.py:32 __init__.py:33 msgid "submit to OCR queue" msgstr "" -#: __init__.py:33 __init__.py:34 +#: __init__.py:34 __init__.py:35 msgid "re-queue" msgstr "" -#: __init__.py:35 __init__.py:36 __init__.py:49 +#: __init__.py:36 __init__.py:37 __init__.py:50 msgid "delete" msgstr "" -#: __init__.py:38 +#: __init__.py:39 msgid "stop queue" msgstr "" -#: __init__.py:39 +#: __init__.py:40 msgid "activate queue" msgstr "" -#: __init__.py:41 +#: __init__.py:42 msgid "clean up pages content" msgstr "" -#: __init__.py:41 +#: __init__.py:42 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." msgstr "" -#: __init__.py:43 +#: __init__.py:44 msgid "queue document list" msgstr "" -#: __init__.py:44 __init__.py:62 permissions.py:7 +#: __init__.py:45 __init__.py:63 permissions.py:7 msgid "OCR" msgstr "" -#: __init__.py:46 +#: __init__.py:47 msgid "transformations" msgstr "" -#: __init__.py:47 +#: __init__.py:48 msgid "add transformation" msgstr "" -#: __init__.py:48 +#: __init__.py:49 msgid "edit" msgstr "" -#: __init__.py:69 +#: __init__.py:74 msgid "Default" msgstr "" -#: __init__.py:97 +#: __init__.py:102 msgid "Checks the OCR queue for pending documents." msgstr "" diff --git a/apps/ocr/locale/es/LC_MESSAGES/django.mo b/apps/ocr/locale/es/LC_MESSAGES/django.mo index 4a3d4d8b4fe6ae5f1dcdc5ebd818a9b6a8a155eb..4b72681b3c35908e96e65bc152498c6cd290ddbd 100644 GIT binary patch delta 2375 zcmY+_e`wTo9LMqZF6Z2=nKS2Rso(s)Hr;JH-BxqA<|=jNHv2I(t?%x>TbK8%yPbvw zr-(s@S*(J=pd!eBB!UZ+N{Eb9P$>!uN^1r|45dPf{*j)q+a2nMeeUu3e!rjZ=jZ$L z-Q~cg&djBXDQ_ETJNX{+HJ@1q&lU4SI#Xii;#pjcwbRU+@mXAjqp17maRd5FC+~M- zJ=gotj~}DzjiZB=WjQmpmO>*p`mq*Y!)16JXW}nN-}Vg{H;(2u%ak8PT2j6#4L$FLo*U=yym!)y))@h*G`HLy2OGdh7Q@ef>z zRpn;$upQUo4%7t3P#u1Rx8aY-pZ&~FKubMAK`T%@bw zTX8<_LB?Y5pc?!Tr{GCc_0Yszd+qTiwd%DP|trwb@V%O z((F&vz>3&k=4O>RoBpkdf+}o6z3?=u!9mo_qo|JdqGogeRc{p4;RmSqv#5c7g+xw<@t*mcn zW~`5F9np9?d$?qmug8r!Ud$bcc=e%hN;<>OdCum}KIetBm-ehv6<+j$>ERnsf)S6q z>4X!HIc_B4gyO+;)Qb%}33q7ZT4{2=7xAcGxSetalkw<{HnX9!y5g!W>49i?_~uIS zr0Qgk%sAzn*3jrQG_^MRN48ZsCAw&7ZOrbk=$ex0NqZsBaf8F*-EOizLcGc$X3X3ot2oX>N5BGJ$3-ZMrt zQ$|x>d(5KPF_16fXrkGAJcgy%i(&L9nN7!4sQ!~!kKL|+aI)D{+7S%mF4T3G(2s9% zlBW7arGSp{gUr%!Au@-p!|}KY19;3CL;h%=-0#ULW)o;nL0z{LGqBCIPhlnP2N=QM zSdB9Wo0aKS4^SCF$8F5SXQ%~zM6KLA#H<+0a3XHRTs(nQcpbIyuc!t5!2vj7s2LwC ziT8KDcNd_YM>2NMq(@K&N?s;Zy;mabJT$E(Tm?v>G9L~*Yzi`4O)N? z^?NGnD6^2$vOLs$0o206Y3#oyXrMzYT8moYCe#4iP=9Pi4Rjdw$9B|2=THM)MvZd^ zwPW4blVJ7%wZo72la8vA^R2};RJ$vaUn5j(xY=T;LA6g~4ZgzJn91!|V>1@xS=3QH z#mV>=nac{9o&2(L9E)?En{gcN<2VU#p>pYcluG>Uv&~BA2q0ay29+ecu>~*SR`haC zjkpUV_!vi_zV!I!;1mpF7+Wxc7g6JXLCu$*)0bn>3M!0kCs8ZAg38`k$S&DiT!y_^ zj@8Vf>keWNui$iihsvQ85@;XhBb#CukO#@`qIR;&wY?-5M;)~^D!Sur)L92n6IUR+ zZ%vqjEvOu6MV+k?uLwZ{-N}}bc z3pS!A+JYpw?LjT99U0rsqZWAI{r(bl{TI|k-%xk{1GVsfsOuB`eb?pUuqYh`R5U>d zwT1JMdS@B z%};5f=*6Q@(r9rC<%^Q5P7PunMLEII#*Zq3dR+CcQ0Q2+1BzLc28woCPZ&>0)Rt3G za*d-DQOYPfQ*AeS7k_P%xbZ{;n?Y$-#l<3=>gp3wySaq2)b%aEQi}4dKUPqwq|_@1 z0#xQwbnX=tg`NT*MQ5g{qA1f9BzydQ5O27zIk=EA-?jB(QYfjFs2qR%9ivxukfO)f zYPRp(8+(zs)zjHAXh&>RO3}dBy3}q@QgE8Tq_n&w)LD?>PgEmZUJ`4}sPlFvWFLuL N&2IL^Mvi&n`41*hq-+2H diff --git a/apps/ocr/locale/es/LC_MESSAGES/django.po b/apps/ocr/locale/es/LC_MESSAGES/django.po index f6ea7bf693..4c81e3a84c 100644 --- a/apps/ocr/locale/es/LC_MESSAGES/django.po +++ b/apps/ocr/locale/es/LC_MESSAGES/django.po @@ -3,13 +3,13 @@ # 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: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:19+0000\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" @@ -18,31 +18,31 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:31 __init__.py:32 +#: __init__.py:32 __init__.py:33 msgid "submit to OCR queue" msgstr "enviar a lista de OCR" -#: __init__.py:33 __init__.py:34 +#: __init__.py:34 __init__.py:35 msgid "re-queue" msgstr "volver a la cola" -#: __init__.py:35 __init__.py:36 __init__.py:49 +#: __init__.py:36 __init__.py:37 __init__.py:50 msgid "delete" msgstr "eliminar" -#: __init__.py:38 +#: __init__.py:39 msgid "stop queue" msgstr "detener cola" -#: __init__.py:39 +#: __init__.py:40 msgid "activate queue" msgstr "activar cola" -#: __init__.py:41 +#: __init__.py:42 msgid "clean up pages content" msgstr "limpiar el contenido" -#: __init__.py:41 +#: __init__.py:42 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -50,31 +50,31 @@ msgstr "" "Ejecuta un filtro de lenguaje para eliminar los errores más comunes de OCR " "del contenido de las paginas del documento." -#: __init__.py:43 +#: __init__.py:44 msgid "queue document list" msgstr "lista de documentos en la cola" -#: __init__.py:44 __init__.py:62 permissions.py:7 +#: __init__.py:45 __init__.py:63 permissions.py:7 msgid "OCR" msgstr "OCR" -#: __init__.py:46 +#: __init__.py:47 msgid "transformations" msgstr "transformaciones" -#: __init__.py:47 +#: __init__.py:48 msgid "add transformation" msgstr "añadir transformación" -#: __init__.py:48 +#: __init__.py:49 msgid "edit" msgstr "editar" -#: __init__.py:69 +#: __init__.py:74 msgid "Default" msgstr "Por defecto" -#: __init__.py:97 +#: __init__.py:102 msgid "Checks the OCR queue for pending documents." msgstr "Comprueba la cola de OCR para documentos pendientes." @@ -186,19 +186,19 @@ msgstr "transformaciones de cola de documentos" #: permissions.py:8 msgid "Submit documents for OCR" -msgstr "" +msgstr "Enviar documentos para OCR" #: permissions.py:9 msgid "Delete documents from OCR queue" -msgstr "" +msgstr "Eliminar documentos de la cola de OCR" #: permissions.py:10 msgid "Can enable/disable the OCR queue" -msgstr "" +msgstr "Puede activar/desactivar la cola de OCR" #: permissions.py:11 msgid "Can execute the OCR clean up on all document pages" -msgstr "" +msgstr "Se puede ejecutar limpieza de OCR en todas las páginas de documentos" #: permissions.py:12 msgid "Can edit an OCR queue properties" diff --git a/apps/ocr/locale/it/LC_MESSAGES/django.mo b/apps/ocr/locale/it/LC_MESSAGES/django.mo index c7381f6c7ebd72ad27460ff6ceb0f5cd37bdfd2a..75ac3ea7efd69f342e47d57e7d84ef94584e4794 100644 GIT binary patch delta 774 zcmXZaPe{{o7{~EXnWg!!T$-9Lu?;HQ-0v4^4VJUiNRlGfp`u`uF)Y|nCU^*b9%7Jq ziB+edlR+RAdiNlB@Maf|kZKlnSnp6C1h?)g67XTKK%+tytC;b9hhya5@QUp>Ntf|4_TwuY!FBAx6V1{EOyYTbij7#tWB8$2 zp27s5Scu{lTEU9b(nah?2Qz4eUZb5`L3-9My10+G&~1^1@i|%}tC+;u|Fo*YX4jb?%S|fk30^80UtOqek9!2|o0qp?`Xbo?mO>`d_ zo)YcS1H9)EFfA=&J+7i1{Oaco9nw+qAo56su^JP24sW6re13nWFonw2VSPljrEtdlSYW@Q)Oj?`( delta 788 zcmXZaPe@cz6vy$O)#Ox`I5YmuOw6=D;B&Mb8?dw(LDH2BWK{4>8Hbpenm-F^@irDr zL{J0Ku0;!1LNc4ETuH480xKwJ=|X7Ht|Fqo2j61&+;iV~=bn4!eLK5!?)k?Z-sc+W zYlAc^X*DbjVI(4r;6*%xW#4t2BL0iR_PkLV#3hX33mnHE=wPf#I*utkh7U1>FR>Qi zH_6jc7N6MY!#`*RPc-wxYZ%2cTA^2Hd7DVjinK@r*n<-|g9&_w*2or)Vt=dDhPQn0 z<4NM>R!Sn@{KRPR3nyvrf8DD9slt^`Z7)|3GK-R6H8142IrR0^!ShC*5qS, 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:31 __init__.py:32 +#: __init__.py:32 __init__.py:33 msgid "submit to OCR queue" msgstr "Sottoponi una coda di OCR" -#: __init__.py:33 __init__.py:34 +#: __init__.py:34 __init__.py:35 msgid "re-queue" msgstr "riaccoda" -#: __init__.py:35 __init__.py:36 __init__.py:49 +#: __init__.py:36 __init__.py:37 __init__.py:50 msgid "delete" msgstr "cancella" -#: __init__.py:38 +#: __init__.py:39 msgid "stop queue" msgstr "stoppa la coda" -#: __init__.py:39 +#: __init__.py:40 msgid "activate queue" msgstr "attiva la coda" -#: __init__.py:41 +#: __init__.py:42 msgid "clean up pages content" msgstr "ripulisci il contenuto delle pagine" -#: __init__.py:41 +#: __init__.py:42 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -50,31 +51,31 @@ msgstr "" "Esegue un filtro per rimuovere i comuni errori di OCR dal contenuto del " "documento pagine." -#: __init__.py:43 +#: __init__.py:44 msgid "queue document list" msgstr "lista dei documenti in coda" -#: __init__.py:44 __init__.py:62 permissions.py:7 +#: __init__.py:45 __init__.py:63 permissions.py:7 msgid "OCR" msgstr "OCR" -#: __init__.py:46 +#: __init__.py:47 msgid "transformations" msgstr "transformazioni" -#: __init__.py:47 +#: __init__.py:48 msgid "add transformation" msgstr "aggiungi trasformazione" -#: __init__.py:48 +#: __init__.py:49 msgid "edit" msgstr "modifica" -#: __init__.py:69 +#: __init__.py:74 msgid "Default" msgstr "Default" -#: __init__.py:97 +#: __init__.py:102 msgid "Checks the OCR queue for pending documents." msgstr "Controlla i documenti nella coda dell'OCR" @@ -381,8 +382,8 @@ msgstr "Errore nella cancellazione della coda di trasformazione; %(error)s" msgid "" "Are you sure you wish to delete queue transformation \"%(transformation)s\"" msgstr "" -"Sei sicuro di voler cancellare la coda di trasformazione " -"\"%(transformation)s\"" +"Sei sicuro di voler cancellare la coda di trasformazione \"%(transformation)s" +"\"" #: views.py:412 msgid "Queue transformation created successfully" @@ -403,8 +404,8 @@ 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." +"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." @@ -414,8 +415,7 @@ msgstr "" #: conf/settings.py:15 msgid "Automatically queue newly created documents for OCR." -msgstr "" -"Automaticamente crea una coda appena si sottomone un documento ad OCR." +msgstr "Automaticamente crea una coda appena si sottomone un documento ad OCR." #: conf/settings.py:17 msgid "File path to unpaper program." @@ -424,5 +424,3 @@ 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/pt/LC_MESSAGES/django.mo b/apps/ocr/locale/pt/LC_MESSAGES/django.mo index f1ddf70ec16c48ce2224a3d5049e0b1494f291ac..7bf81b457b22a2bab52fe247343b29e191ac1642 100644 GIT binary patch delta 774 zcmXZaJxmjE7{~D+T71Fc3zauPd5H-q9<+xBTa=neh_Q`0=mLXjLTOx3pp=axAt4ZB zB!00}rSsEY$(s*AF?x{x@CgGRqk?viUi|L3{ObIhkZB`xPuRf|KKf5RZBN<0ekTSTK+Fy!9^Ph`jKk+E0a24<2A=)5!>ZJ=fi=^}h zt^Q`cCv|i9PU1RN^OSXZKd^vl;uT~$I>0VG+Q0|9k!7d{2QiI3xQte(gbu3Fe_l=pgC&uw#5XUb{<-`L>k4j?&jv|-F`C{9873ANct#%Dh;x<;{M{LC} zXq)_vwpp+Bl0R7rt+OY145u-KGiU|pg7^iVB3?pkY#C4B3RdDO+D6_Z!)p(%!5_hW zHTjL5M&6T99S1AeC9MeDwE^(^L()-GQ6=E=?wn|B?wyq delta 789 zcmXZaKWGzS7{~FSt<`8FwTVWf{fCOtM!o)%+O(KOq|%}wIM_jQYPe=dQ|}T%5CRSb z(Sndggt!&KMX_Qx2fJ8tDuSqk4i45;oa*5B;SP>`p67ip&pq#R_b9)TfBC7U{$-2w zwNtt+>2*>X!|Wa@k3~F-OOZeEBKhIH(ggZ=24CPf{)*O*q@?5IE)L-X%;H7Q*$L{?Sp(fGpE8sa?#3@|IN$g372l4O#`7>lo z@6i7DEnSy}31aMy-~?Kyw<4Q3O}>TUtBce?%MYXWW6`F@YO+ z2>+o?vbQIkZ2ba(oyn~b^ zoxS0H2CcEv$a8Ya6Ij9X;esxsy`!sWH~QFtchNqchiH>%F5hokh-YT2)%l#`c%|xW z?fR)3m9pbk0@p89e5dT*ap#;;5Y&o6qa)E38yM;v9LWuiHii@L8?od}`?Ndf)m*Qb M>ziLLBnRUE0r13QV*mgE diff --git a/apps/ocr/locale/pt/LC_MESSAGES/django.po b/apps/ocr/locale/pt/LC_MESSAGES/django.po index 7fa831ca42..c6418c4f40 100644 --- a/apps/ocr/locale/pt/LC_MESSAGES/django.po +++ b/apps/ocr/locale/pt/LC_MESSAGES/django.po @@ -1,49 +1,50 @@ # 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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:31 __init__.py:32 +#: __init__.py:32 __init__.py:33 msgid "submit to OCR queue" msgstr "submeter à lista de OCR" -#: __init__.py:33 __init__.py:34 +#: __init__.py:34 __init__.py:35 msgid "re-queue" msgstr "re-enfileirar" -#: __init__.py:35 __init__.py:36 __init__.py:49 +#: __init__.py:36 __init__.py:37 __init__.py:50 msgid "delete" msgstr "excluir" -#: __init__.py:38 +#: __init__.py:39 msgid "stop queue" msgstr "parar lista" -#: __init__.py:39 +#: __init__.py:40 msgid "activate queue" msgstr "ativar lista" -#: __init__.py:41 +#: __init__.py:42 msgid "clean up pages content" msgstr "limpar conteúdo das páginas" -#: __init__.py:41 +#: __init__.py:42 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -51,31 +52,31 @@ msgstr "" "Executa um filtro de linguagem para remover erros comuns de OCR do conteúdo " "das páginas do documento." -#: __init__.py:43 +#: __init__.py:44 msgid "queue document list" msgstr "lista de documentos da fila" -#: __init__.py:44 __init__.py:62 permissions.py:7 +#: __init__.py:45 __init__.py:63 permissions.py:7 msgid "OCR" msgstr "OCR" -#: __init__.py:46 +#: __init__.py:47 msgid "transformations" msgstr "transformações" -#: __init__.py:47 +#: __init__.py:48 msgid "add transformation" msgstr "adicionar transformação" -#: __init__.py:48 +#: __init__.py:49 msgid "edit" msgstr "editar" -#: __init__.py:69 +#: __init__.py:74 msgid "Default" msgstr "Padrão" -#: __init__.py:97 +#: __init__.py:102 msgid "Checks the OCR queue for pending documents." msgstr "Verifica a lista de OCR para documentos pendentes." @@ -339,8 +340,7 @@ msgstr "Tem certeza de que deseja limpar todo o conteúdo das páginas?" #: 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." +"Em grandes bases de dados esta operação pode levar algum tempo para executar." #: views.py:285 msgid "Document pages content clean up complete." @@ -384,8 +384,8 @@ msgstr "Erro ao deletar transformação de lista; %(error)s " msgid "" "Are you sure you wish to delete queue transformation \"%(transformation)s\"" msgstr "" -"Tem certeza que deseja deletar a transformação de lista " -"\"%(transformation)s\"" +"Tem certeza que deseja deletar a transformação de lista \"%(transformation)s" +"\"" #: views.py:412 msgid "Queue transformation created successfully" @@ -425,5 +425,3 @@ msgstr "Caminho do arquivo para o programa unpaper." #: 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 ca6858dc7152d7801977c9fb74fa48311fe51c4a..bfb70a625805aac783adbaa5a5a3aaa662bd9439 100644 GIT binary patch delta 775 zcmXZaUr1A77{~FSkzU9!+p=ltT5hE!ht3X7VHqSPL5=)_7uFP7v`i>RG9zekNJ_F> zgYJT)yDpNZ)KwA@-Gw+2>N2R?KuItn`aUf<@OjVsKIeJf_c`y|!6$f zia~teBwwc(tTS;D!}}MvBTI=c$NyjmUHb0D(X9g|) z71rZBw7jcm@mtt~9fvFWHyK#KOKit7(sljD0EXFxC5mGWCUF;bqZLXc*G3t%jpdPM zX&POeN1CBBTHc@d?*J6T6N)jgfKKE-X&61sR{}JT{7xE%twzOuO%}mX#t}|n_N(u^LM$r(Wa?;h-Hc%J4TNDHrvL5Ow zm{`yGQbZ(J554pzB)vrhN%R=fLvIl-guaLQ^f~u`59j><=l_42{*Yey(%{D$q?H}g zTS@;y(j+eIl(HCYmd0@gZ{Sb7hr=yW9zWu3jPH`};0t_&?YpJx_zG`gAS_)%5BK8| z2Ju%|zD^UYvv36mTcuHah8OVNa3-}3pur zm~4}d;UtdW^ER@q(O(uUacFOSBlFnJ_d42%I%Cp7e1mq96}10{+9d}^a26k+Z7{r# zW|+qm&f`h^jlJ00A-%)PK7lQ4WiEs|j%CcCHTaC%u!e_mOJ{v_2^`=%g|_aa)p?DU z{|&d}Dq7t&wESq7bOzHK`m+R<@D&eW4Vk(+=pMj9v_iwU2}iLBC(s&s$g|OXv^$+c zhNhR;hs(%NR70y9p^4=s>Yh-Fz!EaZdy, 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-02 14:17-0400\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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\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:31 __init__.py:32 +#: __init__.py:32 __init__.py:33 msgid "submit to OCR queue" msgstr "отправить на распознавание" -#: __init__.py:33 __init__.py:34 +#: __init__.py:34 __init__.py:35 msgid "re-queue" msgstr "переотправить" -#: __init__.py:35 __init__.py:36 __init__.py:49 +#: __init__.py:36 __init__.py:37 __init__.py:50 msgid "delete" msgstr "удалить" -#: __init__.py:38 +#: __init__.py:39 msgid "stop queue" msgstr "остановка очереди" -#: __init__.py:39 +#: __init__.py:40 msgid "activate queue" msgstr "активировать очередь" -#: __init__.py:41 +#: __init__.py:42 msgid "clean up pages content" msgstr "очистка содержимого страниц" -#: __init__.py:41 +#: __init__.py:42 msgid "" "Runs a language filter to remove common OCR mistakes from document pages " "content." @@ -50,31 +52,31 @@ msgstr "" "Применить языковый фильтр для удаления общих ошибок распознавания " "содержимого страниц документа." -#: __init__.py:43 +#: __init__.py:44 msgid "queue document list" msgstr "список очереди документов" -#: __init__.py:44 __init__.py:62 permissions.py:7 +#: __init__.py:45 __init__.py:63 permissions.py:7 msgid "OCR" msgstr "Распознавание текста" -#: __init__.py:46 +#: __init__.py:47 msgid "transformations" msgstr "преобразования" -#: __init__.py:47 +#: __init__.py:48 msgid "add transformation" msgstr "добавить преобразование" -#: __init__.py:48 +#: __init__.py:49 msgid "edit" msgstr "редактировать" -#: __init__.py:69 +#: __init__.py:74 msgid "Default" msgstr "Умолчание" -#: __init__.py:97 +#: __init__.py:102 msgid "Checks the OCR queue for pending documents." msgstr "Проверить очередь документов ожидающих распознавания ." @@ -384,8 +386,7 @@ msgstr "Ошибка при удалении преобразования оче msgid "" "Are you sure you wish to delete queue transformation \"%(transformation)s\"" msgstr "" -"Вы действительно хотите удалить преобразование очереди " -"\"%(transformation)s\"" +"Вы действительно хотите удалить преобразование очереди \"%(transformation)s\"" #: views.py:412 msgid "Queue transformation created successfully" @@ -426,5 +427,3 @@ msgstr "Путь к программе unpaper." #: parsers/__init__.py:37 msgid "Text extracted from PDF" msgstr "Текст, извлеченный из PDF" - - diff --git a/apps/permissions/locale/en/LC_MESSAGES/django.po b/apps/permissions/locale/en/LC_MESSAGES/django.po index acd1b43e64..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: 2012-02-02 14:17-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" @@ -61,11 +61,11 @@ msgstr "" msgid "name" msgstr "" -#: models.py:131 models.py:187 views.py:152 views.py:216 +#: models.py:131 models.py:187 views.py:152 views.py:215 msgid "permission" msgstr "" -#: models.py:132 views.py:57 views.py:154 views.py:218 +#: models.py:132 views.py:57 views.py:154 views.py:217 msgid "permissions" msgstr "" @@ -82,7 +82,7 @@ msgid "label" msgstr "" #: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117 -#: views.py:336 +#: views.py:334 msgid "role" msgstr "" @@ -126,11 +126,11 @@ msgstr "" msgid "has permission" msgstr "" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 msgid " and " msgstr "" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 #, python-format msgid "%(permissions)s to %(requester)s" msgstr "" @@ -145,46 +145,46 @@ msgstr "" msgid "%(requester)s, already had the permission \"%(permission)s\" granted." msgstr "" -#: views.py:174 +#: views.py:173 #, python-format msgid "" "Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" msgstr "" -#: views.py:223 +#: views.py:222 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "" -#: views.py:226 +#: views.py:225 #, python-format msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." msgstr "" -#: views.py:238 +#: views.py:236 #, python-format msgid "" "Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" msgstr "" -#: views.py:273 views.py:297 +#: views.py:271 views.py:295 msgid "Users" msgstr "" -#: views.py:276 views.py:300 +#: views.py:274 views.py:298 msgid "Groups" msgstr "" -#: views.py:279 views.py:303 +#: views.py:277 views.py:301 msgid "Special" msgstr "" -#: views.py:332 +#: views.py:330 #, python-format msgid "non members of role: %s" msgstr "" -#: views.py:333 +#: 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 a8cf185da1ff49bcdd25deebeb0cf5dfef8d8b76..21e0374d2155624fe4ee032097fb498325189468 100644 GIT binary patch delta 403 zcmXZYze@sf7{~EPlkU_DHT(gmnfMQwTFXI2bG3yI4(1?kEz(rsAK-X_OVD3nNkYp- z4nb4PjZO}N&=f6=()-JOr`J87=lMS0FZXFb+LPPRzzd1A4H1xhRAd)-@E8yA2=B0o zZ+MF7n8-O^VgjFV8{aX9KC)82F@?Xli5u~tAHzCzIW7a)=c7Sj;tQl7FF^Tk3j^{4B{#=V346dPc#l)=Jd_r?%%V4BtBIT=lLyy{=R0_T6W*HO)mU Fk$*U@Fh>9Y delta 466 zcmXZYze@sP9LMp;kTieL55mHzTwDS>Pldpwplk?>8iJrjp6bvW^y2OuqQbF1Kxk+Q zqCX&V351rQJ*dH<#i*gBp~bQHg9it%`+lD9^L-wkoA^uo{@mB>`GhD3gaENNBE&ov zaTSko1@CYlKe2?%AtAQ$5=ZeJC-4iWu#b!sV__l2aT, 2011, 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-02 14:17-0400\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-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:17 models.py:209 views.py:40 @@ -62,11 +63,11 @@ msgstr "espacio de nombres" msgid "name" msgstr "nombre" -#: models.py:131 models.py:187 views.py:152 views.py:216 +#: models.py:131 models.py:187 views.py:152 views.py:215 msgid "permission" msgstr "permiso" -#: models.py:132 views.py:57 views.py:154 views.py:218 +#: models.py:132 views.py:57 views.py:154 views.py:217 msgid "permissions" msgstr "permisos" @@ -83,7 +84,7 @@ msgid "label" msgstr "etiqueta" #: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117 -#: views.py:336 +#: views.py:334 msgid "role" msgstr "función" @@ -127,11 +128,11 @@ msgstr "Revocar permisos" msgid "has permission" msgstr "tiene permiso" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 msgid " and " msgstr "y" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 #, python-format msgid "%(permissions)s to %(requester)s" msgstr "%(permissions)s a %(requester)s" @@ -146,48 +147,48 @@ msgstr "Permiso \"%(permission)s\" otorgado a: %(requester)s." msgid "%(requester)s, already had the permission \"%(permission)s\" granted." msgstr "%(requester)s, ya tenía el permiso \"%(permission)s\" concedido." -#: views.py:174 +#: 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:223 +#: views.py:222 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "Permiso \"%(permission)s\" revocado de: %(requester)s." -#: views.py:226 +#: 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:238 +#: 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:273 views.py:297 +#: views.py:271 views.py:295 msgid "Users" msgstr "Usuarios" -#: views.py:276 views.py:300 +#: views.py:274 views.py:298 msgid "Groups" msgstr "Grupos" -#: views.py:279 views.py:303 +#: views.py:277 views.py:301 msgid "Special" msgstr "Especial" -#: views.py:332 +#: views.py:330 #, python-format msgid "non members of role: %s" msgstr "no miembros de la función: %s" -#: views.py:333 +#: views.py:331 #, python-format msgid "members of role: %s" msgstr "miembros de la función: %s" @@ -207,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 index 1996647392b9b98c278e9c4f4a887e123278cdd7..1662db40f5abafd11c4dff433f290e9061330bce 100644 GIT binary patch delta 403 zcmXZYu}T9$5P;!1In9|IB7$O0#DHl}?iLjcSSi>DQAid?WClNQ8Go#E z!y-H62Ux`ytY9%K!jV(LD4ts{Fh}0SDSW^Qe8YMC!bJ>n(iC>cCf!3=#YxoY;~AR4 zEi`?X)@$U*Enx&7kvB;n&75~M3qR4tZ(IMxY4Sfb^8$ZOWSq+^+l)(S3S~5dw$S{{ z9-4HF)t TQ9IT(%JsCp>uvX*JjeY9K!G(4 delta 417 zcmXZYy-UMD7{~Fa5^ZdYi1-#?u;AckS}6(vhYljB;G#=$FluQtw2>weoq~%vxMfwS ziy%S~x(ebTx;VH94*mxYI;fN2_b_nW=bn3x-yPR99*paqMEH^r8A*zCipZxfGJ!uh zk3-%6uHy!EgeCmIHC#@KFr>-Ui&wEXn5KThQGCTg{K5ieXwG6WEunCi?6c8@hd7MK zn89;Y!7WthZet&jA0!S|E_)6aiL9BeSg<7&5Gk!gRSXpw`Mk6&u%zw!>ri{cHMM5 nFDQG_YI01^&1CZhD?b-`$@^$QFQr!OdL^(cWh>i0)iv!8N3cCH diff --git a/apps/permissions/locale/it/LC_MESSAGES/django.po b/apps/permissions/locale/it/LC_MESSAGES/django.po index 7c37d3efb9..c9c70931c1 100644 --- a/apps/permissions/locale/it/LC_MESSAGES/django.po +++ b/apps/permissions/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:17 models.py:209 views.py:40 @@ -62,11 +63,11 @@ msgstr "namespace" msgid "name" msgstr "nome" -#: models.py:131 models.py:187 views.py:152 views.py:216 +#: 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:218 +#: models.py:132 views.py:57 views.py:154 views.py:217 msgid "permissions" msgstr "permessi" @@ -83,7 +84,7 @@ msgid "label" msgstr "etichetta" #: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117 -#: views.py:336 +#: views.py:334 msgid "role" msgstr "ruolo" @@ -127,11 +128,11 @@ msgstr "Revoca le autorizzazioni" msgid "has permission" msgstr "ha il permesso" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 msgid " and " msgstr " and " -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 #, python-format msgid "%(permissions)s to %(requester)s" msgstr "%(permissions)s a %(requester)s" @@ -146,7 +147,7 @@ msgstr "Permesso \"%(permission)s\" concesso a: %(requester)s." msgid "%(requester)s, already had the permission \"%(permission)s\" granted." msgstr "%(requester)s, ha già il permesso \"%(permission)s\" concesso." -#: views.py:174 +#: views.py:173 #, python-format msgid "" "Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" @@ -154,17 +155,17 @@ msgstr "" "Sei sicuro che tu voglia concedere questo permesso %(permissions_label)s " "%(title_suffix)s?" -#: views.py:223 +#: views.py:222 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "Permesso \"%(permission)s\" revocato per: %(requester)s." -#: views.py:226 +#: 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:238 +#: views.py:236 #, python-format msgid "" "Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" @@ -172,24 +173,24 @@ msgstr "" "Sei sicuro di voler revocare questo permesso %(permissions_label)s " "%(title_suffix)s?" -#: views.py:273 views.py:297 +#: views.py:271 views.py:295 msgid "Users" msgstr "" -#: views.py:276 views.py:300 +#: views.py:274 views.py:298 msgid "Groups" msgstr "" -#: views.py:279 views.py:303 +#: views.py:277 views.py:301 msgid "Special" msgstr "" -#: views.py:332 +#: views.py:330 #, python-format msgid "non members of role: %s" msgstr "nessun menbro per il ruolo:%s" -#: views.py:333 +#: views.py:331 #, python-format msgid "members of role: %s" msgstr "membri per il ruolo:%s" @@ -209,5 +210,3 @@ msgid "" msgstr "" "Un elenco di ruoli esistenti che vengono automaticamente assegnati agli " "utenti appena creati" - - diff --git a/apps/permissions/locale/pt/LC_MESSAGES/django.mo b/apps/permissions/locale/pt/LC_MESSAGES/django.mo index 039a7cdf27cd637eb4826b946afaf08c6a9f1205..04280bb198791b1c37f995d6b791d06c3413dcff 100644 GIT binary patch delta 307 zcmXZXF;Bu!6o%o`rj>#fi-H(Zk}hlxmcY`uxRbcJ5T-^+H{(zimNL0GHc>~NT?oX5 zg^jS4AHYQX4K5^v_Y#-;l~D%@qfR{Npc8U6siO_$S!h^dF-N#4_LqvR`3-s z@e9=gGgJ#M@C-9l4{uP-{X;dcNE81(^a8!pfzL~x0&b-z4n4Tm7 delta 369 zcmXZXy-EW?5Ww-tnHY1Ycz%m01UrlKazPQUO*#V+w9;w~A-N*Ca36(=#9GTVf)AjL zAg0&SynuyZ;{(`g>wkkV%#WQNW@m5hSNmx?)Bnhb)UzT=M7AbHX7L8+@D6Q!#3_8i zMSR0G{6q_XF^?0ZWwdYxH*o<=NJy1LtJMC_hk5CbFHR_|aM3_^kqa!~6|Unons|>( z_>8MKLcPEj>IJ`X9)D0jT%f4uZlIpGi~M)o3-k_6(=V1wUfC(>D0(}-w>Nmmjs};xW2>gR OtyHyW=?&j=72^*#^f-Y4 diff --git a/apps/permissions/locale/pt/LC_MESSAGES/django.po b/apps/permissions/locale/pt/LC_MESSAGES/django.po index 902ac36a32..f3e0abc0ae 100644 --- a/apps/permissions/locale/pt/LC_MESSAGES/django.po +++ b/apps/permissions/locale/pt/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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:17 models.py:209 views.py:40 @@ -62,11 +63,11 @@ msgstr "namespace" msgid "name" msgstr "nome" -#: models.py:131 models.py:187 views.py:152 views.py:216 +#: models.py:131 models.py:187 views.py:152 views.py:215 msgid "permission" msgstr "permissão" -#: models.py:132 views.py:57 views.py:154 views.py:218 +#: models.py:132 views.py:57 views.py:154 views.py:217 msgid "permissions" msgstr "permissões" @@ -83,7 +84,7 @@ msgid "label" msgstr "rótulo" #: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117 -#: views.py:336 +#: views.py:334 msgid "role" msgstr "função" @@ -127,11 +128,11 @@ msgstr "Revogar as permissões" msgid "has permission" msgstr "" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 msgid " and " msgstr "" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 #, python-format msgid "%(permissions)s to %(requester)s" msgstr "" @@ -146,46 +147,46 @@ msgstr "" msgid "%(requester)s, already had the permission \"%(permission)s\" granted." msgstr "" -#: views.py:174 +#: views.py:173 #, python-format msgid "" "Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" msgstr "" -#: views.py:223 +#: views.py:222 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "" -#: views.py:226 +#: views.py:225 #, python-format msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." msgstr "" -#: views.py:238 +#: views.py:236 #, python-format msgid "" "Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" msgstr "" -#: views.py:273 views.py:297 +#: views.py:271 views.py:295 msgid "Users" msgstr "" -#: views.py:276 views.py:300 +#: views.py:274 views.py:298 msgid "Groups" msgstr "" -#: views.py:279 views.py:303 +#: views.py:277 views.py:301 msgid "Special" msgstr "" -#: views.py:332 +#: views.py:330 #, python-format msgid "non members of role: %s" msgstr "não membros da função: %s" -#: views.py:333 +#: views.py:331 #, python-format msgid "members of role: %s" msgstr "membros da função: %s" @@ -205,5 +206,3 @@ msgid "" msgstr "" "A lista de funções existentes que são automaticamente designados para " "usuários recém-criados" - - diff --git a/apps/permissions/locale/ru/LC_MESSAGES/django.mo b/apps/permissions/locale/ru/LC_MESSAGES/django.mo index 7ce243e6ceef6bf749d68119dc7a7e7e0758a1db..9ab687cace3e35e682135827b4e63570b1b336b8 100644 GIT binary patch delta 403 zcmXZWu}Z^G6vpw>q9)d~h*VOmg(?+Xt|UPnLU2(jNVN`53PMUt=u)A!pi^;nEDpK~ zqLY?7_yUR#;OwAJA&B_DnCW-U{os7}u5ey>tS5Tk36Z=Zk`$5bxJU_Y3@|_+&+q}C zu!8lJ$Tkje7Jp)M6CyM0E11JwbTPtZyuvMf!*$G9(vvL1jwLdQHJry2)Q2x|0SB1D zcg*7#>VjXKMmznVE1Y5vVyigDUPFDii8fxK?!8HuMHU&Jd04`aI523_ADTlGRlKjE zE+}IG590iEc%Qr-DW&$R`)Z@z2s_Q=mf8$E4Zr9)uBRMNxn9v-^*yJ5ZM;~OuoZQ~ Qh`8PDADM^4SMzi94=k-R*Z=?k delta 419 zcmXZWJxfAi7{>8C$vl}xL{V9Sy+}=-j3PLN4Ix1YElx$l=_E%7HO@=WB#sh9aJGhO zikgaC8(LcW1VTeYAD|D=(*MCT{qF0z;J%-B`Z4`-I?&2QL{c#kkgZ{nB`n}JT4>-s zKI0db@G>s4k3F2l#gV={I72?dY4kCVSD3?hEaEQ~a3ditnPBh|B4gOWdAvcj_zf4Z zhokt1DU2uk2eLRxE}-hmIF456IS!FKsP0?XbV=K1Ch|m#dz4X6U+I^Q!(y&T7_mr|Ftbt?B4>^TKTCHP`hkZg3Er j(^l6q`E?_|8Mv{Jpr{=tN@m0MO}k=b9KU<3{Y3u(?29|w diff --git a/apps/permissions/locale/ru/LC_MESSAGES/django.po b/apps/permissions/locale/ru/LC_MESSAGES/django.po index 4a10f25c8a..ecf7a2a65d 100644 --- a/apps/permissions/locale/ru/LC_MESSAGES/django.po +++ b/apps/permissions/locale/ru/LC_MESSAGES/django.po @@ -1,22 +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: # 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: 2012-02-02 14:17-0400\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-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:17 models.py:209 views.py:40 msgid "roles" @@ -62,11 +64,11 @@ msgstr "пространство имен" msgid "name" msgstr "имя" -#: models.py:131 models.py:187 views.py:152 views.py:216 +#: models.py:131 models.py:187 views.py:152 views.py:215 msgid "permission" msgstr "разрешение" -#: models.py:132 views.py:57 views.py:154 views.py:218 +#: models.py:132 views.py:57 views.py:154 views.py:217 msgid "permissions" msgstr "разрешения" @@ -83,7 +85,7 @@ msgid "label" msgstr "надпись" #: models.py:208 models.py:239 views.py:76 views.py:93 views.py:117 -#: views.py:336 +#: views.py:334 msgid "role" msgstr "роль" @@ -127,11 +129,11 @@ msgstr "Отмена разрешений" msgid "has permission" msgstr "имеет право" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 msgid " and " msgstr "и" -#: views.py:149 views.py:213 +#: views.py:149 views.py:212 #, python-format msgid "%(permissions)s to %(requester)s" msgstr "%(permissions)s для %(requester)s" @@ -146,46 +148,46 @@ msgstr "Право \"%(permission)s\" предоставлено %(requester)s." msgid "%(requester)s, already had the permission \"%(permission)s\" granted." msgstr "%(requester)s уже имеет право \"%(permission)s\"." -#: views.py:174 +#: 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:223 +#: views.py:222 #, python-format msgid "Permission \"%(permission)s\" revoked from: %(requester)s." msgstr "Право \"%(permission)s\" отозвано у %(requester)s." -#: views.py:226 +#: views.py:225 #, python-format msgid "%(requester)s, doesn't have the permission \"%(permission)s\" granted." msgstr "%(requester)s не имеет права \"%(permission)s\"." -#: views.py:238 +#: 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:273 views.py:297 +#: views.py:271 views.py:295 msgid "Users" msgstr "" -#: views.py:276 views.py:300 +#: views.py:274 views.py:298 msgid "Groups" msgstr "" -#: views.py:279 views.py:303 +#: views.py:277 views.py:301 msgid "Special" msgstr "" -#: views.py:332 +#: views.py:330 #, python-format msgid "non members of role: %s" msgstr "не входит в %s" -#: views.py:333 +#: views.py:331 #, python-format msgid "members of role: %s" msgstr "входит в %s" @@ -205,5 +207,3 @@ msgid "" msgstr "" "Список существующих ролей, которые автоматически назначаются вновь " "создаваемым пользователям" - - diff --git a/apps/project_setup/locale/en/LC_MESSAGES/django.po b/apps/project_setup/locale/en/LC_MESSAGES/django.po index 567bfb3830..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: 2012-02-02 14:17-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" diff --git a/apps/project_setup/locale/es/LC_MESSAGES/django.mo b/apps/project_setup/locale/es/LC_MESSAGES/django.mo index 054334e2686d644f5b6a7d33ed83ecf5b5e7226b..8094ae0b6164d2c8650a26c6da34490629476a35 100644 GIT binary patch delta 19 acmcb`a*Jic5e`Em1w&ISBZG}+`WOL4-3F=v delta 19 acmcb`a*Jic5e@?*1w#`nL-UPi`WOL4<_4|+ diff --git a/apps/project_setup/locale/es/LC_MESSAGES/django.po b/apps/project_setup/locale/es/LC_MESSAGES/django.po index c02355f76d..82e75e203a 100644 --- a/apps/project_setup/locale/es/LC_MESSAGES/django.po +++ b/apps/project_setup/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-04 01:03+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/project_setup/locale/it/LC_MESSAGES/django.mo b/apps/project_setup/locale/it/LC_MESSAGES/django.mo index 837d26e8e38056e14cd40a7f5e3c9d5874052d50..8147693df5e4ff91a7f402a265ed39a34a486ae8 100644 GIT binary patch delta 19 acmX@aa)@QZ5e`Em1w&ISBZG}+$`}DcO$K5B delta 19 acmX@aa)@QZ5e@?*1w#`nL-UPi$`}DcRt9DO diff --git a/apps/project_setup/locale/it/LC_MESSAGES/django.po b/apps/project_setup/locale/it/LC_MESSAGES/django.po index 7d10e457d4..647c2314ad 100644 --- a/apps/project_setup/locale/it/LC_MESSAGES/django.po +++ b/apps/project_setup/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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/" diff --git a/apps/project_setup/locale/pt/LC_MESSAGES/django.mo b/apps/project_setup/locale/pt/LC_MESSAGES/django.mo index c35bd7a24031251ca0cebda3389834d3bcc8bef2..0686fd6a3c0ca2dab28dcc1b614cb165eafa17ed 100644 GIT binary patch delta 19 acmdnPvWI2D5e`Em1w&ISBZG}+3K#)FX$DXL delta 19 acmdnPvWI2D5e@?*1w#`nL-UPi3K#)Fat2fY diff --git a/apps/project_setup/locale/pt/LC_MESSAGES/django.po b/apps/project_setup/locale/pt/LC_MESSAGES/django.po index e675f151ed..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: 2012-02-02 14:17-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/" diff --git a/apps/project_setup/locale/ru/LC_MESSAGES/django.mo b/apps/project_setup/locale/ru/LC_MESSAGES/django.mo index a413851f5ae3d11f8443ceb17135858909f3d687..1be87c998b01441fb4fd46849e8ce4876d318289 100644 GIT binary patch delta 19 bcmey#@{?u45e`Em1w&ISBZG}+)-nPBN_Phb delta 19 bcmey#@{?u45e@?*1w#`nL-UPi)-nPBN`MCo diff --git a/apps/project_setup/locale/ru/LC_MESSAGES/django.po b/apps/project_setup/locale/ru/LC_MESSAGES/django.po index 945a27b089..f0c539bbd6 100644 --- a/apps/project_setup/locale/ru/LC_MESSAGES/django.po +++ b/apps/project_setup/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-19 20:30+0000\n" "Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/project_tools/locale/en/LC_MESSAGES/django.po b/apps/project_tools/locale/en/LC_MESSAGES/django.po index dbf6bf4871..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: 2012-02-02 14:17-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" diff --git a/apps/project_tools/locale/es/LC_MESSAGES/django.mo b/apps/project_tools/locale/es/LC_MESSAGES/django.mo index 73e308f8dc49e7870148969a9e772c657ce5ef3d..7387ce96d92df027c07ec256a6f2bb77e9600d44 100644 GIT binary patch delta 19 acmZ3$vVdj63Jyaf1w&ISBZG|_3K#)9odw_k delta 19 acmZ3$vVdj63JwD!1w#`nL-UOr3K#)9rUm2x diff --git a/apps/project_tools/locale/es/LC_MESSAGES/django.po b/apps/project_tools/locale/es/LC_MESSAGES/django.po index ba97e95eda..714f2f9f66 100644 --- a/apps/project_tools/locale/es/LC_MESSAGES/django.po +++ b/apps/project_tools/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-09-30 05:22+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.mo b/apps/project_tools/locale/it/LC_MESSAGES/django.mo index e74238fc0bfb5162dbcc3ee6fb01e3c57ad5b584..de891e390b5e4d2d884f55524f79053492e0caa4 100644 GIT binary patch delta 19 acmeBT>0+6%g2T{A!O+yo$YA4!C`JG{Sp}W| delta 19 acmeBT>0+6%g2TW_!O+CY(0t>DC`JG{Vg;fA diff --git a/apps/project_tools/locale/it/LC_MESSAGES/django.po b/apps/project_tools/locale/it/LC_MESSAGES/django.po index bb22a3a0c3..ca3f7d9be2 100644 --- a/apps/project_tools/locale/it/LC_MESSAGES/django.po +++ b/apps/project_tools/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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/" diff --git a/apps/project_tools/locale/pt/LC_MESSAGES/django.mo b/apps/project_tools/locale/pt/LC_MESSAGES/django.mo index 4fd22d2f96333a9b003430b93428eb0d2278db25..b11a377f8dafc1dc4498c63a5080efd262db3137 100644 GIT binary patch delta 19 acmZo?X=jDa7F+(@CBIw diff --git a/apps/project_tools/locale/pt/LC_MESSAGES/django.po b/apps/project_tools/locale/pt/LC_MESSAGES/django.po index 937385df3b..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: 2012-02-02 14:17-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/" diff --git a/apps/project_tools/locale/ru/LC_MESSAGES/django.mo b/apps/project_tools/locale/ru/LC_MESSAGES/django.mo index 316e8bbbf63d986d29b3d1d09d78c437cae7cf17..cedcf43ffc5ba467cf451deb25e6cf91300bd0bf 100644 GIT binary patch delta 19 bcmcb>a)D*S3Jyaf1w&ISBZG|_7BB(;LcIoX delta 19 bcmcb>a)D*S3JwD!1w#`nL-UOr7BB(;LdFJk diff --git a/apps/project_tools/locale/ru/LC_MESSAGES/django.po b/apps/project_tools/locale/ru/LC_MESSAGES/django.po index 9d2e159cc5..6cc3064eb2 100644 --- a/apps/project_tools/locale/ru/LC_MESSAGES/django.po +++ b/apps/project_tools/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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/" diff --git a/apps/smart_settings/locale/en/LC_MESSAGES/django.po b/apps/smart_settings/locale/en/LC_MESSAGES/django.po index d3d311c670..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: 2012-02-02 14:17-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" diff --git a/apps/smart_settings/locale/es/LC_MESSAGES/django.mo b/apps/smart_settings/locale/es/LC_MESSAGES/django.mo index 1b20e4e7df6b61e584fe6fe74ca10887217f21f5..23f3eb628bf116477ba67526df43cb32bbfb602f 100644 GIT binary patch delta 19 acmeBV?PQ(sjl+Zbkq-@CI)H diff --git a/apps/smart_settings/locale/es/LC_MESSAGES/django.po b/apps/smart_settings/locale/es/LC_MESSAGES/django.po index 4b433c3294..70fb0f67bb 100644 --- a/apps/smart_settings/locale/es/LC_MESSAGES/django.po +++ b/apps/smart_settings/locale/es/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-09-30 05:09+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/smart_settings/locale/it/LC_MESSAGES/django.mo b/apps/smart_settings/locale/it/LC_MESSAGES/django.mo index 30ad835a45cb53c72fb3f861509443b27b98f45c..d36c2eacdc9dbe77ed011d6a453b565432be19d0 100644 GIT binary patch delta 19 acmey!@{wi2Hx5H11w&ISBZH0qiWvb+H3uO8 delta 19 acmey!@{wi2Hx2_M1w#`nL-URQiWvb+J_jWL diff --git a/apps/smart_settings/locale/it/LC_MESSAGES/django.po b/apps/smart_settings/locale/it/LC_MESSAGES/django.po index 00cd08980d..ddd908c065 100644 --- a/apps/smart_settings/locale/it/LC_MESSAGES/django.po +++ b/apps/smart_settings/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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/" diff --git a/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo b/apps/smart_settings/locale/pt/LC_MESSAGES/django.mo index eb2bc89543e7ab69adb9f7cfbda7e3925fdc02d8..bd58bb60a2809236195d56fbbd650a98303c1ed2 100644 GIT binary patch delta 19 acmaFE@`h!?Hx5H11w&ISBZH0q@)!Y2cLx#x delta 19 acmaFE@`h!?Hx2_M1w#`nL-URQ@)!Y2fCm-; diff --git a/apps/smart_settings/locale/pt/LC_MESSAGES/django.po b/apps/smart_settings/locale/pt/LC_MESSAGES/django.po index 56eff8ce7f..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: 2012-02-02 14:17-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/" diff --git a/apps/smart_settings/locale/ru/LC_MESSAGES/django.mo b/apps/smart_settings/locale/ru/LC_MESSAGES/django.mo index 9f2931e45f113d4767448675441675ce8ab4999d..e4856bc7ca3002dad38354cf5e140fb47a098bee 100644 GIT binary patch delta 19 bcmX@bdWv\n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/sources/locale/en/LC_MESSAGES/django.po b/apps/sources/locale/en/LC_MESSAGES/django.po index 90020f8f73..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: 2012-02-02 14:17-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" @@ -29,15 +29,15 @@ msgstr "" msgid "sources" msgstr "" -#: __init__.py:23 literals.py:53 models.py:201 +#: __init__.py:23 literals.py:53 models.py:203 msgid "web forms" msgstr "" -#: __init__.py:24 models.py:172 +#: __init__.py:24 models.py:174 msgid "staging folders" msgstr "" -#: __init__.py:25 models.py:236 +#: __init__.py:25 models.py:238 msgid "watch folders" msgstr "" @@ -137,7 +137,7 @@ msgstr "" msgid "Empty printer" msgstr "" -#: literals.py:47 models.py:200 +#: literals.py:47 models.py:202 msgid "web form" msgstr "" @@ -157,117 +157,117 @@ msgstr "" msgid "server watch folders" msgstr "" -#: models.py:36 +#: models.py:37 msgid "title" msgstr "" -#: models.py:37 +#: models.py:38 msgid "enabled" msgstr "" -#: models.py:38 +#: models.py:39 msgid "whitelist" msgstr "" -#: models.py:39 +#: models.py:40 msgid "blacklist" msgstr "" -#: models.py:140 +#: models.py:142 msgid "icon" msgstr "" -#: models.py:140 +#: models.py:142 msgid "An icon to visually distinguish this source." msgstr "" -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "folder path" msgstr "" -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "Server side filesystem path." msgstr "" -#: models.py:157 +#: models.py:159 msgid "preview width" msgstr "" -#: models.py:157 +#: models.py:159 msgid "Width value to be passed to the converter backend." msgstr "" -#: models.py:158 +#: models.py:160 msgid "preview height" msgstr "" -#: models.py:158 +#: models.py:160 msgid "Height value to be passed to the converter backend." msgstr "" -#: models.py:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "uncompress" msgstr "" -#: models.py:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "Whether to expand or not compressed archives." msgstr "" -#: models.py:160 models.py:210 +#: models.py:162 models.py:212 msgid "delete after upload" msgstr "" -#: models.py:160 models.py:210 +#: models.py:162 models.py:212 msgid "Delete the file after is has been successfully uploaded." msgstr "" -#: models.py:171 +#: models.py:173 msgid "staging folder" msgstr "" -#: models.py:211 +#: models.py:213 msgid "interval" msgstr "" -#: models.py:211 +#: models.py:213 msgid "" "Inverval in seconds where the watch folder path is checked for new documents." msgstr "" -#: models.py:235 +#: models.py:237 msgid "watch folder" msgstr "" -#: models.py:240 +#: models.py:242 msgid "Enter a valid value." msgstr "" -#: models.py:268 views.py:581 +#: models.py:270 views.py:589 msgid "order" msgstr "" -#: models.py:269 views.py:582 views.py:619 views.py:649 +#: models.py:271 views.py:590 views.py:627 views.py:657 msgid "transformation" msgstr "" -#: models.py:270 views.py:583 +#: models.py:272 views.py:591 msgid "arguments" msgstr "" -#: models.py:270 +#: models.py:272 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "" -#: models.py:281 +#: models.py:283 msgid "document source transformation" msgstr "" -#: models.py:282 +#: models.py:284 msgid "document source transformations" msgstr "" -#: models.py:288 models.py:289 +#: models.py:290 models.py:291 msgid "out of process" msgstr "" @@ -400,115 +400,123 @@ 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:358 views.py:377 +#: views.py:366 views.py:385 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "" -#: views.py:400 +#: views.py:408 msgid "Staging file delete successfully." msgstr "" -#: views.py:402 +#: views.py:410 #, python-format msgid "Staging file delete error; %s." msgstr "" -#: views.py:462 +#: views.py:470 msgid "Source edited successfully" msgstr "" -#: views.py:465 +#: views.py:473 #, python-format msgid "Error editing source; %s" msgstr "" -#: views.py:470 +#: views.py:478 #, python-format msgid "edit source: %s" msgstr "" -#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 -#: views.py:691 +#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656 +#: views.py:699 msgid "source" msgstr "" -#: views.py:504 +#: views.py:512 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "" -#: views.py:506 +#: views.py:514 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "" -#: views.py:513 +#: views.py:521 #, python-format msgid "Are you sure you wish to delete the source: %s?" msgstr "" -#: views.py:545 +#: views.py:553 msgid "Source created successfully" msgstr "" -#: views.py:548 +#: views.py:556 #, python-format msgid "Error creating source; %s" msgstr "" -#: views.py:553 +#: views.py:561 #, python-format msgid "Create new source of type: %s" msgstr "" -#: views.py:575 +#: views.py:583 #, python-format msgid "transformations for: %s" msgstr "" -#: views.py:605 +#: views.py:613 msgid "Source transformation edited successfully" msgstr "" -#: views.py:608 +#: views.py:616 #, python-format msgid "Error editing source transformation; %s" msgstr "" -#: views.py:613 +#: views.py:621 #, python-format msgid "Edit transformation: %s" msgstr "" -#: views.py:636 +#: views.py:644 msgid "Source transformation deleted successfully." msgstr "" -#: views.py:638 +#: views.py:646 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "" -#: views.py:651 +#: views.py:659 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" msgstr "" -#: views.py:681 +#: views.py:689 msgid "Source transformation created successfully" msgstr "" -#: views.py:684 +#: views.py:692 #, python-format msgid "Error creating source transformation; %s" msgstr "" -#: views.py:693 +#: 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 4873b27b15abd3a76591fabed0a59917b03defcd..7cdd8eb99819b451dbfd3639fc69e84c35a964ad 100644 GIT binary patch delta 2665 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 SgWqMR&dnakO*PM(TktQoCEh~- diff --git a/apps/sources/locale/es/LC_MESSAGES/django.po b/apps/sources/locale/es/LC_MESSAGES/django.po index 276debfca4..9074aeb8ad 100644 --- a/apps/sources/locale/es/LC_MESSAGES/django.po +++ b/apps/sources/locale/es/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-12 00:20+0000\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" @@ -30,15 +30,15 @@ msgstr "borrar" msgid "sources" msgstr "fuentes" -#: __init__.py:23 literals.py:53 models.py:201 +#: __init__.py:23 literals.py:53 models.py:203 msgid "web forms" msgstr "formularios web" -#: __init__.py:24 models.py:172 +#: __init__.py:24 models.py:174 msgid "staging folders" msgstr "carpetas de archivos provisionales" -#: __init__.py:25 models.py:236 +#: __init__.py:25 models.py:238 msgid "watch folders" msgstr "carpetas bajo observación" @@ -139,7 +139,7 @@ msgstr "Impresora" msgid "Empty printer" msgstr "Impresora vacia" -#: literals.py:47 models.py:200 +#: literals.py:47 models.py:202 msgid "web form" msgstr "formulario web" @@ -159,79 +159,79 @@ msgstr "carpetas de archivos provisionales de servidor" msgid "server watch folders" msgstr "carpetas observadas de servidor" -#: models.py:36 +#: models.py:37 msgid "title" msgstr "título" -#: models.py:37 +#: models.py:38 msgid "enabled" msgstr "activado" -#: models.py:38 +#: models.py:39 msgid "whitelist" msgstr "lista blanca" -#: models.py:39 +#: models.py:40 msgid "blacklist" msgstr "lista negra" -#: models.py:140 +#: models.py:142 msgid "icon" msgstr "icono" -#: models.py:140 +#: models.py:142 msgid "An icon to visually distinguish this source." msgstr "Un icono para distinguir visualmente esta fuente." -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "folder path" msgstr "ruta de la carpeta" -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "Server side filesystem path." msgstr "Camino a los archivos en el servidor." -#: models.py:157 +#: models.py:159 msgid "preview width" msgstr "ancho de muestra" -#: models.py:157 +#: 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:158 +#: models.py:160 msgid "preview height" msgstr "alto de muestra" -#: models.py:158 +#: 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:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "uncompress" msgstr "descomprimir" -#: models.py:159 models.py:196 models.py:209 +#: 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:160 models.py:210 +#: models.py:162 models.py:212 msgid "delete after upload" msgstr "eliminar después de subir" -#: models.py:160 models.py:210 +#: 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:171 +#: models.py:173 msgid "staging folder" msgstr "carpeta de archivos provisionales" -#: models.py:211 +#: models.py:213 msgid "interval" msgstr "intervalo" -#: models.py:211 +#: models.py:213 msgid "" "Inverval in seconds where the watch folder path is checked for new " "documents." @@ -239,40 +239,40 @@ msgstr "" "Inverval es segundos, donde se comprueba la ruta de la carpeta para detectar" " nuevos documentos." -#: models.py:235 +#: models.py:237 msgid "watch folder" msgstr "carpeta observada" -#: models.py:240 +#: models.py:242 msgid "Enter a valid value." msgstr "Introduzca un valor válido." -#: models.py:268 views.py:581 +#: models.py:270 views.py:589 msgid "order" msgstr "orden" -#: models.py:269 views.py:582 views.py:619 views.py:649 +#: models.py:271 views.py:590 views.py:627 views.py:657 msgid "transformation" msgstr "transformación" -#: models.py:270 views.py:583 +#: models.py:272 views.py:591 msgid "arguments" msgstr "argumentos" -#: models.py:270 +#: models.py:272 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Utilizar diccionarios para identificar argumentos, por ejemplo: %s" -#: models.py:281 +#: models.py:283 msgid "document source transformation" msgstr "transformación de fuente de documentos" -#: models.py:282 +#: models.py:284 msgid "document source transformations" msgstr "transformaciones de fuentes de documentos" -#: models.py:288 models.py:289 +#: models.py:290 models.py:291 msgid "out of process" msgstr "fuera de proceso" @@ -415,100 +415,108 @@ msgid "files in staging path" msgstr "archivos en la direccion de archivos provisionales" #: 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:358 views.py:377 +#: 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:400 +#: views.py:408 msgid "Staging file delete successfully." msgstr "Archivos provisional borrado exitosamente." -#: views.py:402 +#: views.py:410 #, python-format msgid "Staging file delete error; %s." msgstr "Error al borrar archivo provisional; %s." -#: views.py:462 +#: views.py:470 msgid "Source edited successfully" msgstr "Fuente editada exitosamente" -#: views.py:465 +#: views.py:473 #, python-format msgid "Error editing source; %s" msgstr "Error editando fuente; %s" -#: views.py:470 +#: views.py:478 #, python-format msgid "edit source: %s" msgstr "editar fuente: %s" -#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 -#: views.py:691 +#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656 +#: views.py:699 msgid "source" msgstr "fuente" -#: views.py:504 +#: views.py:512 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Fuente \"%s\" borrada exitosamente." -#: views.py:506 +#: views.py:514 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Error borrando fuente \"%(source)s\": %(error)s" -#: views.py:513 +#: 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:545 +#: views.py:553 msgid "Source created successfully" msgstr "Fuente creada exitosamente" -#: views.py:548 +#: views.py:556 #, python-format msgid "Error creating source; %s" msgstr "Error creando fuente; %s" -#: views.py:553 +#: views.py:561 #, python-format msgid "Create new source of type: %s" msgstr "Crear nuevo tipo de fuente: %s" -#: views.py:575 +#: views.py:583 #, python-format msgid "transformations for: %s" msgstr "transformaciones para: %s" -#: views.py:605 +#: views.py:613 msgid "Source transformation edited successfully" msgstr "Transformación de la fuente editada exitosamente" -#: views.py:608 +#: views.py:616 #, python-format msgid "Error editing source transformation; %s" msgstr "Error al editar la transformación de la fuente; %s" -#: views.py:613 +#: views.py:621 #, python-format msgid "Edit transformation: %s" msgstr "Editar transformación: %s" -#: views.py:636 +#: views.py:644 msgid "Source transformation deleted successfully." msgstr "Transformación de la fuente borrada exitosamente." -#: views.py:638 +#: 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:651 +#: views.py:659 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -516,16 +524,16 @@ msgstr "" "¿Está seguro que desea eliminar la transformación de la fuente " "\"%(transformation)s\"" -#: views.py:681 +#: views.py:689 msgid "Source transformation created successfully" msgstr "Transformación de la fuente creado exitosamente" -#: views.py:684 +#: views.py:692 #, python-format msgid "Error creating source transformation; %s" msgstr "Error al crear la transformación de la fuente; %s" -#: views.py:693 +#: 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 index 1f5ed79f936ae25b9146102495424c4709402122..73223cfe1a3f1f6d1d71f271a90538668ea00c4a 100644 GIT binary patch delta 34 mcmX@=bku2su`q|Bk%FPAm65?@YheX2$I{BkcyqGwBVGWiAPGMJ delta 34 mcmX@=bku2su`q{$k%FO#m7)1$YheX2$HL0cVso\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n" "MIME-Version: 1.0\n" @@ -30,15 +30,15 @@ msgstr "cancella" msgid "sources" msgstr "sorgenti" -#: __init__.py:23 literals.py:53 models.py:201 +#: __init__.py:23 literals.py:53 models.py:203 msgid "web forms" msgstr "web forms" -#: __init__.py:24 models.py:172 +#: __init__.py:24 models.py:174 msgid "staging folders" msgstr "cartelle per la gestione temporanea" -#: __init__.py:25 models.py:236 +#: __init__.py:25 models.py:238 msgid "watch folders" msgstr "cartelle di" @@ -138,7 +138,7 @@ msgstr "Stampante" msgid "Empty printer" msgstr "Stampante vuota" -#: literals.py:47 models.py:200 +#: literals.py:47 models.py:202 msgid "web form" msgstr "web form" @@ -158,82 +158,82 @@ msgstr "server per la gestione temporanea delle cartelle" msgid "server watch folders" msgstr "server di salvataggio delle cartelle" -#: models.py:36 +#: models.py:37 msgid "title" msgstr "titolo" -#: models.py:37 +#: models.py:38 msgid "enabled" msgstr "abilitato" -#: models.py:38 +#: models.py:39 msgid "whitelist" msgstr "whitelist" -#: models.py:39 +#: models.py:40 msgid "blacklist" msgstr "blacklist" -#: models.py:140 +#: models.py:142 msgid "icon" msgstr "icona" -#: models.py:140 +#: models.py:142 msgid "An icon to visually distinguish this source." msgstr "Un'icona per distinguere visivamente questa fonte." -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "folder path" msgstr "path della cartella" -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "Server side filesystem path." msgstr "Path del server di filesystem" -#: models.py:157 +#: models.py:159 msgid "preview width" msgstr "anteprima larghezza" -#: models.py:157 +#: 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:158 +#: models.py:160 msgid "preview height" msgstr "anteprima altezza" -#: models.py:158 +#: 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:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "uncompress" msgstr "decomprimere" -#: models.py:159 models.py:196 models.py:209 +#: 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:160 models.py:210 +#: models.py:162 models.py:212 msgid "delete after upload" msgstr "cancella dopo il caricamento" -#: models.py:160 models.py:210 +#: 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:171 +#: models.py:173 msgid "staging folder" msgstr "Cartella di conservazione" -#: models.py:211 +#: models.py:213 msgid "interval" msgstr "intervallo" -#: models.py:211 +#: models.py:213 msgid "" "Inverval in seconds where the watch folder path is checked for new " "documents." @@ -241,40 +241,40 @@ msgstr "" "Invervallo di pochi secondi in cui viene controllato il percorso cartella di" " controllo per i nuovi documenti." -#: models.py:235 +#: models.py:237 msgid "watch folder" msgstr "controlla cartella" -#: models.py:240 +#: models.py:242 msgid "Enter a valid value." msgstr "Inserisci un valore valido" -#: models.py:268 views.py:581 +#: models.py:270 views.py:589 msgid "order" msgstr "ordine" -#: models.py:269 views.py:582 views.py:619 views.py:649 +#: models.py:271 views.py:590 views.py:627 views.py:657 msgid "transformation" msgstr "trasformazione" -#: models.py:270 views.py:583 +#: models.py:272 views.py:591 msgid "arguments" msgstr "argomenti" -#: models.py:270 +#: 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:281 +#: models.py:283 msgid "document source transformation" msgstr "trasformazione del documento sorgente" -#: models.py:282 +#: models.py:284 msgid "document source transformations" msgstr "trasformazioni dei documenti sorgente" -#: models.py:288 models.py:289 +#: models.py:290 models.py:291 msgid "out of process" msgstr "" @@ -411,101 +411,109 @@ 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:358 views.py:377 +#: 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:400 +#: views.py:408 msgid "Staging file delete successfully." msgstr "File in allestimento cancellato con successo." -#: views.py:402 +#: views.py:410 #, python-format msgid "Staging file delete error; %s." msgstr "Errore nella cancellazione del file in allestimento;%s." -#: views.py:462 +#: views.py:470 msgid "Source edited successfully" msgstr "Sorgente modificata con successo" -#: views.py:465 +#: views.py:473 #, python-format msgid "Error editing source; %s" msgstr "Errore nella modifica del sorgente;%s" -#: views.py:470 +#: views.py:478 #, python-format msgid "edit source: %s" msgstr "modifica sorgente:%s" -#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 -#: views.py:691 +#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656 +#: views.py:699 msgid "source" msgstr "sorgente" -#: views.py:504 +#: views.py:512 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Sorgente \"%s\" cancellata con successo." -#: views.py:506 +#: 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:513 +#: 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:545 +#: views.py:553 msgid "Source created successfully" msgstr "Sorgente creata con successo" -#: views.py:548 +#: views.py:556 #, python-format msgid "Error creating source; %s" msgstr "Errore nella creazione della sorgente;%s" -#: views.py:553 +#: views.py:561 #, python-format msgid "Create new source of type: %s" msgstr "Crea nuovo tipo di sorgente:%s" -#: views.py:575 +#: views.py:583 #, python-format msgid "transformations for: %s" msgstr "trasformazione per: %s" -#: views.py:605 +#: views.py:613 msgid "Source transformation edited successfully" msgstr "Sorgente per la trasformazione modificata con successo" -#: views.py:608 +#: views.py:616 #, python-format msgid "Error editing source transformation; %s" msgstr "Errore nella modifica della sorgente per la trasformazione;%s" -#: views.py:613 +#: views.py:621 #, python-format msgid "Edit transformation: %s" msgstr "Modifica trasformazione:%s" -#: views.py:636 +#: views.py:644 msgid "Source transformation deleted successfully." msgstr "Sorgente per la trasformazione cancellata con successo." -#: views.py:638 +#: 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:651 +#: views.py:659 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -513,16 +521,16 @@ msgstr "" "Sei sicuro di voler cancellare la sorgente di trasformazione " "\"%(transformation)s\"" -#: views.py:681 +#: views.py:689 msgid "Source transformation created successfully" msgstr "Sorgente di trasformazione creata con successo" -#: views.py:684 +#: views.py:692 #, python-format msgid "Error creating source transformation; %s" msgstr "Errore nella creazione della sorgente di trasformazione; %s" -#: views.py:693 +#: 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/pt/LC_MESSAGES/django.mo b/apps/sources/locale/pt/LC_MESSAGES/django.mo index 3ccd8d7c726cdd4f49c5747cb56e285c29e7a26a..6f2e4bc1cd5fbf0c85fb76911d4470c2788a12c9 100644 GIT binary patch delta 34 mcmZp4Xmr?MEX-kOq+n=jWn?hfT37+hv9vNW-kdBvj|Tvkj|gr6 delta 34 mcmZp4Xmr?MEX-kGq+n=bWoSOxT37+hv9L0<*qkgpj|Tvk(Fk+^ diff --git a/apps/sources/locale/pt/LC_MESSAGES/django.po b/apps/sources/locale/pt/LC_MESSAGES/django.po index 8b6840a616..2898677a7d 100644 --- a/apps/sources/locale/pt/LC_MESSAGES/django.po +++ b/apps/sources/locale/pt/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:18+0000\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" @@ -30,15 +30,15 @@ msgstr "excluir" msgid "sources" msgstr "fontes" -#: __init__.py:23 literals.py:53 models.py:201 +#: __init__.py:23 literals.py:53 models.py:203 msgid "web forms" msgstr "formulários web" -#: __init__.py:24 models.py:172 +#: __init__.py:24 models.py:174 msgid "staging folders" msgstr "staging folders" -#: __init__.py:25 models.py:236 +#: __init__.py:25 models.py:238 msgid "watch folders" msgstr "assistir pastas" @@ -140,7 +140,7 @@ msgstr "Impressora" msgid "Empty printer" msgstr "Impressora vazia" -#: literals.py:47 models.py:200 +#: literals.py:47 models.py:202 msgid "web form" msgstr "formulário web" @@ -160,79 +160,79 @@ msgstr "server staging folders" msgid "server watch folders" msgstr "assistir pastas do servidor" -#: models.py:36 +#: models.py:37 msgid "title" msgstr "título" -#: models.py:37 +#: models.py:38 msgid "enabled" msgstr "habilitado" -#: models.py:38 +#: models.py:39 msgid "whitelist" msgstr "lista branca" -#: models.py:39 +#: models.py:40 msgid "blacklist" msgstr "lista negra" -#: models.py:140 +#: models.py:142 msgid "icon" msgstr "ícone" -#: models.py:140 +#: models.py:142 msgid "An icon to visually distinguish this source." msgstr "Um ícone para distinguir visualmente essa fonte." -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "folder path" msgstr "caminho da pasta" -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "Server side filesystem path." msgstr "Caminho do sistema do servidor" -#: models.py:157 +#: models.py:159 msgid "preview width" msgstr "largura de visualização" -#: models.py:157 +#: 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:158 +#: models.py:160 msgid "preview height" msgstr "altura de visualização" -#: models.py:158 +#: 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:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "uncompress" msgstr "descompactar" -#: models.py:159 models.py:196 models.py:209 +#: 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:160 models.py:210 +#: models.py:162 models.py:212 msgid "delete after upload" msgstr "excluir após o upload" -#: models.py:160 models.py:210 +#: 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:171 +#: models.py:173 msgid "staging folder" msgstr "preparação de pasta" -#: models.py:211 +#: models.py:213 msgid "interval" msgstr "intervalo" -#: models.py:211 +#: models.py:213 msgid "" "Inverval in seconds where the watch folder path is checked for new " "documents." @@ -240,40 +240,40 @@ msgstr "" "Invervalo em segundos, onde o caminho da pasta assistida está marcada para " "novos documentos." -#: models.py:235 +#: models.py:237 msgid "watch folder" msgstr "assistir pasta" -#: models.py:240 +#: models.py:242 msgid "Enter a valid value." msgstr "Digite um valor válido." -#: models.py:268 views.py:581 +#: models.py:270 views.py:589 msgid "order" msgstr "ordem" -#: models.py:269 views.py:582 views.py:619 views.py:649 +#: models.py:271 views.py:590 views.py:627 views.py:657 msgid "transformation" msgstr "transformação" -#: models.py:270 views.py:583 +#: models.py:272 views.py:591 msgid "arguments" msgstr "argumentos" -#: models.py:270 +#: 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:281 +#: models.py:283 msgid "document source transformation" msgstr "transformação do documento de origem" -#: models.py:282 +#: models.py:284 msgid "document source transformations" msgstr "fonte de transformações de documentos" -#: models.py:288 models.py:289 +#: models.py:290 models.py:291 msgid "out of process" msgstr "" @@ -411,100 +411,108 @@ msgid "files in staging path" msgstr "files in staging path" #: 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:358 views.py:377 +#: views.py:366 views.py:385 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "Staging file transformation error: %(error)s" -#: views.py:400 +#: views.py:408 msgid "Staging file delete successfully." msgstr "Staging file delete successfully." -#: views.py:402 +#: views.py:410 #, python-format msgid "Staging file delete error; %s." msgstr "Staging file delete error; %s." -#: views.py:462 +#: views.py:470 msgid "Source edited successfully" msgstr "Fonte editada com sucesso" -#: views.py:465 +#: views.py:473 #, python-format msgid "Error editing source; %s" msgstr "Erro ao editar fonte; %s" -#: views.py:470 +#: views.py:478 #, python-format msgid "edit source: %s" msgstr "editar fonte: %s" -#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 -#: views.py:691 +#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656 +#: views.py:699 msgid "source" msgstr "fonte" -#: views.py:504 +#: views.py:512 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Fonte \"%s\" removida com sucesso." -#: views.py:506 +#: views.py:514 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Erro ao excluir fonte \" %(source)s \": %(error)s " -#: views.py:513 +#: 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:545 +#: views.py:553 msgid "Source created successfully" msgstr "Fonte criada com sucesso" -#: views.py:548 +#: views.py:556 #, python-format msgid "Error creating source; %s" msgstr "Erro ao criar fonte; %s" -#: views.py:553 +#: views.py:561 #, python-format msgid "Create new source of type: %s" msgstr "Criar nova fonte do tipo: %s" -#: views.py:575 +#: views.py:583 #, python-format msgid "transformations for: %s" msgstr "transformações para: %s" -#: views.py:605 +#: views.py:613 msgid "Source transformation edited successfully" msgstr "Transformação de fonte alterado com sucesso" -#: views.py:608 +#: views.py:616 #, python-format msgid "Error editing source transformation; %s" msgstr "Erro ao editar transformação de fonte; %s" -#: views.py:613 +#: views.py:621 #, python-format msgid "Edit transformation: %s" msgstr "Editar transformação: %s" -#: views.py:636 +#: views.py:644 msgid "Source transformation deleted successfully." msgstr "Transformação de fonte excluída com sucesso." -#: views.py:638 +#: views.py:646 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "Erro ao deletar transformação de fonte; %(error)s " -#: views.py:651 +#: views.py:659 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -512,16 +520,16 @@ msgstr "" "Tem certeza de que deseja deletar a transformação de fonte \" " "%(transformation)s \"" -#: views.py:681 +#: views.py:689 msgid "Source transformation created successfully" msgstr "Transformação de fonte criada com sucesso" -#: views.py:684 +#: views.py:692 #, python-format msgid "Error creating source transformation; %s" msgstr "Erro ao criar a transformação de fonte; %s" -#: views.py:693 +#: 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 7155e2b7493d109e0e28009cfdacafe6e71e21c8..363361635b71ba16256fbbb830126687f84dad06 100644 GIT binary patch delta 3702 zcmcK4du)_d8prX|Lf3L>f!?TA?NO-|3Z*RtUgSa* zIDxm|86-(ll4r~;oQf=?*@PPSVVsUTundo44gL{Tf${mN_luBQrVQCOW^USBP?cPs zPyM+zYxq#do3Rw1L@mW@$Yjl1s1o+0_Q1QyHZW&V&z(GyKte-{|j6^$`_xezgWwWASV;V>#+;T z#k`D_coG-lSGWjg@K8NQQ3>|o4R{8Z;3b@aw{r7-jN=0Q2p?m7lfwp>i%(+&PoidC z#o1bhyHS-ni>lO=8;#kH8}=CA?eY9v>)7d6lcR3cyC1k7d@xp)<7 z(@nt)Tt(>q_ieP+Ul~3^Y$8;4%|MOn8kW}oNxlO|688~JgpQJ0X$pU%Dp9pjgnk3G z+3qB6BXm;M5^7b1_Jt~uQ1+UM+EPO6sfrA5RLuN};I#QoCt_y$S~FLBkWh7WI<$cw zCREL#O;uGJLHttZUrlS;NGu|j5&A(=W10P*<7RBo4O)y?>0fa~QDK~}xPrKwXd`Nf5<-n%q#+AL#<0z&N}Vzqx|%q>&5znZBxKuLo1=jc-vnZ|DH3YxXbQClnr$O*#wz^|oISb4 zGyR@Ac_tE#+khR?qn@1h<8I=XCo7%L$L!A!ciPafOx0g<+t~4$^Zw_=oGrN(&Tn$_ zrhlK&<$QjeO2EdNBAY3KvUFa}ZO)54#H^c{Z}`{2aBG~(CC7}b$jptl$8EIHwzfr8 zpXBTbcV;;2^G1!2FoU5bc2?#U&KZ8w#^Qm^3}j=`_O@WS)|SOgs<3v*qfU3;f$ZuU zTRpqBrpl?yxBfr#YHMaDgZYJ7H~h{$>~(qD++J^wbq~3NZlAZ^J?0*E2fS{#$GW}l zQ75DH#)K^&m3 z|LVcI2l-==L+)Yg4l*PcZojvS;dgpZSnu&v&+4P{a`(d$SvWBCy8*gl>?35*{nKOi zDJ{#yw|U*(u1aTJ$%O^`QfaCR2Y;p{KT(ARSI-{dym9Sy_fVz($K0K0>3sEnhgLxo zbPsqt-Too-9G(>Q(_@skmuWu1><;nbpnL3xdONR|UaHzhxd-Wt^>PpR3&2YG5Arf^ zvV8sCZtp37xqIEi$^G`lkp*lD>mKK&LGMYwjN9CvWL;V2h{>1JILfQ+AB}mCcxOmm i-Cn1(yx2KEc|yt0KT}-fcj0aKb`R;o+wIhqcmD@3V@PfQ delta 2345 zcmY+^e@xVM9LMoDcZWdyJh+22j8goGzmod;cB_X=3-RqEZGXp zGQX=!UxGzu5i6w<;vehLgGW#g4r3}FM?aoIUa)b@#wqk+3^jnCQ5{{w z#aNJOR)tllf%aepp1@l%ibeEqF)Etj9MiZV3i)6}IDQ9KuQ*L;mb@E?M+%GgNNJtEh(3auTVoM2)x`HM6I21)fDc7fbp( zZsvDht{GL^gAF)rFhj)Jy*L!g6kC4J%LssYSiG7B!$2BsmsF zHPnNJIEWg^^QgV>CdM}_>itR7`=6i&^d)LSv#5UNz2sjH+(m3;YN&M zBW5w0E^I?>qSsLwxP*7$3^t&bEvh@*HC8JiVxMAUu_4r5F5_ayQcu}`@! z=O1&Z4@Mf7YAnMR>_TP4!B+el)v=GASBlNJ4g0YM-^2a*9d5w-lEn9A5PSK34tHXD zKog8`T&Nu5#u(~YRB*PAU>J4GE^^s}b9fJi80{{65jEpk)TYa1G;1&)b<8#*%WsE~ zB-&9_Cf>kRIDu{SZ{Mhbi#gn6)%s8~8AdfQfwlM{YS&*!rQE}4wZ^%~$+BWp2UV!| zo3R-mMP+OP>+maFhn{lsuNk&bk^QKKo<()+AkW%3GDeFf@Be{%&P}VVn)#9jQ5|(~ z(Lf)^9z2P6<2YSX-nDX1OmA^M3hq4c^4rCmjxE0qgH z%cHW3xSzO_&@olnPPE5siT#wQlK)0(>=oNWXx*4xyl4|@77RK*3*BU?;~$(>)SmDW znt)0Np^X(F_7Sy&ik~T z-9>0eFBI*1l?RDVVk@Eb?jp1gLPQ&JkZ=<_h)5HchX|EYqL0wpR}$L@mHP<37xA*0 zYdtZL_-WnPLTHEU`@zcDy##yoe`PJdw7Io!7D_tbyZC2uQSuH)J6@J?Eg|%UdVt6z zQi(L;zY_f{, 2011. +# Sergey Glita , 2011, 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-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:18+0000\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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\n" "MIME-Version: 1.0\n" @@ -30,15 +30,15 @@ msgstr "удалить" msgid "sources" msgstr "источники" -#: __init__.py:23 literals.py:53 models.py:201 +#: __init__.py:23 literals.py:53 models.py:203 msgid "web forms" msgstr "web-формы" -#: __init__.py:24 models.py:172 +#: __init__.py:24 models.py:174 msgid "staging folders" msgstr "транспортные папки" -#: __init__.py:25 models.py:236 +#: __init__.py:25 models.py:238 msgid "watch folders" msgstr "наблюдаемые папки" @@ -64,7 +64,7 @@ msgstr "Источники документов" #: __init__.py:38 msgid "upload new version" -msgstr "" +msgstr "загрузить новую версию" #: __init__.py:68 widgets.py:39 msgid "thumbnail" @@ -85,7 +85,7 @@ msgstr "Промежуточный файл" #: forms.py:50 msgid "File" -msgstr "" +msgstr "Файл" #: literals.py:8 literals.py:13 msgid "Always" @@ -139,7 +139,7 @@ msgstr "Принтер" msgid "Empty printer" msgstr "Пустой принтер" -#: literals.py:47 models.py:200 +#: literals.py:47 models.py:202 msgid "web form" msgstr "веб-формы" @@ -159,121 +159,121 @@ msgstr "папки на промежуточном сервере" msgid "server watch folders" msgstr "наблюдаемые папки" -#: models.py:36 +#: models.py:37 msgid "title" msgstr "название" -#: models.py:37 +#: models.py:38 msgid "enabled" msgstr "разрешено" -#: models.py:38 +#: models.py:39 msgid "whitelist" msgstr "белый список" -#: models.py:39 +#: models.py:40 msgid "blacklist" msgstr "черный список" -#: models.py:140 +#: models.py:142 msgid "icon" msgstr "иконка" -#: models.py:140 +#: models.py:142 msgid "An icon to visually distinguish this source." msgstr "Значок, чтобы визуально отличать этот источник." -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "folder path" msgstr "путь к папке" -#: models.py:156 models.py:208 +#: models.py:158 models.py:210 msgid "Server side filesystem path." msgstr "Путь на сервере" -#: models.py:157 +#: models.py:159 msgid "preview width" msgstr "ширина предпросмотра" -#: models.py:157 +#: models.py:159 msgid "Width value to be passed to the converter backend." msgstr "Ширина после обработки." -#: models.py:158 +#: models.py:160 msgid "preview height" msgstr "Предварительный просмотр высоты" -#: models.py:158 +#: models.py:160 msgid "Height value to be passed to the converter backend." msgstr "Высота после обработки." -#: models.py:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "uncompress" msgstr "распаковать" -#: models.py:159 models.py:196 models.py:209 +#: models.py:161 models.py:198 models.py:211 msgid "Whether to expand or not compressed archives." msgstr "Независимо от того распакованы или нет архивы." -#: models.py:160 models.py:210 +#: models.py:162 models.py:212 msgid "delete after upload" msgstr "удалить после загрузки" -#: models.py:160 models.py:210 +#: models.py:162 models.py:212 msgid "Delete the file after is has been successfully uploaded." msgstr "Удалить файл после загрузки." -#: models.py:171 +#: models.py:173 msgid "staging folder" msgstr "промежуточная папка" -#: models.py:211 +#: models.py:213 msgid "interval" msgstr "интервал" -#: models.py:211 +#: models.py:213 msgid "" "Inverval in seconds where the watch folder path is checked for new " "documents." msgstr "" "Интервал в секундах, между проверками папки на появление новых документов." -#: models.py:235 +#: models.py:237 msgid "watch folder" msgstr "просматривать папку" -#: models.py:240 +#: models.py:242 msgid "Enter a valid value." msgstr "Введите допустимое значение." -#: models.py:268 views.py:581 +#: models.py:270 views.py:589 msgid "order" msgstr "порядок" -#: models.py:269 views.py:582 views.py:619 views.py:649 +#: models.py:271 views.py:590 views.py:627 views.py:657 msgid "transformation" msgstr "преобразование" -#: models.py:270 views.py:583 +#: models.py:272 views.py:591 msgid "arguments" msgstr "аргументы" -#: models.py:270 +#: models.py:272 #, python-format msgid "Use dictionaries to indentify arguments, example: %s" msgstr "Использование словарей для определения аргументов, например: %s" -#: models.py:281 +#: models.py:283 msgid "document source transformation" msgstr "преобразования источника документов" -#: models.py:282 +#: models.py:284 msgid "document source transformations" msgstr "преобразования источника документов" -#: models.py:288 models.py:289 +#: models.py:290 models.py:291 msgid "out of process" -msgstr "" +msgstr "из процесса" #: permissions.py:7 msgid "Sources setup" @@ -336,29 +336,29 @@ msgstr "" #: views.py:163 msgid "New document version uploaded successfully." -msgstr "" +msgstr "Новая версия документа загружена." #: views.py:167 msgid "File uploaded successfully." -msgstr "" +msgstr "Файл загружен." #: views.py:170 msgid "File uncompressed successfully and uploaded as individual files." -msgstr "" +msgstr "Файл распакован и загружен в виде отдельных файлов." #: views.py:173 msgid "File was not a compressed file, uploaded as it was." -msgstr "" +msgstr "Файл не сжат и загружен как есть." #: views.py:179 views.py:258 #, python-format msgid "Unhandled exception: %s" -msgstr "" +msgstr "Необработанное исключение %s" #: views.py:188 #, python-format msgid "upload a new version from source: %s" -msgstr "" +msgstr "загрузка новой версии из источника %s" #: views.py:190 #, python-format @@ -368,7 +368,7 @@ msgstr "загрузить локальный документ из источн #: views.py:236 #, python-format msgid "Document version from staging file: %s, uploaded successfully." -msgstr "" +msgstr "Версия документа из транспортного файла %s загружена." #: views.py:239 #, python-format @@ -380,12 +380,12 @@ msgstr "Промежуточный файл %s загружен." msgid "" "Staging file: %s, uncompressed successfully and uploaded as individual " "files." -msgstr "" +msgstr "Транспортный файл %s распакован и загружен в виде отдельных файлов." #: views.py:245 #, python-format msgid "Staging file: %s, was not compressed, uploaded as a single file." -msgstr "" +msgstr "Транспортный файл %s не был сжат загруженные в исходном виде." #: views.py:250 #, python-format @@ -395,7 +395,7 @@ msgstr "Постановка файл %s успешно удален." #: views.py:273 #, python-format msgid "upload a new version from staging source: %s" -msgstr "" +msgstr "загрузка новой версии из источника %s" #: views.py:275 #, python-format @@ -407,100 +407,108 @@ 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:358 views.py:377 +#: views.py:366 views.py:385 #, python-format msgid "Staging file transformation error: %(error)s" msgstr "Ошибка преобразования транспортного файла: %(error)s" -#: views.py:400 +#: views.py:408 msgid "Staging file delete successfully." msgstr "Транспортный файл удалён." -#: views.py:402 +#: views.py:410 #, python-format msgid "Staging file delete error; %s." msgstr "Ошибка удаления транспортного файла %s." -#: views.py:462 +#: views.py:470 msgid "Source edited successfully" msgstr "Источник успешно изменен" -#: views.py:465 +#: views.py:473 #, python-format msgid "Error editing source; %s" msgstr "Ошибка редактирования источника; %s" -#: views.py:470 +#: views.py:478 #, python-format msgid "edit source: %s" msgstr "редактировать источник: %s" -#: views.py:475 views.py:515 views.py:577 views.py:618 views.py:648 -#: views.py:691 +#: views.py:483 views.py:523 views.py:585 views.py:626 views.py:656 +#: views.py:699 msgid "source" msgstr "источник" -#: views.py:504 +#: views.py:512 #, python-format msgid "Source \"%s\" deleted successfully." msgstr "Источник \"%s\"удален." -#: views.py:506 +#: views.py:514 #, python-format msgid "Error deleting source \"%(source)s\": %(error)s" msgstr "Ошибка при удалении источника \"%(source)s\": %(error)s" -#: views.py:513 +#: views.py:521 #, python-format msgid "Are you sure you wish to delete the source: %s?" msgstr "Вы действительно хотите удалить источник: %s?" -#: views.py:545 +#: views.py:553 msgid "Source created successfully" msgstr "Источник создан" -#: views.py:548 +#: views.py:556 #, python-format msgid "Error creating source; %s" msgstr "Ошибка создания источника; %s" -#: views.py:553 +#: views.py:561 #, python-format msgid "Create new source of type: %s" msgstr "Создать новый источник типа: %s" -#: views.py:575 +#: views.py:583 #, python-format msgid "transformations for: %s" msgstr "преобразования для: %s" -#: views.py:605 +#: views.py:613 msgid "Source transformation edited successfully" msgstr "Преобразование источника изменено" -#: views.py:608 +#: views.py:616 #, python-format msgid "Error editing source transformation; %s" msgstr "Ошибка редактирования преобразования источника; %s" -#: views.py:613 +#: views.py:621 #, python-format msgid "Edit transformation: %s" msgstr "Изменить преобразование: %s" -#: views.py:636 +#: views.py:644 msgid "Source transformation deleted successfully." msgstr "Преобразование источника удалено." -#: views.py:638 +#: views.py:646 #, python-format msgid "Error deleting source transformation; %(error)s" msgstr "Ошибка при удалении преобразования источника; %(error)s" -#: views.py:651 +#: views.py:659 #, python-format msgid "" "Are you sure you wish to delete source transformation \"%(transformation)s\"" @@ -508,16 +516,16 @@ msgstr "" "Вы действительно хотите удалить источник трансформации " "\"%(transformation)s\"" -#: views.py:681 +#: views.py:689 msgid "Source transformation created successfully" msgstr "Преобразование источника создано" -#: views.py:684 +#: views.py:692 #, python-format msgid "Error creating source transformation; %s" msgstr "Ошибка создания преобразования источника; %s" -#: views.py:693 +#: views.py:701 #, python-format msgid "Create new transformation for source: %s" msgstr "Создать новое преобразование для источника: %s" diff --git a/apps/tags/locale/en/LC_MESSAGES/django.po b/apps/tags/locale/en/LC_MESSAGES/django.po index cd16115144..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: 2012-02-02 14:17-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,51 +17,47 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:21 +#: __init__.py:20 msgid "tag list" msgstr "" -#: __init__.py:22 +#: __init__.py:21 msgid "create new tag" msgstr "" -#: __init__.py:23 +#: __init__.py:22 msgid "attach tag" msgstr "" -#: __init__.py:24 __init__.py:25 +#: __init__.py:23 __init__.py:24 msgid "remove" msgstr "" -#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 +#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98 msgid "tags" msgstr "" -#: __init__.py:27 __init__.py:30 +#: __init__.py:26 __init__.py:29 msgid "delete" msgstr "" -#: __init__.py:28 +#: __init__.py:27 msgid "edit" msgstr "" -#: __init__.py:29 +#: __init__.py:28 msgid "tagged documents" msgstr "" -#: __init__.py:31 +#: __init__.py:30 msgid "ACLs" msgstr "" -#: __init__.py:35 models.py:13 -msgid "color" +#: __init__.py:34 +msgid "preview" msgstr "" -#: __init__.py:39 -msgid "color name" -msgstr "" - -#: __init__.py:43 +#: __init__.py:38 msgid "tagged items" msgstr "" @@ -117,10 +113,14 @@ msgstr "" msgid "Yellow" msgstr "" -#: models.py:12 views.py:153 views.py:205 views.py:219 +#: models.py:12 views.py:154 views.py:206 views.py:220 msgid "tag" msgstr "" +#: models.py:13 +msgid "color" +msgstr "" + #: models.py:16 msgid "tag properties" msgstr "" @@ -180,64 +180,64 @@ msgstr "" msgid "attach tag to: %s" msgstr "" -#: views.py:129 views.py:256 +#: views.py:130 views.py:257 msgid "Must provide at least one tag." msgstr "" -#: views.py:144 +#: views.py:145 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "" -#: views.py:146 views.py:268 +#: views.py:147 views.py:269 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" msgstr "" -#: views.py:161 +#: views.py:162 #, python-format msgid "Are you sure you wish to delete the tag: %s?" msgstr "" -#: views.py:162 views.py:165 +#: views.py:163 views.py:166 msgid "Will be removed from all documents." msgstr "" -#: views.py:164 +#: views.py:165 #, python-format msgid "Are you sure you wish to delete the tags: %s?" msgstr "" -#: views.py:193 +#: views.py:194 msgid "Tag updated succesfully." msgstr "" -#: views.py:202 +#: views.py:203 #, python-format msgid "edit tag: %s" msgstr "" -#: views.py:216 +#: views.py:217 #, python-format msgid "documents with the tag \"%s\"" msgstr "" -#: views.py:235 +#: views.py:236 #, python-format msgid "tags for: %s" msgstr "" -#: views.py:266 +#: views.py:267 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "" -#: views.py:282 +#: views.py:283 #, python-format msgid "Are you sure you wish to remove the tag: %s?" msgstr "" -#: views.py:284 +#: 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 a451381c2c1e4a183856693e0e6ea641894085d9..23f977dc773033ba9bf7d77abc86091d014ea844 100644 GIT binary patch delta 1458 zcmYk+O-K}B9LMoz%hh#T%Ph+@YphH&w{lG_qi8cBLo|xKM297(G}NuxvAW1coq7R- zA*f3c1ceY4LWc@^IYm+j@m3Ud>6Ap!3rNuSH#>z7^PkT=FFx~so@dsniWimH4<&h5 z4W)%xPE3W2>A=f#xltbE8N+2Ba$AItupVDy9DfD%>Ts^UAIoSzi*%Xm$YpK>-o^#g z$B_Q4dCbE+8lK@QoWMey#v1&MF|_h?6U9;ejaY!&aRs)cUf7FVrk|VEa01KG#g#aU z8h_t6Ys_07w6d?L%tOp7%TW_HqF%TKSK}^Zs5y#J9K?lq2FcZ2#QAt7=)Z{?KZX_f z5H;@`jPZUm$pe@9$V~&kpfaDv2!2ORID^F)rBORlftsi`sK-%T+lrq##=Sv*oGdG8 zPhbM~p^p1JX4UW{XqZL~T+4ZA;@zkfbp&?f66yzo{sB}%C$R?41@$rX=S3wxjhg2V z@(MGT>{*MMALIPBrAuhg%3FhuBr1UpRDTy%qZ8Dx;Tq~sQAhU)mG}?TH?*iIcVx}T zWp;AY-*+LKVqDabjTEu}OL-WjK^fk`#dr_3l`m0$Fp2tj-k}nmLG8pGmZz003#>wo zUxy`_K+WHd8h<#@MSWA3vOH+uRn$j!7dblr7qK2U5GqPWMPIIpl2uVsN}!3*nf@zl zdC)hcqAlM{Xkl{*6(ysi%W5?`JKpPWHTYYmpUfs=9igq#cC)*tkmA^@K_-p|e)emYQT+XU5x; zH&K>!-PDmj%S|22SZ>X`3Jn8`CSDk9Qzb4UR%NYNJGMEXlhMt@@gWMU)kE4Xc_O0YzyUewk0#(g~Ff9 zhwS4i$Fkl2lf$-~%2=uY?@njDk?4lvU1`UeJ;ED{)|HXM>^9TxIBCa94S3HBOUJ)O d`$FL!n_0c?SfBSQHc&7)Y-e02QJYoKbP_lNFAaGf-Z%Dx89%a@!|LE^?ZMSpXd91_By^CD}Jr>-ZHc_ zeJA~q$CxA7zmXr>F|RQZJdQ~`i=9|<@pBjdKn@e}8N*>3oQ+sZ+=9BE!QI%4ZN?PM z83vm;F@+rFCO_3Ui+;R^jraidf+eiN52!gV;|~0cyYMgS{s=e8G-?4Su>o_=N%Zo4 zGs~cv3%8NOyyB+@-{2Pfh`iH$cjtd$n0VF2US`SA)M5;ysEMXg3+r*$kD?}g0s}aV zVZLv&3^wB>)B{&gFSzdF5-NqW_>J<+W1P4|npCz0?7lbkkammGxv4waU zRg$$J`PWK9EL)qR16BJW)Pq@6swPpTn8s~5hg#7SROX)HR$M}5>I>?*->5zD4>i$f zsIu}nY9W~r`PYs8oT$SA)CaQe#>>uW)Wq(f?pr`@rWZ&>Oc!1M9yNVPO`B5nR%5~C z%xE&5bUmA-$5nsr(hj;lP)}FWNA{OTl?f?r+FUBrdP_0byB=UGz1zjgCUYw{WlmXA zX_fYNy2`6IqBN_izDnUfx-ycWtEtXvWU#zxwwI$ynpJ`g^d`E}sb-&g-`P1|n|<$V zUR?7X^4P=v;p+TYzL1z09naYr|A_tRUkP-l6RAvJs>i+!B+9{ozEtnxpTI$nP1mg2 mfnd^J4Yn`73{H9MQ0QE6B0qkAIcmD%)(`}ak diff --git a/apps/tags/locale/es/LC_MESSAGES/django.po b/apps/tags/locale/es/LC_MESSAGES/django.po index 06404c5505..2a28bd8cd7 100644 --- a/apps/tags/locale/es/LC_MESSAGES/django.po +++ b/apps/tags/locale/es/LC_MESSAGES/django.po @@ -3,13 +3,13 @@ # 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: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:19+0000\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" @@ -18,51 +18,47 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:21 +#: __init__.py:20 msgid "tag list" msgstr "lista de etiquetas" -#: __init__.py:22 +#: __init__.py:21 msgid "create new tag" msgstr "crear nueva etiqueta" -#: __init__.py:23 +#: __init__.py:22 msgid "attach tag" msgstr "adjuntar etiqueta" -#: __init__.py:24 __init__.py:25 +#: __init__.py:23 __init__.py:24 msgid "remove" msgstr "remover" -#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 +#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98 msgid "tags" msgstr "etiquetas" -#: __init__.py:27 __init__.py:30 +#: __init__.py:26 __init__.py:29 msgid "delete" msgstr "eliminar" -#: __init__.py:28 +#: __init__.py:27 msgid "edit" msgstr "editar" -#: __init__.py:29 +#: __init__.py:28 msgid "tagged documents" msgstr "documentos etiquetados" -#: __init__.py:31 +#: __init__.py:30 msgid "ACLs" -msgstr "" +msgstr "LCAs" -#: __init__.py:35 models.py:13 -msgid "color" -msgstr "color" +#: __init__.py:34 +msgid "preview" +msgstr "muestra" -#: __init__.py:39 -msgid "color name" -msgstr "nombre del color" - -#: __init__.py:43 +#: __init__.py:38 msgid "tagged items" msgstr "artículos etiquetados" @@ -118,10 +114,14 @@ msgstr "Naranja" msgid "Yellow" msgstr "Amarillo" -#: models.py:12 views.py:153 views.py:205 views.py:219 +#: models.py:12 views.py:154 views.py:206 views.py:220 msgid "tag" msgstr "etiqueta" +#: models.py:13 +msgid "color" +msgstr "color" + #: models.py:16 msgid "tag properties" msgstr "propiedades de etiqueta" @@ -136,19 +136,19 @@ msgstr "Crear nuevas etiquetas" #: permissions.py:10 msgid "Delete tags" -msgstr "" +msgstr "Borrar etiquetas" #: permissions.py:11 msgid "Edit tags" -msgstr "" +msgstr "Editar etiquetas" #: permissions.py:12 msgid "View tags" -msgstr "" +msgstr "Ver etiquetas" #: permissions.py:13 msgid "Attach tags to documents" -msgstr "" +msgstr "Anejar etiquetas a documentos" #: permissions.py:14 msgid "Remove tags from documents" @@ -181,64 +181,64 @@ msgstr "Etiqueta \"%s\" adjuntada exitosamente." msgid "attach tag to: %s" msgstr "adjuntar etiqueta a: %s" -#: views.py:129 views.py:256 +#: views.py:130 views.py:257 msgid "Must provide at least one tag." msgstr "Debe proveer al menos una etiqueta." -#: views.py:144 +#: views.py:145 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Etiqueta \"%s\" borrada exitosamente." -#: views.py:146 views.py:268 +#: 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:161 +#: 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:162 views.py:165 +#: views.py:163 views.py:166 msgid "Will be removed from all documents." msgstr "Se removerá de todos los documentos." -#: views.py:164 +#: 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:193 +#: views.py:194 msgid "Tag updated succesfully." msgstr "Etiqueta actualizada exitosamente." -#: views.py:202 +#: views.py:203 #, python-format msgid "edit tag: %s" msgstr "editar la etiqueta: %s" -#: views.py:216 +#: views.py:217 #, python-format msgid "documents with the tag \"%s\"" msgstr "documentos con la etiqueta \"%s\"" -#: views.py:235 +#: views.py:236 #, python-format msgid "tags for: %s" msgstr "etiquetas para: %s" -#: views.py:266 +#: views.py:267 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Etiqueta \"%s\" removida exitosamente." -#: views.py:282 +#: 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:284 +#: 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?" diff --git a/apps/tags/locale/it/LC_MESSAGES/django.mo b/apps/tags/locale/it/LC_MESSAGES/django.mo index 8c6c87fca7202f1f46a444735ed9d71c2ec1839d..053f74c2735b0f6487db39e36f237bd057e3a893 100644 GIT binary patch delta 1012 zcmYk*OGs2v9LMqhc&~QzRXGmUT(e0h$H_5gCZ}?+#Spa7h=_2bD_0ghkX8{4QXz_) z7$VY@;G$(PP$7sQEp#i@BB+gRS_amlg8KgQ2p-NkpYynL-t#$p9hSee_|J@xBej#3 zBW9N{4p&iYe1~z|z!SKQ`rhLs*@@af36J6p=NZWapvJj~hne3-DCh^{ zr~z)e`d!q~J;aY(%RHW>KEd$};1ew33TE+#vzygxoKe&Q#*m-d1h(NV*Zv60c^c*@ zoWoTl+76j^{1=dv=Z{X1&HU#JskVK(j;v+K~hLokNI0Q)t`0gNRZ1Xa)n|( YTS*0p|CPaF{%rMXaNDnLG{z$T0C|&BAOHXW delta 1044 zcmXxiKWLLd7{~D^=50-E+Ein0Xli|Ht5wt1BqXf~E=5602XU%H9Wq3hrok?XL$Xwd zil77ui1=qv5gf#zC^(3VU0jMv6%+(roCI-j((kXi9`C)Md)_~H_uSp{#Fs?v>o)I( zQ8Lti>f?af5j-5^Mmg@8#c&!&@idO%vWs81_y=-Xtj&ze;?4n#5)Y%^XK^>?am1`< zb2K76SVAtl&Mk}$+>G~d03V?`SiyFDhnnMi?87zOg}+hX$M{HQPzjvGIF_7M^cde7 zG=_L_3%Tqyw=MVMN<<5|=X7f>Bsa`7^12^;v4?RkiU#8s9li+8brA25a8%wA5R`dLIx@I3OXRk0T@ zV@)q^)6o9k#|d0RE{k@wGVjAqVjtDPIQlq&8ekT+Wpk*NI^*8Y<1q169Kok9{*0Qy zzYf-aCyidxRz^8gN3*CyQbbK~3AKk;um|tB=g*M7>=kNnS5RB?4YkC-P-oz;i{oUW zfd^5E3lOADtm1Um2$~%-i-7I{sRU$ BT8;n! diff --git a/apps/tags/locale/it/LC_MESSAGES/django.po b/apps/tags/locale/it/LC_MESSAGES/django.po index 9db54331f8..34e4aceea0 100644 --- a/apps/tags/locale/it/LC_MESSAGES/django.po +++ b/apps/tags/locale/it/LC_MESSAGES/django.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:19+0000\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" @@ -19,51 +19,47 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:21 +#: __init__.py:20 msgid "tag list" msgstr "lista delle etichette" -#: __init__.py:22 +#: __init__.py:21 msgid "create new tag" msgstr "crea una nuova etichetta" -#: __init__.py:23 +#: __init__.py:22 msgid "attach tag" msgstr "allega un'etichetta" -#: __init__.py:24 __init__.py:25 +#: __init__.py:23 __init__.py:24 msgid "remove" msgstr "rimuovi" -#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 +#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98 msgid "tags" msgstr "etichette" -#: __init__.py:27 __init__.py:30 +#: __init__.py:26 __init__.py:29 msgid "delete" msgstr "cancella" -#: __init__.py:28 +#: __init__.py:27 msgid "edit" msgstr "modifica" -#: __init__.py:29 +#: __init__.py:28 msgid "tagged documents" msgstr "documenti etichettati" -#: __init__.py:31 +#: __init__.py:30 msgid "ACLs" msgstr "" -#: __init__.py:35 models.py:13 -msgid "color" -msgstr "colore" +#: __init__.py:34 +msgid "preview" +msgstr "" -#: __init__.py:39 -msgid "color name" -msgstr "nome colore" - -#: __init__.py:43 +#: __init__.py:38 msgid "tagged items" msgstr "articoli etichettati." @@ -119,10 +115,14 @@ msgstr "Arancione" msgid "Yellow" msgstr "Giallo" -#: models.py:12 views.py:153 views.py:205 views.py:219 +#: 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" @@ -182,64 +182,64 @@ msgstr "Eticetta \"%s\" allegata con successo." msgid "attach tag to: %s" msgstr "allega etichetta a:%s" -#: views.py:129 views.py:256 +#: views.py:130 views.py:257 msgid "Must provide at least one tag." msgstr "Devi fornire almeno un'etichetta" -#: views.py:144 +#: views.py:145 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Etichetta \"%s\" cancellata con successo." -#: views.py:146 views.py:268 +#: 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:161 +#: 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:162 views.py:165 +#: views.py:163 views.py:166 msgid "Will be removed from all documents." msgstr "Sarà rimossa da tutti i documenti" -#: views.py:164 +#: 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:193 +#: views.py:194 msgid "Tag updated succesfully." msgstr "Etichetta aggiornata con successo" -#: views.py:202 +#: views.py:203 #, python-format msgid "edit tag: %s" msgstr "modifica l'etichetta:%s" -#: views.py:216 +#: views.py:217 #, python-format msgid "documents with the tag \"%s\"" msgstr "documenti con l'etichetta \"%s\"" -#: views.py:235 +#: views.py:236 #, python-format msgid "tags for: %s" msgstr "etichette per: %s" -#: views.py:266 +#: views.py:267 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Etichetta \"%s\" rimossa con successo." -#: views.py:282 +#: 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:284 +#: 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 ?" diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.mo b/apps/tags/locale/pt/LC_MESSAGES/django.mo index 992d243914f4ba7cbe184e0cb3bbf1c4211edb88..e9fb23cfaf1cae2d9cf86b988b2ce8d8faa0b505 100644 GIT binary patch delta 1011 zcmYk)O-NKx7{>9}?oF@Fr1_nV_Z)(ggfz+a}Ishw*?w| zd9jE*_Jp5p_!L|4IWniMU=zM`@4q0At?`qaO7`*RqHy;tQll*L4dI;*yKkaD;e(-D{p{)WT;`2RM%%c+tgW zEcerKlSU37;dXrQ27JXB@poix`;7zW)2RhAsQw)4WTU7nD538794fOnoK|# zqu;O)4IM=dJc->ngWQA-MI|rOk)@?iDns2()zbT-iq}@$ zPfMkXstoA+(7`r~vYp-xP`5A~z48)8U97e|NYzgMFQk7XeTVrp%05sQBaSj5Gl4i$rgwxNn3Dhb89 zbPyy+P!x4h3vO9-5ClOTbSWL$#YqudiwNT2_gCM(+Se0-wcWdK zlst7i^;N*^C>{=SqMY!|5_l2^@f;4}yo+DE_&ah~qQ#8Ex|}^2C+{r+=$Px2NzH;_=K(a1vSSd+=k1T##Pk)32u^k)B;Xp7nYq>^cde7 zH2UaxgdFyc(w(!X#>ltq!X*shIK~*? z&eGV77f}yfN4?;Vi|0{W*uWLi^8)*cXW6D4KF5Q&?BY1HKR|p0^`2{}fp4G|QpFCO z!yNb^|3Bj-%WbD4jrvIPn8Xt5h38Qdn?c=o6T9&)k`dci&jm9bL$vhtAaw^- zLucwU!Nl->S}L7XrB2_;0Cl}6jl0(a)Z(-CH^J1f{!2}H4^=Z!QLa=-&)PojMeVy! zRq1Pny~PdT%H_%xe|mDN++1nR1VY)opDPq|BlT#=UkeTubEC~d=#&?lu1uBv3zL4c I8Vv^i0q{9l?f?J) diff --git a/apps/tags/locale/pt/LC_MESSAGES/django.po b/apps/tags/locale/pt/LC_MESSAGES/django.po index c0b69116a7..9cb59e63b0 100644 --- a/apps/tags/locale/pt/LC_MESSAGES/django.po +++ b/apps/tags/locale/pt/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:19+0000\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" @@ -18,51 +18,47 @@ msgstr "" "Language: pt\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: __init__.py:21 +#: __init__.py:20 msgid "tag list" msgstr "lista de etiquetas" -#: __init__.py:22 +#: __init__.py:21 msgid "create new tag" msgstr "criar nova etiqueta" -#: __init__.py:23 +#: __init__.py:22 msgid "attach tag" msgstr "anexar etiqueta" -#: __init__.py:24 __init__.py:25 +#: __init__.py:23 __init__.py:24 msgid "remove" msgstr "remover" -#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 +#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98 msgid "tags" msgstr "Etiquetas" -#: __init__.py:27 __init__.py:30 +#: __init__.py:26 __init__.py:29 msgid "delete" msgstr "excluir" -#: __init__.py:28 +#: __init__.py:27 msgid "edit" msgstr "editar" -#: __init__.py:29 +#: __init__.py:28 msgid "tagged documents" msgstr "documentos etiquetados" -#: __init__.py:31 +#: __init__.py:30 msgid "ACLs" msgstr "" -#: __init__.py:35 models.py:13 -msgid "color" -msgstr "cor" +#: __init__.py:34 +msgid "preview" +msgstr "" -#: __init__.py:39 -msgid "color name" -msgstr "nome da cor" - -#: __init__.py:43 +#: __init__.py:38 msgid "tagged items" msgstr "itens marcados" @@ -118,10 +114,14 @@ msgstr "Laranja" msgid "Yellow" msgstr "Amarelo" -#: models.py:12 views.py:153 views.py:205 views.py:219 +#: models.py:12 views.py:154 views.py:206 views.py:220 msgid "tag" msgstr "etiqueta" +#: models.py:13 +msgid "color" +msgstr "cor" + #: models.py:16 msgid "tag properties" msgstr "propriedades de etiqueta" @@ -181,64 +181,64 @@ msgstr "Etiqueta \"%s\" anexada com sucesso." msgid "attach tag to: %s" msgstr "anexar etiqueta a: %s" -#: views.py:129 views.py:256 +#: views.py:130 views.py:257 msgid "Must provide at least one tag." msgstr "Deve fornecer pelo menos uma etiqueta." -#: views.py:144 +#: views.py:145 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Etiqueta \"%s\" removida com sucesso." -#: views.py:146 views.py:268 +#: 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:161 +#: 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:162 views.py:165 +#: views.py:163 views.py:166 msgid "Will be removed from all documents." msgstr "Será removido de todos os documentos." -#: views.py:164 +#: 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:193 +#: views.py:194 msgid "Tag updated succesfully." msgstr "Etiqueta atualizada com sucesso." -#: views.py:202 +#: views.py:203 #, python-format msgid "edit tag: %s" msgstr "editar etiqueta: %s" -#: views.py:216 +#: views.py:217 #, python-format msgid "documents with the tag \"%s\"" msgstr "documentos com a etiqueta \"%s\"" -#: views.py:235 +#: views.py:236 #, python-format msgid "tags for: %s" msgstr "etiquetas para: %s" -#: views.py:266 +#: views.py:267 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Etiqueta \"%s\" removida com sucesso." -#: views.py:282 +#: 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:284 +#: 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 b520139771cceb0421833a330ddeb6482a000c2b..0a0bc49abca6303b1ee385ef2619871fb03d989f 100644 GIT binary patch delta 1433 zcmXxjTS!zv9LMoFwrlH}m#och>QO80qUD;a85DM*J3&Ph5hb}@pt5iyl3>lC5W2xJ zhiavMhMoDGIWs$#|D1VU^`ScXsVs2S zkYePS+tkA3Q{Uy3_mkWF$r(s0?c3oe)H>*;8=YHPUZbEq{$2*KXb`<5KE|E zN7|F-HV=io7{MBRj0N}!>+m~Hz|#D&fhth#wKyIduo7EP6K+F(W+#RAuotIe7gk{s z)qlt{X-t*}?d&6Ji@l{ekoK0?x6Z*lRR+ayc;kd|0l-xl6Iw}4@*hA8c$Z(b!Go29glxwy@{Hs z>*)9#yflT9sk~@wVcMKNX7+Ck(e-w>5a*KhH7gnlS(IEs*3D4TaVS-f;g#BvcBvy< zM4m@(AnVpBy1Ld%jbnIagpvp}nkF9fH7o2kc>!5TVb--&QfN)b%8fnF+Q7@H9f?He zzJqq6^FWWC=(fAM_nkNrKbq)q%7XRb_~CdW?zK5>!P%j%LkX{v-WBYy^0yy~pR^Os zwfwE=-}!T`P*c=yYH5!ya_U01S6R{?ZBB0vow5R&E&ZZkhZP&j^|_;NhVqg7%pJ}3 z=Puap6ZcWB-_5wAwwtlthi;Y*XZ6;7%KQ876Q`oE)4J2^Wq3tO#}^QO2u&mB!a eDEwtj8FI6^GxW|f7{mHQIyZ{Wr~*RGZ5ZLVfBp<^b+l&y8}}Z%h$(V>6z>FphieS+D&CxlB>O7%o%lS&8|y>rlT(u?E|* z-k5|r&O;6_t|6D1;FgJ#7{rHIiBC`+EZ_!QM9uLnmg9S@!e6NGi}*;|r~r;&DaJfU z(a-p1l80J;xQ|@s1-C4Gi3Ruu>C=4n-hanD+P}TFpIP!~^05MoQ4_UMfwg+SccLcT zgBjS1d5mxRdDw`jQGd9E>R`-kkE2pJiJ^7IOre%wfi(5tisyc2-9`JB=Q~s&mD#HU zHsB`OHg3l*Oem5#4^bS!PE2AM{z1*OfLWDbIToUgZFmqB`Kb4P4AtLVY{4nip8DYV z7qvtsx$fGV)?D(hwHx4t*6Ips#`kbHK0^LuKA|%71NHqs)WpgdO)0OzI^2tz_$lNv zBiy#(P1OIAxC0ka{jDhf8ZbzH6=5N&!$z#fL#PhosPAs0GVlQPT@pDkW+zpVswg8W z8qhmLhD5qcs_4U1ZNz5kR;|AxZ=!0~Z>FkfkX`Q6>ckYC2Gpe1N`wbRvsSdGmeym%IfP4AB|lc zIzKcV4|fh;h;@W)D`JN&U7<)@N2EQqoN?Kg>d!jnbG~K|I45&jQgb;!ea>RuNJV-+ eJ)M4*PI8}5&!%TWOV?@4EL}}cr@HeeeE$I*t%IZh diff --git a/apps/tags/locale/ru/LC_MESSAGES/django.po b/apps/tags/locale/ru/LC_MESSAGES/django.po index 06e294b4da..a51cbebc53 100644 --- a/apps/tags/locale/ru/LC_MESSAGES/django.po +++ b/apps/tags/locale/ru/LC_MESSAGES/django.po @@ -3,12 +3,13 @@ # 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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" -"PO-Revision-Date: 2012-02-02 18:19+0000\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: Russian (http://www.transifex.net/projects/p/mayan-edms/team/ru/)\n" "MIME-Version: 1.0\n" @@ -17,51 +18,47 @@ 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:21 +#: __init__.py:20 msgid "tag list" msgstr "список меток" -#: __init__.py:22 +#: __init__.py:21 msgid "create new tag" msgstr "создать новую метку" -#: __init__.py:23 +#: __init__.py:22 msgid "attach tag" msgstr "пометить" -#: __init__.py:24 __init__.py:25 +#: __init__.py:23 __init__.py:24 msgid "remove" msgstr "удаление" -#: __init__.py:26 __init__.py:49 __init__.py:57 views.py:98 +#: __init__.py:25 __init__.py:44 __init__.py:52 views.py:98 msgid "tags" msgstr "метки" -#: __init__.py:27 __init__.py:30 +#: __init__.py:26 __init__.py:29 msgid "delete" msgstr "удалить" -#: __init__.py:28 +#: __init__.py:27 msgid "edit" msgstr "редактировать" -#: __init__.py:29 +#: __init__.py:28 msgid "tagged documents" msgstr "помеченные документы" -#: __init__.py:31 +#: __init__.py:30 msgid "ACLs" +msgstr "ACLs" + +#: __init__.py:34 +msgid "preview" msgstr "" -#: __init__.py:35 models.py:13 -msgid "color" -msgstr "цвет" - -#: __init__.py:39 -msgid "color name" -msgstr "название цвета" - -#: __init__.py:43 +#: __init__.py:38 msgid "tagged items" msgstr "помеченные элементы" @@ -117,10 +114,14 @@ msgstr "Оранжевый" msgid "Yellow" msgstr "Желтый" -#: models.py:12 views.py:153 views.py:205 views.py:219 +#: models.py:12 views.py:154 views.py:206 views.py:220 msgid "tag" msgstr "метка" +#: models.py:13 +msgid "color" +msgstr "цвет" + #: models.py:16 msgid "tag properties" msgstr "свойства метки" @@ -135,19 +136,19 @@ msgstr "Создание новых меток" #: permissions.py:10 msgid "Delete tags" -msgstr "" +msgstr "Удалить метки" #: permissions.py:11 msgid "Edit tags" -msgstr "" +msgstr "Редактировать метки" #: permissions.py:12 msgid "View tags" -msgstr "" +msgstr "Посмотреть метки" #: permissions.py:13 msgid "Attach tags to documents" -msgstr "" +msgstr "Прикрепить метки к документам" #: permissions.py:14 msgid "Remove tags from documents" @@ -180,64 +181,64 @@ msgstr "Помечено как \"%s\"" msgid "attach tag to: %s" msgstr "пометить как %s" -#: views.py:129 views.py:256 +#: views.py:130 views.py:257 msgid "Must provide at least one tag." msgstr "Должна быть хотя бы одна метка." -#: views.py:144 +#: views.py:145 #, python-format msgid "Tag \"%s\" deleted successfully." msgstr "Метка \"%s\"удалён." -#: views.py:146 views.py:268 +#: views.py:147 views.py:269 #, python-format msgid "Error deleting tag \"%(tag)s\": %(error)s" msgstr "Ошибка при удалении метки \"%(tag)s\": %(error)s" -#: views.py:161 +#: views.py:162 #, python-format msgid "Are you sure you wish to delete the tag: %s?" msgstr "Вы действительно хотите удалить метку: %s?" -#: views.py:162 views.py:165 +#: views.py:163 views.py:166 msgid "Will be removed from all documents." msgstr "Будет удален из всех документов." -#: views.py:164 +#: views.py:165 #, python-format msgid "Are you sure you wish to delete the tags: %s?" msgstr "Вы действительно хотите удалить метки: %s?" -#: views.py:193 +#: views.py:194 msgid "Tag updated succesfully." msgstr "Метка обновлена." -#: views.py:202 +#: views.py:203 #, python-format msgid "edit tag: %s" msgstr "редактировать метку %s" -#: views.py:216 +#: views.py:217 #, python-format msgid "documents with the tag \"%s\"" msgstr "документы с тегом \"%s\"" -#: views.py:235 +#: views.py:236 #, python-format msgid "tags for: %s" msgstr "теги для:%s" -#: views.py:266 +#: views.py:267 #, python-format msgid "Tag \"%s\" removed successfully." msgstr "Метка \"%s\" удалена." -#: views.py:282 +#: views.py:283 #, python-format msgid "Are you sure you wish to remove the tag: %s?" msgstr "Вы действительно хотите снять метку: %s?" -#: views.py:284 +#: views.py:285 #, python-format msgid "Are you sure you wish to remove the tags: %s?" msgstr "Вы действительно хотите снять метку: %s?" diff --git a/apps/user_management/locale/en/LC_MESSAGES/django.po b/apps/user_management/locale/en/LC_MESSAGES/django.po index 2a79d9f030..5a895404b4 100644 --- a/apps/user_management/locale/en/LC_MESSAGES/django.po +++ b/apps/user_management/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: 2012-02-02 14:17-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" diff --git a/apps/user_management/locale/es/LC_MESSAGES/django.mo b/apps/user_management/locale/es/LC_MESSAGES/django.mo index 35124521903544c855b106c546f62eade747cccf..fc5b05d0274f6262c2a7d9819accb9600f844dcf 100644 GIT binary patch delta 484 zcmXZXyGjF55P;zcl57&!m?#=A0awu|BAQ*XFxpxeygYz~L|6g}f-ET_$QC|;!gj$_ zR)R$!kRo>0S_G`bMl5W^Mmrn-Aq$7|&78|H)6QSzn@3GgehX4j z@C~(*Z=A=OK|W&%H?f8uw($%X(;}C6gId?3h`NPyc#M;Ho$-5<-E)xT;1Of^iY$3& z(}{mDj>b^$K8@6tEV5*QP2X)GJ;**r@emnST-3TA>VW5{_38zJQG#0>#|~;EFKFNw wY9qg>A7ZUqU&09PlDW9;SoT`cDFn~SuDMe_tyIeuw`jRu(C9yCMNQlI2V*)nMF0Q* delta 547 zcmXZXze_?<6u|K#Qks@!(ocgd$|ikkfg#aS5dFfUTAF%>sE|M3GiY)sf*^=$i-v+| z4uYDcrf7+VCI{R44}zAy7lq6F+;i@|=bdxrfAT-PTPoickyVF?CL*DBkudHwy}(K0 zSM0%G^q{Mw5s%^^@iY$M2KHm2nLoh@@m*hffM~Lg_ zMr&uIksh2NUc?|4aRzVDz#0~Dy-VZ}Ur^Ouponr0$MGD!`0TDUCix`MN8$%t(bC=c zu^rXKgJ{Pfs`DsPTV|0ZaX#u^0_j2au?3Hjq2(0SyDLS__#cBZnv-Kxl~zCaV2Ry)|?UBKVvFO A;s5{u diff --git a/apps/user_management/locale/es/LC_MESSAGES/django.po b/apps/user_management/locale/es/LC_MESSAGES/django.po index ffca035a57..031b6e4bf2 100644 --- a/apps/user_management/locale/es/LC_MESSAGES/django.po +++ b/apps/user_management/locale/es/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2012-02-02 18:30+0000\n" "Last-Translator: Roberto Rosario \n" -"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mayan-edms/team/es/)\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:13 @@ -123,8 +124,8 @@ msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." msgstr "" -"No se permite editar el super usuario y usuario de personal, use la interfaz" -" de administración para estos casos." +"No se permite editar el super usuario y usuario de personal, use la interfaz " +"de administración para estos casos." #: views.py:68 #, python-format @@ -262,5 +263,3 @@ msgstr "no miembros del grupo: %s" #, python-format msgid "members of group: %s" msgstr "miembros del grupo: %s" - - diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.mo b/apps/user_management/locale/it/LC_MESSAGES/django.mo index eeadde4b8c0327af1f9e13a582b93e0576a1a22b..85c3440f847cfa8a3f2d68edbe2d035ddef73276 100644 GIT binary patch delta 476 zcmXZYJxc>Y5Qp)J;t}r>HNGIC=oL8?e9eJ^QLq=$A|QfQ&=3y9N-KrKDmH?0pjc@s zSSX|u1≧Op{Kq2sR<#KoFmmfn$IBADG*nz4V&tr%Eh*jET6m$c%{89Fb}KRi_dn zv*c||VM)Ege)0nj;~RG4Ck|l?d(cXXEaM=qU=BC%0$uz{N+@YI(k1_TI7(bo1LTu4 z77wr0SDYX>a2y>@FQJde_>AYc$Squ~pgHGTwVB3TcrF!+^s!l`U?$A5SXe+a;l6r` zaq^XVi>B`$d+`N3@BS+GcK=Tq!%|B`zO#{?BC)t=M8`HuPn#N7!6=h5FZaHXg nS<#6-63_T)J!4 z$r)V)ue7h&MK(CK6XUpxv$&1Vc!2ZV!o&|$=hRY#GKMUXnNW$_GFWCpRk%gx$9+^4 zmbE8XL%!7Bq1yL=jrfAq_=OZFKdAm=@KL=)2vzRT_FxM++RZ>c*_fVK&11uUP$;Gg#^l7bHIh#|o}0^B pqmGwOnDJ;VZbelyWBrNPKzY-+EhhtWM#{-%icW?lmE*v@{}&{IOHKd) diff --git a/apps/user_management/locale/it/LC_MESSAGES/django.po b/apps/user_management/locale/it/LC_MESSAGES/django.po index 53b244cfea..21982b6118 100644 --- a/apps/user_management/locale/it/LC_MESSAGES/django.po +++ b/apps/user_management/locale/it/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # 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-02 14:17-0400\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-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" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: __init__.py:13 @@ -263,5 +264,3 @@ msgstr "non membri del gruppo: %s" #, python-format msgid "members of group: %s" msgstr "membri del gruppo: %s" - - diff --git a/apps/user_management/locale/pt/LC_MESSAGES/django.mo b/apps/user_management/locale/pt/LC_MESSAGES/django.mo index 652f660de4cdc7d4338bcdd89a8e83bb03c452f0..df9e96e88ae34989a1833d5fbea1a25a6a087961 100644 GIT binary patch delta 476 zcmXZYJxD@P6u|ML(d+e|mi9$a#50v5sC;URAhg)j&|ZsyJRFL`+=NF{qr-!sAZUx4 zLWhQ$q@f`w3L092XfSAL?|<LSM= rZnmp^T_b2%Gp3t$+|@!h6I@u2k&W`6S1)^&g0p`Zc=lHN*=`yCD$h50 delta 538 zcmXZY&nrYx6u|K_$>5D&<41@zeuc$&^O%~NvO)>@QC6%TrkPh}9`C(LN=>p-7HX{g z0hUsu*(u7xN-SAeuu^swqLlB;t=s+FbMEPM?tSjxAGo*;6rKVi5lv)7M1DddF&wTH zF>nRP@CY058k_I|Tk#D$@Ebd^xlW`Vb@bzD)Nw<3f>Xq|*o|7f6ePl7xL%|eXOvkS zAU;NBlQItCjmp2PxPhtS;^3a5m$4TS;9{TV5u=HnMJKb;ov1$FdzgYwnsk-E!T0%GDMZmZK9+ w%JeKd7o9Y{R5CIeGe)B^e?^RV(nu6{wY%bcXeBgf=F)jHP03d2EOZ(C1NBKwr2qf` diff --git a/apps/user_management/locale/pt/LC_MESSAGES/django.po b/apps/user_management/locale/pt/LC_MESSAGES/django.po index cc120cae6c..2203e31166 100644 --- a/apps/user_management/locale/pt/LC_MESSAGES/django.po +++ b/apps/user_management/locale/pt/LC_MESSAGES/django.po @@ -1,21 +1,22 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Renata Oliveira , 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-02 14:17-0400\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: Portuguese (http://www.transifex.net/projects/p/mayan-edms/team/pt/)\n" +"Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" +"team/pt/)\n" +"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 @@ -261,5 +262,3 @@ msgstr "não-membros do grupo: %s" #, python-format msgid "members of group: %s" msgstr "membros do grupo: %s" - - diff --git a/apps/user_management/locale/ru/LC_MESSAGES/django.mo b/apps/user_management/locale/ru/LC_MESSAGES/django.mo index 5aa4e055bc98d4f01114de8258e4b9861ab13b2d..d1955097eca6cc4a446bed87cb8a758595ba8d3e 100644 GIT binary patch delta 476 zcmXZYK`4W99LDiyiS%v^n_)S;OB*H4mPsq2Br-)VGO5)V4i2&#?WlH;T3orv#X*)G z9OQu0IJ&vn$xbUpF1~N?F7M}k-uLbQ`#oE{)?pj^Qo7;TM+izC(J)BabwQ>t5SD4v|Y3!B20_KG4@`H<(A3)d^Zn z&(RwAQh)x3ezM`S4-BHUz!F+T^2khGBR@}%Xcc&^=L)i$YG`8P0B^14A+$bBaOuW0 x_TynaUlz9;s!fFhqqjK{H6yWjbhvO~Ji8L9-Ap!>*@&Ba*+SZxES8-;u76v;KJWkl delta 539 zcmXZY&npCB9LMpmA35xf-@l~{@}pQ|v@K03vWXDILE6jE+MR=4&CC|3E#)Lhj;_w4 zO)fa$wCzPH#lb-?-24IFPrLOrujljh^nAbHc`&|=tH-jeUM`{sM3zKkS}S^j>*NpI zz(}=7FP>sQ-e3gZF^r8hB2k>fDLlp%EZ`h=)rzcQ5@UFWI=0tIR=U|(bs~KjLkkaZ z7VohYE9*t(u@hCnZJfk&oWM6MU_*mQ9zXFFFB?UM@UW@qHHOF^XkxHATYPY`xj2D~ zG%dHNCVfU#@V9i{(<0JAHc>sih^m1-RD)b2HRT2QdGd{FfWK1K2=pfHsN?V;8#Vb7 zvc%)lhDSJn7p0ufITb%u3rXMKwG1QS_{q%X$X0sCaMPacI%(I~vG?ti;dovq?gdts z*FrOH-1ePxDipQ-xTTMcnq#3+wRAIVnd4{sfv2;D;D)wnrxF=E!4)@?y9jn@|DWMe Al>h($ diff --git a/apps/user_management/locale/ru/LC_MESSAGES/django.po b/apps/user_management/locale/ru/LC_MESSAGES/django.po index b7b425cdfb..08a91e48ef 100644 --- a/apps/user_management/locale/ru/LC_MESSAGES/django.po +++ b/apps/user_management/locale/ru/LC_MESSAGES/django.po @@ -1,21 +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: msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" -"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" -"POT-Creation-Date: 2012-02-02 14:17-0400\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-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:13 msgid "user list" @@ -122,8 +124,8 @@ msgid "" "Super user and staff user editing is not allowed, use the admin interface " "for these cases." msgstr "" -"Редактирование суперпользователя и персонала не допускается, используйте для" -" этого интерфейс администратора." +"Редактирование суперпользователя и персонала не допускается, используйте для " +"этого интерфейс администратора." #: views.py:68 #, python-format @@ -260,5 +262,3 @@ msgstr "не входят в группу: %s" #, python-format msgid "members of group: %s" msgstr "входят в группу: %s" - - diff --git a/apps/web_theme/locale/en/LC_MESSAGES/django.po b/apps/web_theme/locale/en/LC_MESSAGES/django.po index a8daed9146..08e76067bc 100644 --- a/apps/web_theme/locale/en/LC_MESSAGES/django.po +++ b/apps/web_theme/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: 2012-02-02 14:17-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" diff --git a/apps/web_theme/locale/es/LC_MESSAGES/django.mo b/apps/web_theme/locale/es/LC_MESSAGES/django.mo index c0c6863e92b7e0a00f2e3df30fbd061aad098fa7..c2f179bf10cf13b9adb8bf705c28a660aa3a8a07 100644 GIT binary patch delta 21 ccmX@edysd7FEfXsk%FPAm65^bQ05$F07Xd!qyPW_ delta 21 ccmX@edysd7FEfXMk%FO#m7)3OQ05$F07X^>r~m)} diff --git a/apps/web_theme/locale/es/LC_MESSAGES/django.po b/apps/web_theme/locale/es/LC_MESSAGES/django.po index b9f0245104..13984eb57f 100644 --- a/apps/web_theme/locale/es/LC_MESSAGES/django.po +++ b/apps/web_theme/locale/es/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-03 21:44+0000\n" "Last-Translator: Roberto Rosario \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/" diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.mo b/apps/web_theme/locale/it/LC_MESSAGES/django.mo index ee22c2a67190fc975a02b6721dac0a3ab504da9d..989093a22a4ee86fed1b4e7c63de7c1820e4dd0a 100644 GIT binary patch delta 21 ccmZ3=yOei>FEfXsk%FPAm65^bQ04$;06?(?Pyhe` delta 21 ccmZ3=yOei>FEfXMk%FO#m7)3OQ04$;06@M4Q~&?~ diff --git a/apps/web_theme/locale/it/LC_MESSAGES/django.po b/apps/web_theme/locale/it/LC_MESSAGES/django.po index dbca29b3d1..26968a531a 100644 --- a/apps/web_theme/locale/it/LC_MESSAGES/django.po +++ b/apps/web_theme/locale/it/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-12-09 18:07+0000\n" "Last-Translator: Pierpaolo Baldan \n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" diff --git a/apps/web_theme/locale/pt/LC_MESSAGES/django.mo b/apps/web_theme/locale/pt/LC_MESSAGES/django.mo index 56d6afffc98af4edf380975a66bc245f26108784..ed5c36e7c9270b7b187e6f8ca34c73e04595e64b 100644 GIT binary patch delta 21 ccmbQiJA-$FFEfXsk%FPAm65^bP-bUl06vceDF6Tf delta 21 ccmbQiJA-$FFEfXMk%FO#m7)3OP-bUl06v@rEdT%j diff --git a/apps/web_theme/locale/pt/LC_MESSAGES/django.po b/apps/web_theme/locale/pt/LC_MESSAGES/django.po index a51db3747c..a5f21f001f 100644 --- a/apps/web_theme/locale/pt/LC_MESSAGES/django.po +++ b/apps/web_theme/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: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-04 00:46+0000\n" "Last-Translator: emersonsoares \n" "Language-Team: Portuguese (http://www.transifex.net/projects/p/mayan-edms/" diff --git a/apps/web_theme/locale/ru/LC_MESSAGES/django.mo b/apps/web_theme/locale/ru/LC_MESSAGES/django.mo index f9648438ef51d150198598fc120c19a6762fc178..bceb298da5fdc337500837b9495de7fd82eda855 100644 GIT binary patch delta 21 ccmbQpKaqcfFEfXsk%FPAm65^bP-Ytz06n$^82|tP delta 21 ccmbQpKaqcfFEfXMk%FO#m7)3OP-Ytz06oJ69RL6T diff --git a/apps/web_theme/locale/ru/LC_MESSAGES/django.po b/apps/web_theme/locale/ru/LC_MESSAGES/django.po index 63943d0479..5557684b8b 100644 --- a/apps/web_theme/locale/ru/LC_MESSAGES/django.po +++ b/apps/web_theme/locale/ru/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Mayan EDMS\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-02 14:17-0400\n" +"POT-Creation-Date: 2012-02-12 15:20-0400\n" "PO-Revision-Date: 2011-11-04 15:22+0000\n" "Last-Translator: Sergey Glita \n" "Language-Team: Russian (http://www.transifex.net/projects/p/mayan-edms/team/" From 60176ada09982a9cbe43eaa2a7b1cf8f6451b4f2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 12 Feb 2012 17:12:42 -0400 Subject: [PATCH 416/484] Documentation updates --- docs/faq/index.rst | 55 ++++++++++++-------------- docs/topics/development.rst | 51 ++++++++++++++++++++++-- docs/topics/document_visualization.rst | 11 ++++-- docs/topics/settings.rst | 34 ++++++++++------ docs/topics/smart_links.rst | 2 +- 5 files changed, 103 insertions(+), 50 deletions(-) diff --git a/docs/faq/index.rst b/docs/faq/index.rst index b695062027..f24adbae02 100644 --- a/docs/faq/index.rst +++ b/docs/faq/index.rst @@ -7,8 +7,7 @@ Frequently asked questions and solutions Database related ---------------- -Q: PostgreSQL vs. MySQL -~~~~~~~~~~~~~~~~~~~~~~~ +**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 @@ -19,8 +18,7 @@ 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 '='") -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Q: _mysql_exceptions. OperationalError: (1267, "Illegal mix of collations (latin1_swedish_ci, IMPLICIT) and (utf8_general_ci, COERCIBLE) for operation '='")** * Solution:: @@ -39,8 +37,7 @@ Q: _mysql_exceptions. OperationalError: (1267, "Illegal mix of collations (latin - http://stackoverflow.com/questions/1073295/django-character-set-with-mysql-weirdness -Q: Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row 1 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Q: Incorrect string value: ``'\xE2\x80\x95rs6...'`` for column ``'content'`` at row 1** When using ``MySQL`` and doing OCR on languages other than English @@ -54,8 +51,7 @@ When using ``MySQL`` and doing OCR on languages other than English Document sharing ---------------- -Q: File system links not showing when serving content with ``Samba`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Q: File system links not showing when serving content with ``Samba``** * Solution: @@ -81,8 +77,7 @@ Q: File system links not showing when serving content with ``Samba`` Document handling ----------------- -How to store documents outside of **Mayan EDMS's** path -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**How to store documents outside of **Mayan EDMS's** path** * Sub class Django's ``FileSystemStorage`` class: @@ -102,8 +97,7 @@ How to store documents outside of **Mayan EDMS's** path DOCUMENTS_STORAGE_BACKEND = CustomStorage -Q: How to enable the ``GridFS`` storage backend -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Q: How to enable the ``GridFS`` storage backend** * Solution: @@ -114,8 +108,7 @@ Q: How to enable the ``GridFS`` storage backend - 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? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Q: How do you upload a new version of an existing file?** * Solution: @@ -125,20 +118,21 @@ Q: How do you upload a new version of an existing file? 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 -~~~~~~~~~~~~~~~~~~~~~~ +**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`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Q: How to enable x-sendile support for ``Apache``** * If using Ubuntu execute the following:: @@ -157,8 +151,7 @@ Q: How to enable x-sendile support for ``Apache`` OCR --- -Q: The included version of ``unoconv`` in my distribution is too old -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**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 @@ -166,12 +159,16 @@ Q: The included version of ``unoconv`` in my distribution is too old 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? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**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. @@ -182,8 +179,7 @@ Q: Is virtualenv required as specified in the documentation? Mayan to stop working for no apparent reason. -Q: Mayan EDMS installed correctly and works, but static files are not served -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**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 @@ -201,8 +197,7 @@ Other ----- -Q: How to connect Mayan EDMS to an Active Directory tree -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**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. @@ -249,8 +244,10 @@ 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? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**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/topics/development.rst b/docs/topics/development.rst index b55371ac69..8521d397af 100644 --- a/docs/topics/development.rst +++ b/docs/topics/development.rst @@ -51,9 +51,9 @@ To familiarize yourself with the technical details of the project read the :ref: .. _docs: ------------------ +------------- Documentation ------------------ +------------- The documentation is written in `reStructured Text`_ format. @@ -74,8 +74,51 @@ You can also generate the documentation in format other than HTML. .. _Sphinx: http://sphinx.pocoo.org ---------------- +------------ 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. + +--------- +Debugging +--------- + +**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:: + + 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', + }, + } + } + +.. _`logging capabilities`: https://docs.djangoproject.com/en/dev/topics/logging diff --git a/docs/topics/document_visualization.rst b/docs/topics/document_visualization.rst index daa9cead49..cfedc23ad3 100644 --- a/docs/topics/document_visualization.rst +++ b/docs/topics/document_visualization.rst @@ -7,8 +7,9 @@ The philosophy in place is to try to avoid having users download a documents and **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 for conversion to PDF_. The PDF_ is stored in a temporary +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 @@ -17,7 +18,7 @@ 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 rotate interactively +(thumbnail, page preview, full preview) and rotated interactively in the details view. @@ -31,4 +32,6 @@ before they can be previewed and text can be extracted. .. _PDF: http://en.wikipedia.org/wiki/Portable_Document_Format -.. _Libreoffice: http://www.libreoffice.org/ +.. _LibreOffice: http://www.libreoffice.org/ +.. _unoconv: https://github.com/dagwieers/unoconv/ +.. _supervisor: http://supervisord.org/introduction.html diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst index a57beb99b5..5d17d1779e 100644 --- a/docs/topics/settings.rst +++ b/docs/topics/settings.rst @@ -129,7 +129,29 @@ The path where the visual representations of the documents are stored for fast d 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** @@ -170,18 +192,6 @@ fine tune it's functionality as explained in the `GraphicsMagick documentation`_ .. _GraphicsMagick documentation: http://www.graphicsmagick.org/convert.html#conv-opti - -.. setting:: CONVERTER_GRAPHICS_BACKEND - -**CONVERTER_GRAPHICS_BACKEND** - -Default: ``converter.backends.python`` - -Graphics conversion backend to use. Options are: - -* ``converter.backends.imagemagick`` - Wrapper for ImageMagick -* ``converter.backends.graphicsmagick`` - Wrapper for GraphicsMagick -* ``converter.backends.python`` - Wrapper for Pillow and Ghostscript .. setting:: CONVERTER_UNOCONV_PATH diff --git a/docs/topics/smart_links.rst b/docs/topics/smart_links.rst index ea2559e965..07db50a9d0 100644 --- a/docs/topics/smart_links.rst +++ b/docs/topics/smart_links.rst @@ -4,6 +4,6 @@ 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 currently +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. From cc3525366cc402a53f3132b2dd3a7ddf5bdb2e55 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 13 Feb 2012 02:13:48 -0400 Subject: [PATCH 417/484] Add Michael Terretta to the contributors file --- docs/credits/contributors.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/credits/contributors.rst b/docs/credits/contributors.rst index afe08d3d1d..6d099fd964 100644 --- a/docs/credits/contributors.rst +++ b/docs/credits/contributors.rst @@ -67,9 +67,11 @@ 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 From a9cd2141b0812a2303dd2ab650e3d5d4593c3b1d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 14:24:40 -0400 Subject: [PATCH 418/484] Add Gname news server to the help section of the documentation --- docs/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index aa13b55563..a28c4f98f6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -83,10 +83,11 @@ 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`_. + `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 From d0ba46ecde227da8099a8b7df00dde517c5f322d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 14:25:18 -0400 Subject: [PATCH 419/484] Remove commented default settings Too hard to maintain, users should use the documentation instead and them by hand --- settings.py | 90 +---------------------------------------------------- 1 file changed, 1 insertion(+), 89 deletions(-) diff --git a/settings.py b/settings.py index 7fed78bde0..4b0bd90460 100644 --- a/settings.py +++ b/settings.py @@ -146,7 +146,7 @@ INSTALLED_APPS = ( 'web_theme', # pagination needs to go after web_theme so that the pagination template # if found - 'pagination', + 'pagination', 'common', 'django_gpg', 'dynamic_search', @@ -195,95 +195,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' -#======== End of user configuration options ======= #--------- Web theme --------------- WEB_THEME_ENABLE_SCROLL_JS = False #--------- Django ------------------- From bd4e97b857915a13f7cdb9fbcc01e5c7f362bd1e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 14:26:25 -0400 Subject: [PATCH 420/484] Rename delete_detached_signature to delete_detached_signature_file which is more appropiate --- apps/document_signatures/managers.py | 2 +- apps/document_signatures/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index af967f30ca..af546ac520 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -24,7 +24,7 @@ class DocumentVersionSignatureManager(models.Manager): else: if document_signature.signature_file: logger.debug('Existing detached signature') - document_signature.delete_detached_signature() + document_signature.delete_detached_signature_file() document_signature.signature_file = None document_signature.save() diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index 7ae215f675..e63b5a0396 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -23,7 +23,7 @@ class DocumentVersionSignature(models.Model): objects = DocumentVersionSignatureManager() - def delete_detached_signature(self): + def delete_detached_signature_file(self): self.signature_file.storage.delete(self.signature_file.path) def save(self, *args, **kwargs): From ff52506b24572ac1ea110abf7505dc084932a2d4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 14:26:58 -0400 Subject: [PATCH 421/484] Plug a possible descriptor leak --- apps/document_signatures/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/document_signatures/models.py b/apps/document_signatures/models.py index e63b5a0396..970826e709 100644 --- a/apps/document_signatures/models.py +++ b/apps/document_signatures/models.py @@ -28,7 +28,9 @@ class DocumentVersionSignature(models.Model): def save(self, *args, **kwargs): if not self.pk: - self.has_embedded_signature = gpg.has_embedded_signature(self.document_version.open(raw=True)) + descriptor = self.document_version.open(raw=True) + self.has_embedded_signature = gpg.has_embedded_signature(descriptor) + descriptor.close() super(DocumentVersionSignature, self).save(*args, **kwargs) class Meta: From 6de85b967004c3d87af581ab7d3323086bcc1251 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 14:40:48 -0400 Subject: [PATCH 422/484] Don't pass the detached_signature descriptor, but clone it to avoid being closed, don't close file descriptors leave it up to caller to do so. --- apps/django_gpg/api.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 7071135af6..38e60fde76 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -4,6 +4,11 @@ import logging import tempfile import os +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + from django.utils.translation import ugettext_lazy as _ from hkp import KeyServer @@ -174,7 +179,7 @@ class GPG(object): self.gpg = gnupg.GPG(**kwargs) - def verify_file(self, file_input, detached_signature=None, close_descriptor=True, fetch_key=False): + def verify_file(self, file_input, detached_signature=None, fetch_key=False): """ Verify the signature of a file. """ @@ -185,36 +190,34 @@ class GPG(object): # Save the original data and invert the argument order # Signature first, file second file_descriptor, filename = tempfile.mkstemp(prefix='django_gpg') - file_data = input_descriptor.read() - file_input.close() - os.write(file_descriptor, file_data) + os.write(file_descriptor, input_descriptor.read()) os.close(file_descriptor) - verify = self.gpg.verify_file(detached_signature, data_filename=filename) + + detached_signature = GPG.get_descriptor(detached_signature) + signature_file = StringIO() + signature_file.write(detached_signature.read()) + signature_file.seek(0) + verify = self.gpg.verify_file(signature_file, data_filename=filename) + signature_file.close() else: verify = self.gpg.verify_file(input_descriptor) logger.debug('verify.status: %s' % getattr(verify, 'status', None)) if verify: logger.debug('verify ok') - if close_descriptor: - input_descriptor.close() return verify elif getattr(verify, 'status', None) == 'no public key': # Exception to the rule, to be able to query the keyservers if fetch_key: try: self.receive_key(verify.key_id) - return self.verify_file(input_descriptor, detached_signature, close_descriptor, fetch_key=False) + return self.verify_file(input_descriptor, detached_signature, fetch_key=False) except KeyFetchingError: - if close_descriptor: - input_descriptor.close() return verify else: return verify else: logger.debug('No verify') - if close_descriptor: - input_descriptor.close() raise GPGVerificationError() def verify(self, data): From 90112bb9bbdc3b44876124654ccc82c1f478b0d0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 14:41:44 -0400 Subject: [PATCH 423/484] Explicitly close descriptors after verifying a file's signatures --- apps/document_signatures/managers.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index af546ac520..1a20aabe7e 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -52,13 +52,20 @@ class DocumentVersionSignatureManager(models.Manager): return document_signature.signature_file.storage.open(document_signature.signature_file.path) def verify_signature(self, document): + document_descriptor = document.open(raw=True) + detached_signature = None if self.has_detached_signature(document): logger.debug('has detached signature') - args = (document.open(raw=True), self.detached_signature(document)) + detached_signature = self.detached_signature(document) + args = (document_descriptor, detached_signature) else: - args = (document.open(raw=True),) + args = (document_descriptor,) try: return gpg.verify_file(*args, fetch_key=True) except GPGVerificationError: return None + finally: + document_descriptor.close() + if detached_signature: + detached_signature.close() From 00e467949fb3cf53f2d748b0b3b59fdeb0e6c642 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 15:59:44 -0400 Subject: [PATCH 424/484] Update metadata and indexes after document is fully created --- apps/sources/models.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 617c90e77a..717b89ddb0 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -90,6 +90,8 @@ class BaseModel(models.Model): @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: @@ -98,10 +100,6 @@ class BaseModel(models.Model): apply_default_acls(document, user) - if metadata_dict_list: - save_metadata_list(metadata_dict_list, document, create=True) - warnings = update_indexes(document) - if user: document.add_as_recent_document_for_user(user) create_history(HISTORY_DOCUMENT_CREATED, document, {'user': user}) @@ -132,6 +130,11 @@ class BaseModel(models.Model): 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',) From 614906e6f6d43fe2fd739ab70cfa9195a40c821c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 16:17:12 -0400 Subject: [PATCH 425/484] Add document and document version filename rename model method --- apps/documents/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/documents/models.py b/apps/documents/models.py index 4d7136659a..6d5d7d21d3 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -263,6 +263,10 @@ class Document(models.Model): def versions(self): return self.documentversion_set + def rename(self, new_name): + version = self.latest_version + return version.rename(new_name) + def _get_filename(self): return self.latest_version.filename @@ -514,6 +518,11 @@ class DocumentVersion(models.Model): return self.file.storage.size(self.file.path) else: return None + + def rename(self, new_name): + name, extension = os.path.splitext(self.filename) + self.filename = u''.join([new_name, extension]) + self.save() class DocumentTypeFilename(models.Model): From 9f60cffd0a41cf6fd505d76b5f4607adcc76d65b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 16:35:14 -0400 Subject: [PATCH 426/484] Use the Document model rename method --- apps/sources/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/sources/models.py b/apps/sources/models.py index 717b89ddb0..f421fac7c2 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -123,8 +123,7 @@ class BaseModel(models.Model): raise if filename: - new_version.filename = filename - new_version.save() + document.rename(filename) transformations, errors = self.get_transformation_list() From f78b09229c8d660542288870624ceb6b318388b0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 16:35:39 -0400 Subject: [PATCH 427/484] Fallback to a page count of 1 when slate raise an Exception --- apps/converter/backends/python/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/converter/backends/python/base.py b/apps/converter/backends/python/base.py index dddfa71e7e..c7a96a216d 100644 --- a/apps/converter/backends/python/base.py +++ b/apps/converter/backends/python/base.py @@ -30,7 +30,10 @@ class ConverterClass(ConverterBase): # If file is a PDF open it with slate to determine the page # count with open(input_filepath) as fd: - pages = slate.PDF(fd) + try: + pages = slate.PDF(fd) + except: + return 1 return len(pages) try: From ffb155366a0e3e1535adb86b4824938bee4fb64b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 16:36:59 -0400 Subject: [PATCH 428/484] Add TODO comment for future consideration --- apps/converter/backends/python/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/converter/backends/python/base.py b/apps/converter/backends/python/base.py index c7a96a216d..33fda08171 100644 --- a/apps/converter/backends/python/base.py +++ b/apps/converter/backends/python/base.py @@ -34,6 +34,7 @@ class ConverterClass(ConverterBase): pages = slate.PDF(fd) except: return 1 + # TODO: Maybe return UnknownFileFormat to display proper unknwon file format message in document description return len(pages) try: From 71f9a3171f22025e003e67042cba5de3e2df8ba5 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 23:46:42 -0400 Subject: [PATCH 429/484] Display staging file filename as a title when during preview, treat all staging files as a gallery --- apps/main/templates/base.html | 10 ++++++++++ apps/sources/widgets.py | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index 101caed080..311d930dc8 100644 --- a/apps/main/templates/base.html +++ b/apps/main/templates/base.html @@ -139,6 +139,16 @@ 'type' : 'image', 'autoScale' : true }); + + $("a.fancybox-staging").fancybox({ + 'titleShow' : true, + 'transitionIn' : 'elastic', + 'transitionOut' : 'elastic', + 'easingIn' : 'easeOutBack', + 'easingOut' : 'easeInBack', + 'type' : 'image', + 'autoScale' : true + }); $("a.fancybox-noscaling").fancybox({ 'titleShow' : false, 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'%(string)s' + template = u'%(string)s' except: template = u'%(string)s' @@ -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 }) From 6eca8b66994280c9a1a8bfc641a09999858d4f62 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 23:55:47 -0400 Subject: [PATCH 430/484] Make staging source preview width a required field --- apps/sources/migrations/0001_initial.py | 156 ++++++++++++++++++ .../migrations/0002_preview_width_required.py | 84 ++++++++++ apps/sources/migrations/__init__.py | 0 apps/sources/models.py | 2 +- 4 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 apps/sources/migrations/0001_initial.py create mode 100644 apps/sources/migrations/0002_preview_width_required.py create mode 100644 apps/sources/migrations/__init__.py 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 f421fac7c2..ad20758bff 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -158,7 +158,7 @@ class StagingFolder(InteractiveBaseModel): 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.')) From 0c1da1b0c292e941988794cd65218f1e5d4fa7b6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 14 Feb 2012 23:56:13 -0400 Subject: [PATCH 431/484] Add sources app migration instructions for the release notes --- docs/releases/0.12.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 93b2926a32..b670123691 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -182,6 +182,8 @@ And continue migrating database schema with:: $ ./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 :: From 31c6cc3142ebcc7eb8bbac616c90f52290577c28 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 15 Feb 2012 00:00:49 -0400 Subject: [PATCH 432/484] Move extra requirements upgrade step to the start, add staging file preview updates --- docs/releases/0.12.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index b670123691..1f3563a4b2 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -145,14 +145,27 @@ 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 as the title 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 creating the new database structures with:: +Start off by adding the new requirements:: + + $ pip install -r requirements/production.txt + +Then create the new database structures with:: $ ./manage.py syncdb -Then migrate existing database schema with:: +Afterwards migrate existing database schema with:: $ ./manage.py migrate permissions 0001 --fake $ ./manage.py migrate permissions @@ -200,12 +213,9 @@ Again when a similar messages appears Type ``yes`` and press **Enter** -Add the new requirements:: - - $ pip install -r requirements/production.txt - The upgrade procedure is now complete. + Backward incompatible changes ============================= The permission system has been completely reworked so sadly this is a From d0cdb44e2dd767a04f324f24d803cc973d34381b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 15 Feb 2012 01:44:54 -0400 Subject: [PATCH 433/484] Add clear_detached_signature manager method --- apps/document_signatures/managers.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index 1a20aabe7e..e812f1935f 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -69,3 +69,12 @@ class DocumentVersionSignatureManager(models.Manager): document_descriptor.close() if detached_signature: detached_signature.close() + + def clear_detached_signature(self, document): + document_signature = self.get_document_signature(document) + if not document_signature.signature_file: + raise Exception('document doesn\'t have a detached signature') + + document_signature.delete_detached_signature_file() + document_signature.signature_file = None + document_signature.save() From 57730bcfbe7749cb346abec32681e487aa05eb38 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 18 Feb 2012 04:12:38 -0400 Subject: [PATCH 434/484] Add versioning chapter and diagram --- docs/figure_src/versioning.svg | 211 +++++++++++++++++++++++++++++++++ docs/topics/versioning.png | Bin 0 -> 14432 bytes docs/topics/versioning.rst | 25 ++++ 3 files changed, 236 insertions(+) create mode 100644 docs/figure_src/versioning.svg create mode 100644 docs/topics/versioning.png create mode 100644 docs/topics/versioning.rst diff --git a/docs/figure_src/versioning.svg b/docs/figure_src/versioning.svg new file mode 100644 index 0000000000..e5e64cf1f0 --- /dev/null +++ b/docs/figure_src/versioning.svg @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Original version: 1.0.0 + + New major version: 2.0.0 + + New minor version: 1.1.0 + + New micro version: 1.0.1 + + + + diff --git a/docs/topics/versioning.png b/docs/topics/versioning.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec2f24d866d076175fb71358001441a72c8f185 GIT binary patch literal 14432 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 nj4&rCSeX@~l>crhkq-wH2gpU`Vp0(sH@K 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 W8n{^y2%H8af!#5@{pF@z Date: Sat, 18 Feb 2012 04:12:59 -0400 Subject: [PATCH 435/484] Moved bulk document and user import to a separate chapter --- docs/releases/0.12.rst | 44 ++++++++++--------------------- docs/topics/initial_import.rst | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 docs/topics/initial_import.rst diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst index 1f3563a4b2..68dba8a8ea 100644 --- a/docs/releases/0.12.rst +++ b/docs/releases/0.12.rst @@ -46,6 +46,10 @@ 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 @@ -83,52 +87,32 @@ the download of several documents in a single compressed file. Customizable GPG home directory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Addition of the SIGNATURES_GPG_HOME configuration option to let +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. The command line options for this feature are as -follow:: +from a compressed file. For information about this new feature check the +:doc:`Initial data loading <../topics/initial_import>` chapter. - $ ./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. Out of process user import ~~~~~~~~~~~~~~~~~~~~~~~~~~ A management command has been added to import a large number users -from a CSV file. The command line options for this feature are as -follow:: +from a CSV file. More information about this new feature can also be found +in the :doc:`Initial data loading <../topics/initial_import>` chapter. - $ ./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. Refactored document indexing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The document indexing functionality has been improved and moved from experimental +: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 a skeleton tree that will +``Setup`` menu and allows administrators to create skeleton trees that will be populated with document links depending on their metadata and properties. -This populated tree can also be mirrored on the physical filesystem and shared +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 @@ -147,7 +131,7 @@ the need of the **Mayan EDMS** user base. Staging file previews ~~~~~~~~~~~~~~~~~~~~~ -The staging file previews now show the filename as the title for easier +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 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. From 03cdea8920b7b3cb1b8079e4b0e3039cf97ea279 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 18 Feb 2012 04:13:32 -0400 Subject: [PATCH 436/484] Add document signatures chapter --- docs/topics/index.rst | 11 +++++++---- docs/topics/signatures.rst | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 docs/topics/signatures.rst diff --git a/docs/topics/index.rst b/docs/topics/index.rst index 2d297d1745..a97ff7d101 100644 --- a/docs/topics/index.rst +++ b/docs/topics/index.rst @@ -6,10 +6,13 @@ 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 - permissions - document_visualization ocr - file_storage - transformations 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. From d51a5590f89fcbbb4305f753ccbcdf3c0ab1ea6c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 18 Feb 2012 04:13:49 -0400 Subject: [PATCH 437/484] Updated documentation index --- docs/index.rst | 13 ++++++++----- docs/releases/index.rst | 9 +++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index a28c4f98f6..b13a2291a4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,13 +38,16 @@ First steps 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:`Permission system ` | - :doc:`Document visualization ` | - :doc:`OCR ` | - :doc:`File storage ` | - :doc:`Transformations ` + :doc:`OCR ` Between versions diff --git a/docs/releases/index.rst b/docs/releases/index.rst index bd3fc2ddd6..3bbee2aa57 100644 --- a/docs/releases/index.rst +++ b/docs/releases/index.rst @@ -11,18 +11,15 @@ 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. -Final releases -============== - -0.12 release ------------- +Latest version (0.12) +--------------------- .. toctree:: :maxdepth: 1 0.12 Historic changelogs -=================== +------------------- .. toctree:: :maxdepth: 1 From a510cfe6d0db946da9b81d0a188e8252a6e27bb4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 18 Feb 2012 04:19:56 -0400 Subject: [PATCH 438/484] Link features to the actual chapter where they are discussed --- docs/intro/features.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/intro/features.rst b/docs/intro/features.rst index 43e9bfa267..71d19c1dd9 100644 --- a/docs/intro/features.rst +++ b/docs/intro/features.rst @@ -2,11 +2,11 @@ Features ======== -* Document versioning. +* :doc:`Document versioning <../topics/versioning>`. * Store many versions of the same document, download or revert to a previous version. -* Electronic signature verification. +* :doc:`Electronic signature verification <../topics/signatures>`. * Check the authenticity of documents by verifying their embedded cryptographic signatures or upload detached signatures for document @@ -56,11 +56,11 @@ Features * Automatic linking of documents based on metadata values or document properties. -* Roles support. +* :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. -* Fine grained permissions system. +* :doc:`Fine grained permissions system <../topics/permissions>`. * There is a permission for every atomic operation performed by users. @@ -68,7 +68,7 @@ Features * Multiple page PDFs and TIFFs files supported. -* Distributed OCR processing. +* :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. @@ -76,13 +76,13 @@ Features * **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. -* Multilingual OCR support. +* :doc:`Multilingual OCR support <../topics/ocr>`. * As supported by the OCR engine tesseract. * Duplicated document search. -* Plugable storage backends (File based and GridFS included). +* :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. From 05fdd47fee36939dd92802257c7660b570b5dd7b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 01:47:19 -0400 Subject: [PATCH 439/484] Documentation update --- docs/credits/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/credits/index.rst b/docs/credits/index.rst index 2613360ea1..0280222168 100644 --- a/docs/credits/index.rst +++ b/docs/credits/index.rst @@ -1,7 +1,8 @@ Credits ======= -Introductions to all the key parts of Mayan EDMS you'll need to know: +Here we list everything and everybody that has made his/her/its part in improving +**Mayan EDMS** .. toctree:: :maxdepth: 1 From a7dd15124dc820b93b20da6a31caf68da66e4326 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 11:44:45 -0400 Subject: [PATCH 440/484] Versioning diagram update --- docs/figure_src/versioning.svg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/figure_src/versioning.svg b/docs/figure_src/versioning.svg index e5e64cf1f0..e1f16f0618 100644 --- a/docs/figure_src/versioning.svg +++ b/docs/figure_src/versioning.svg @@ -15,7 +15,10 @@ id="svg2" version="1.1" inkscape:version="0.48.2 r9819" - sodipodi:docname="New document 1"> + sodipodi:docname="versioning.svg" + inkscape:export-filename="/home/rosarior/development/mayan/mayan/docs/topics/versioning.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> Date: Tue, 21 Feb 2012 11:44:57 -0400 Subject: [PATCH 441/484] Fix index menu highlighting logic --- apps/document_indexing/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 8db3c1d54e..32fb6e8a0e 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -44,7 +44,7 @@ index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'tab', ' index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_node_view', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True, 'condition': is_not_instance_root_node} document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} -register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'tab', 'view': 'index_list'}) +register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'tab', 'view': 'index_list', 'children_view_regex': [r'^index_']}) rebuild_index_instances = {'text': _('rebuild indexes'), 'view': 'rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _(u'Deletes and creates from scratch all the document indexes.')} From 1dd6f6f6a2f20da376fa2e8a8f696a1f1a2ad671 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:25:02 -0400 Subject: [PATCH 442/484] Fix top menu navigation children_view_regex matching typo --- apps/navigation/templatetags/navigation_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index b7f8f8550f..f3b989a511 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -38,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 From a6f6dc9f0a1565760b1940d604a16b0aefbe475a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:25:39 -0400 Subject: [PATCH 443/484] Return the top menu entry after it has been registered for futher modification --- apps/navigation/api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index a0ccc9f32e..56bb037245 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -68,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(): From c596c8e24e533ae57b1568345184f3df9408c972 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:26:38 -0400 Subject: [PATCH 444/484] Update a setup top menu entry children_view_regex entries after every new setup sub entry registration --- apps/project_setup/__init__.py | 2 +- apps/project_setup/api.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/project_setup/__init__.py b/apps/project_setup/__init__.py index 7f160810a2..2df65f589d 100644 --- a/apps/project_setup/__init__.py +++ b/apps/project_setup/__init__.py @@ -3,4 +3,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'}, children_path_regex=[r'^settings/', r'^user_management/', r'^permissions', r'^documents/type', r'^metadata/setup', r'sources/setup', r'grouping/setup'], position=-2) diff --git a/apps/project_setup/api.py b/apps/project_setup/api.py index 424d250915..bea3744600 100644 --- a/apps/project_setup/api.py +++ b/apps/project_setup/api.py @@ -1,5 +1,12 @@ +from __future__ import absolute_import + +from . import setup_link + setup_items = [] def register_setup(link): setup_items.append(link) + if 'children_view_regex' in link: + setup_link.setdefault('children_view_regex', []) + setup_link['children_view_regex'].extend(link['children_view_regex']) From 4bb441b5721b0a9db8c8b34a9c185c6a295517e3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:27:42 -0400 Subject: [PATCH 445/484] Improve the document indexing app menu highlighting --- apps/document_indexing/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 32fb6e8a0e..44021889d7 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -28,7 +28,7 @@ def is_not_instance_root_node(context): return context['object'].parent is not None -index_setup = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} +index_setup = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'children_view_regex': [r'^index_setup', r'^template_node']} index_setup_list = {'text': _(u'index list'), 'view': 'index_setup_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} index_setup_create = {'text': _(u'create index'), 'view': 'index_setup_create', 'famfam': 'tab_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_CREATE]} index_setup_edit = {'text': _(u'edit'), 'view': 'index_setup_edit', 'args': 'index.pk', 'famfam': 'tab_edit', 'permissions': [PERMISSION_DOCUMENT_INDEXING_EDIT]} @@ -44,7 +44,7 @@ index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'tab', ' index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_node_view', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True, 'condition': is_not_instance_root_node} document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} -register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'tab', 'view': 'index_list', 'children_view_regex': [r'^index_']}) +register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'tab', 'view': 'index_list', 'children_view_regex': [r'^index_[i,l]']}) rebuild_index_instances = {'text': _('rebuild indexes'), 'view': 'rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _(u'Deletes and creates from scratch all the document indexes.')} From 15219b27b9e350159d692a11852b3ffd3e04cdd9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:52:50 -0400 Subject: [PATCH 446/484] Fix acl app menu highlight --- apps/acls/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 33493dd232..7a83009b39 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -17,7 +17,7 @@ acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_a acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} acl_holder_new = {'text': _(u'New holder'), 'view': 'acl_holder_new', 'args': 'access_object.gid', 'famfam': 'user', 'permissions': [ACLS_EDIT_ACL]} -acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png', 'permissions': [ACLS_CLASS_VIEW_ACL]} +acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png', 'permissions': [ACLS_CLASS_VIEW_ACL], 'children_view_regex': [r'^acl_class', r'^acl_setup']} acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package', 'permissions': [ACLS_CLASS_VIEW_ACL]} acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock_go', 'permissions': [ACLS_CLASS_VIEW_ACL]} acl_class_acl_detail = {'text': _(u'details'), 'view': 'acl_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'key_go', 'permissions': [ACLS_CLASS_VIEW_ACL]} @@ -31,7 +31,7 @@ register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) register_links([AccessObject], [acl_holder_new], menu_name='sidebar') register_setup(acl_setup_valid_classes) -register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acl_class_acl_detail'], [acl_class_list], menu_name='secondary_menu') +register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acl_class_acl_detail', 'acl_class_multiple_grant', 'acl_class_multiple_revoke'], [acl_class_list], menu_name='secondary_menu') register_links(ClassAccessHolder, [acl_class_acl_detail]) From a13052222b0a55014183afd3b7dfaf1802983363 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:53:13 -0400 Subject: [PATCH 447/484] Fix key management app menu hightlighting --- apps/django_gpg/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index 6448d825da..a49c0f26b9 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -16,7 +16,7 @@ public_keys = {'text': _(u'public keys'), 'view': 'key_public_list', 'args': 'ob key_delete = {'text': _(u'delete'), 'view': 'key_delete', 'args': ['object.fingerprint', 'object.type'], 'famfam': 'key_delete', 'permissions': [PERMISSION_KEY_DELETE]} key_query = {'text': _(u'query keyservers'), 'view': 'key_query', 'famfam': 'zoom', 'permissions': [PERMISSION_KEYSERVER_QUERY]} key_receive = {'text': _(u'import'), 'view': 'key_receive', 'args': 'object.keyid', 'famfam': 'key_add', 'keep_query': True, 'permissions': [PERMISSION_KEY_RECEIVE]} -key_setup = {'text': _(u'key management'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} +key_setup = {'text': _(u'key management'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW], 'children_view_regex': [r'^key_']} #register_links(['key_delete', 'key_private_list', 'key_public_list', 'key_query'], [private_keys, public_keys, key_query], menu_name='sidebar') register_links(['key_delete', 'key_public_list', 'key_query'], [public_keys, key_query], menu_name='sidebar') From 21d360d8d22133d22aa4b888b98f354271cae457 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 12:53:35 -0400 Subject: [PATCH 448/484] Improve document acl menu highlighting --- apps/documents/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index f7f1e4a043..5b1dbe4e1d 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -178,7 +178,7 @@ register_top_menu( 'documents', link={'famfam': 'page', 'text': _(u'documents'), 'view': 'document_list_recent'}, children_path_regex=[ - r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents' + r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents', r'document_acl' ], #children_view_regex=[r'upload'], children_views=['document_folder_list', 'folder_add_document', 'document_index_list', 'upload_version', ], From bcb93639df620f8199b4adaa9f6aa29357e64b31 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 15:32:46 -0400 Subject: [PATCH 449/484] Improve the dynamic children view regex append code --- apps/project_setup/api.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/project_setup/api.py b/apps/project_setup/api.py index bea3744600..1d11179701 100644 --- a/apps/project_setup/api.py +++ b/apps/project_setup/api.py @@ -7,6 +7,7 @@ setup_items = [] def register_setup(link): setup_items.append(link) - if 'children_view_regex' in link: - setup_link.setdefault('children_view_regex', []) - setup_link['children_view_regex'].extend(link['children_view_regex']) + + # 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', [])) From ae86d1cd4b29759c86329fd857adb07d18b72621 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 15:33:20 -0400 Subject: [PATCH 450/484] Update all apps to register their own children views regular expressions --- apps/documents/__init__.py | 6 +++--- apps/linking/__init__.py | 2 +- apps/metadata/__init__.py | 4 ++-- apps/permissions/__init__.py | 2 +- apps/project_setup/__init__.py | 3 +-- apps/smart_settings/__init__.py | 2 +- apps/sources/__init__.py | 2 +- apps/user_management/__init__.py | 4 ++-- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 5b1dbe4e1d..cae0edd960 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -110,7 +110,7 @@ document_version_revert = {'text': _(u'revert'), 'view': 'document_version_rever # Document type related links document_type_list = {'text': _(u'document type list'), 'view': 'document_type_list', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} -document_type_setup = {'text': _(u'document types'), 'view': 'document_type_list', 'famfam': 'layout', 'icon': 'layout.png', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} +document_type_setup = {'text': _(u'document types'), 'view': 'document_type_list', 'famfam': 'layout', 'icon': 'layout.png', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW], 'children_view_regex': [r'^document_type_']} document_type_document_list = {'text': _(u'documents of this type'), 'view': 'document_type_document_list', 'args': 'document_type.id', 'famfam': 'page_go', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} document_type_edit = {'text': _(u'edit'), 'view': 'document_type_edit', 'args': 'document_type.id', 'famfam': 'layout_edit', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} document_type_delete = {'text': _(u'delete'), 'view': 'document_type_delete', 'args': 'document_type.id', 'famfam': 'layout_delete', 'permissions': [PERMISSION_DOCUMENT_TYPE_DELETE]} @@ -178,9 +178,9 @@ register_top_menu( 'documents', link={'famfam': 'page', 'text': _(u'documents'), 'view': 'document_list_recent'}, children_path_regex=[ - r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents', r'document_acl' + r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents', ], - #children_view_regex=[r'upload'], + children_view_regex=[r'document_acl', r'smart_link_instance'], children_views=['document_folder_list', 'folder_add_document', 'document_index_list', 'upload_version', ], position=1 ) diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index e45e80a496..b6608ca829 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -17,7 +17,7 @@ from .permissions import (PERMISSION_SMART_LINK_VIEW, smart_link_instance_view_link = {'text': _(u'smart links actions'), 'view': 'smart_link_instance_view', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} smart_link_instances_for_document = {'text': _(u'smart links'), 'view': 'smart_link_instances_for_document', 'args': 'object.pk', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -smart_link_setup = {'text': _(u'smart links'), 'view': 'smart_link_list', 'icon': 'link.png', 'permissions': [PERMISSION_SMART_LINK_CREATE]} +smart_link_setup = {'text': _(u'smart links'), 'view': 'smart_link_list', 'icon': 'link.png', 'permissions': [PERMISSION_SMART_LINK_CREATE], 'children_view_regex': [r'smart_link_list', 'smart_link_create', 'smart_link_delete', 'smart_link_edit', 'smart_link_condition_']} smart_link_list = {'text': _(u'smart links list'), 'view': 'smart_link_list', 'famfam': 'link', 'permissions': [PERMISSION_SMART_LINK_CREATE]} smart_link_create = {'text': _(u'create new smart link'), 'view': 'smart_link_create', 'famfam': 'link_add', 'permissions': [PERMISSION_SMART_LINK_CREATE]} smart_link_edit = {'text': _(u'edit'), 'view': 'smart_link_edit', 'args': 'object.pk', 'famfam': 'link_edit', 'permissions': [PERMISSION_SMART_LINK_EDIT]} diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index f52465d568..9f7ea6bb6e 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -26,12 +26,12 @@ metadata_multiple_add = {'text': _(u'add metadata'), 'view': 'metadata_multiple_ 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]} +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]} +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]} diff --git a/apps/permissions/__init__.py b/apps/permissions/__init__.py index 12c5be29aa..73731a97db 100644 --- a/apps/permissions/__init__.py +++ b/apps/permissions/__init__.py @@ -14,7 +14,7 @@ from .permissions import (PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE) -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]} diff --git a/apps/project_setup/__init__.py b/apps/project_setup/__init__.py index 2df65f589d..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 -setup_link = 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/smart_settings/__init__.py b/apps/smart_settings/__init__.py index e28aa67add..bfc495e54d 100644 --- a/apps/smart_settings/__init__.py +++ b/apps/smart_settings/__init__.py @@ -6,6 +6,6 @@ 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/sources/__init__.py b/apps/sources/__init__.py index 707b09ef67..d9612a6f9d 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -19,7 +19,7 @@ from .permissions import (PERMISSION_SOURCES_SETUP_VIEW, 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], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} +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]} diff --git a/apps/user_management/__init__.py b/apps/user_management/__init__.py index fb751fb6c2..00d0e50533 100644 --- a/apps/user_management/__init__.py +++ b/apps/user_management/__init__.py @@ -11,7 +11,7 @@ from .permissions import (PERMISSION_USER_CREATE, PERMISSION_USER_EDIT, PERMISSION_GROUP_EDIT, PERMISSION_GROUP_VIEW, PERMISSION_GROUP_DELETE) user_list = {'text': _(u'user list'), 'view': 'user_list', 'famfam': 'user', 'permissions': [PERMISSION_USER_VIEW]} -user_setup = {'text': _(u'users'), 'view': 'user_list', 'famfam': 'user', 'icon': 'user.png', 'permissions': [PERMISSION_USER_VIEW]} +user_setup = {'text': _(u'users'), 'view': 'user_list', 'famfam': 'user', 'icon': 'user.png', 'permissions': [PERMISSION_USER_VIEW], 'children_view_regex': [r'^user_']} user_edit = {'text': _(u'edit'), 'view': 'user_edit', 'args': 'object.id', 'famfam': 'user_edit', 'permissions': [PERMISSION_USER_EDIT]} user_add = {'text': _(u'create new user'), 'view': 'user_add', 'famfam': 'user_add', 'permissions': [PERMISSION_USER_CREATE]} user_delete = {u'text': _('delete'), 'view': 'user_delete', 'args': 'object.id', 'famfam': 'user_delete', 'permissions': [PERMISSION_USER_DELETE]} @@ -20,7 +20,7 @@ user_set_password = {u'text': _('reset password'), 'view': 'user_set_password', user_multiple_set_password = {u'text': _('reset password'), 'view': 'user_multiple_set_password', 'famfam': 'lock_edit', 'permissions': [PERMISSION_USER_EDIT]} group_list = {'text': _(u'group list'), 'view': 'group_list', 'famfam': 'group', 'permissions': [PERMISSION_GROUP_VIEW]} -group_setup = {'text': _(u'groups'), 'view': 'group_list', 'famfam': 'group', 'icon': 'group.png', 'permissions': [PERMISSION_GROUP_VIEW]} +group_setup = {'text': _(u'groups'), 'view': 'group_list', 'famfam': 'group', 'icon': 'group.png', 'permissions': [PERMISSION_GROUP_VIEW], 'children_view_regex': [r'^group_']} group_edit = {'text': _(u'edit'), 'view': 'group_edit', 'args': 'object.id', 'famfam': 'group_edit', 'permissions': [PERMISSION_GROUP_EDIT]} group_add = {'text': _(u'create new group'), 'view': 'group_add', 'famfam': 'group_add', 'permissions': [PERMISSION_GROUP_CREATE]} group_delete = {u'text': _('delete'), 'view': 'group_delete', 'args': 'object.id', 'famfam': 'group_delete', 'permissions': [PERMISSION_GROUP_DELETE]} From 91d1e5a33cfa16e0871a03c2d95affcafb9c0079 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 15:45:08 -0400 Subject: [PATCH 451/484] Copy project setup's dynamic children view regex solution --- apps/project_tools/__init__.py | 4 +--- apps/project_tools/api.py | 9 ++++++++- 2 files changed, 9 insertions(+), 4 deletions(-) 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', [])) From 87b042101ddfb0678f51cd2cbdde25aaa15f5da7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 15:45:45 -0400 Subject: [PATCH 452/484] Convert app to use project tools new dynamic children view regex --- apps/converter/__init__.py | 2 +- apps/history/__init__.py | 2 +- apps/main/__init__.py | 2 +- apps/ocr/__init__.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/converter/__init__.py b/apps/converter/__init__.py index 85d6ab408f..29dcb978fe 100644 --- a/apps/converter/__init__.py +++ b/apps/converter/__init__.py @@ -12,7 +12,7 @@ from .conf.settings import GRAPHICS_BACKEND def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser -formats_list = {'text': _('file formats'), 'view': 'formats_list', 'famfam': 'pictures', 'icon': 'pictures.png', 'condition': is_superuser} +formats_list = {'text': _('file formats'), 'view': 'formats_list', 'famfam': 'pictures', 'icon': 'pictures.png', 'condition': is_superuser, 'children_view_regex': [r'formats_list']} register_sidebar_template(['formats_list'], 'converter_file_formats_help.html') diff --git a/apps/history/__init__.py b/apps/history/__init__.py index c347cd6fcc..b0b4025a3e 100644 --- a/apps/history/__init__.py +++ b/apps/history/__init__.py @@ -7,6 +7,6 @@ from project_tools.api import register_tool from .permissions import PERMISSION_HISTORY_VIEW -history_list = {'text': _(u'history'), 'view': 'history_list', 'famfam': 'book', 'icon': 'book.png', 'permissions': [PERMISSION_HISTORY_VIEW], 'children_views': ['history_view']} +history_list = {'text': _(u'history'), 'view': 'history_list', 'famfam': 'book', 'icon': 'book.png', 'permissions': [PERMISSION_HISTORY_VIEW], 'children_view_regex': [r'history_[l,v]']} register_tool(history_list) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 7522fc7a27..e437a2ff9c 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -31,7 +31,7 @@ def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser maintenance_menu = {'text': _(u'maintenance'), 'view': 'maintenance_menu', 'famfam': 'wrench', 'icon': 'wrench.png'} -statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png', 'condition': is_superuser} +statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png', 'condition': is_superuser, 'children_view_regex': [r'statistics']} diagnostics = {'text': _(u'diagnostics'), 'view': 'diagnostics', 'famfam': 'pill', 'icon': 'pill.png'} sentry = {'text': _(u'sentry'), 'view': 'sentry', 'famfam': 'bug', 'icon': 'bug.png', 'condition': is_superuser} admin_site = {'text': _(u'admin site'), 'view': 'admin:index', 'famfam': 'keyboard', 'icon': 'keyboard.png', 'condition': is_superuser} diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index c1c280503c..3a3b0ac7c9 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -42,7 +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]} +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'} From df1cc7121e7ebe5fc95420e65ea3dad7956810a9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 15:47:16 -0400 Subject: [PATCH 453/484] Remove remarked lines --- settings.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/settings.py b/settings.py index 4b0bd90460..ccd6d21270 100644 --- a/settings.py +++ b/settings.py @@ -243,21 +243,18 @@ if DEVELOPMENT: INSTALLED_APPS += ('rosetta',) except ImportError: pass - #sys.stderr.write('DEBUG: rosetta is not installed\n') try: import django_extensions INSTALLED_APPS += ('django_extensions',) except ImportError: pass - #sys.stderr.write('DEBUG: django_extensions is not installed\n') try: import debug_toolbar #INSTALLED_APPS +=('debug_toolbar',) except ImportError: pass - #sys.stderr.write('DEBUG: debug_toolbar is not installed\n') TEMPLATE_CONTEXT_PROCESSORS += ('django.core.context_processors.debug',) From edaf682607520b07187d4d3ad3ef91e9a500d02b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 21 Feb 2012 15:51:49 -0400 Subject: [PATCH 454/484] Shutdown scheduler on South's pre_migrate signal --- apps/scheduler/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/scheduler/__init__.py b/apps/scheduler/__init__.py index fd2f06bd8b..80c406fd3b 100644 --- a/apps/scheduler/__init__.py +++ b/apps/scheduler/__init__.py @@ -7,6 +7,8 @@ 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__) @@ -22,3 +24,9 @@ def scheduler_shutdown_post_syncdb(sender, **kwargs): 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() From 3b22489be18ddc5ee0bbe14bda3963534b192d65 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 09:40:16 -0400 Subject: [PATCH 455/484] Don't hide index rebuilding errors if DEBUG is True --- apps/document_indexing/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 7f9afd2d14..8a94e77cf2 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -8,6 +8,7 @@ from django.contrib import messages from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied from django.utils.html import mark_safe +from django.conf import settings from permissions.models import Permission from documents.permissions import PERMISSION_DOCUMENT_VIEW @@ -372,6 +373,8 @@ def rebuild_index_instances(request): messages.warning(request, warning) except Exception, e: + if settings.DEBUG: + raise messages.error(request, _(u'Index rebuild error: %s') % e) return HttpResponseRedirect(next) From 5bc61ca70ee0b60a836379337096c8c97e2f929f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 11:55:48 -0400 Subject: [PATCH 456/484] Remove unused test files --- apps/acls/tests.py | 16 ---------------- apps/common/tests.py | 22 ---------------------- apps/document_acls/tests.py | 16 ---------------- apps/document_comments/tests.py | 23 ----------------------- apps/document_indexing/tests.py | 22 ---------------------- apps/document_signatures/tests.py | 16 ---------------- apps/dynamic_search/tests.py | 23 ----------------------- apps/feedback/tests.py | 16 ---------------- apps/history/tests.py | 23 ----------------------- apps/job_processor/tests.py | 23 ----------------------- apps/main/tests.py | 22 ---------------------- apps/metadata/tests.py | 22 ---------------------- apps/mimetype/tests.py | 23 ----------------------- apps/navigation/tests.py | 23 ----------------------- apps/ocr/tests.py | 22 ---------------------- apps/permissions/tests.py | 22 ---------------------- apps/project_setup/tests.py | 23 ----------------------- apps/project_tools/tests.py | 23 ----------------------- apps/rest_api/tests.py | 1 - apps/scheduler/tests.py | 23 ----------------------- apps/smart_settings/tests.py | 22 ---------------------- apps/sources/tests.py | 22 ---------------------- apps/storage/tests.py | 23 ----------------------- apps/user_management/tests.py | 23 ----------------------- apps/web_theme/tests.py | 23 ----------------------- 25 files changed, 517 deletions(-) delete mode 100644 apps/acls/tests.py delete mode 100644 apps/common/tests.py delete mode 100644 apps/document_acls/tests.py delete mode 100644 apps/document_comments/tests.py delete mode 100644 apps/document_indexing/tests.py delete mode 100644 apps/document_signatures/tests.py delete mode 100644 apps/dynamic_search/tests.py delete mode 100644 apps/feedback/tests.py delete mode 100644 apps/history/tests.py delete mode 100644 apps/job_processor/tests.py delete mode 100644 apps/main/tests.py delete mode 100644 apps/metadata/tests.py delete mode 100644 apps/mimetype/tests.py delete mode 100644 apps/navigation/tests.py delete mode 100644 apps/ocr/tests.py delete mode 100644 apps/permissions/tests.py delete mode 100644 apps/project_setup/tests.py delete mode 100644 apps/project_tools/tests.py delete mode 100644 apps/rest_api/tests.py delete mode 100644 apps/scheduler/tests.py delete mode 100644 apps/smart_settings/tests.py delete mode 100644 apps/sources/tests.py delete mode 100644 apps/storage/tests.py delete mode 100644 apps/user_management/tests.py delete mode 100644 apps/web_theme/tests.py diff --git a/apps/acls/tests.py b/apps/acls/tests.py deleted file mode 100644 index 501deb776c..0000000000 --- a/apps/acls/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/common/tests.py b/apps/common/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/common/tests.py +++ /dev/null @@ -1,22 +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/document_acls/tests.py b/apps/document_acls/tests.py deleted file mode 100644 index 501deb776c..0000000000 --- a/apps/document_acls/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/document_comments/tests.py b/apps/document_comments/tests.py deleted file mode 100644 index 2247054b35..0000000000 --- a/apps/document_comments/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/document_indexing/tests.py b/apps/document_indexing/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/document_indexing/tests.py +++ /dev/null @@ -1,22 +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/document_signatures/tests.py b/apps/document_signatures/tests.py deleted file mode 100644 index 501deb776c..0000000000 --- a/apps/document_signatures/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/dynamic_search/tests.py b/apps/dynamic_search/tests.py deleted file mode 100644 index 2247054b35..0000000000 --- a/apps/dynamic_search/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/feedback/tests.py b/apps/feedback/tests.py deleted file mode 100644 index 501deb776c..0000000000 --- a/apps/feedback/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this 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.assertEqual(1 + 1, 2) diff --git a/apps/history/tests.py b/apps/history/tests.py deleted file mode 100644 index 2247054b35..0000000000 --- a/apps/history/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/job_processor/tests.py b/apps/job_processor/tests.py deleted file mode 100644 index 2247054b35..0000000000 --- a/apps/job_processor/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/tests.py b/apps/main/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/main/tests.py +++ /dev/null @@ -1,22 +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/tests.py b/apps/metadata/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/metadata/tests.py +++ /dev/null @@ -1,22 +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/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/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/ocr/tests.py b/apps/ocr/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/ocr/tests.py +++ /dev/null @@ -1,22 +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/tests.py b/apps/permissions/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/permissions/tests.py +++ /dev/null @@ -1,22 +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/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_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/rest_api/tests.py b/apps/rest_api/tests.py deleted file mode 100644 index 8b13789179..0000000000 --- a/apps/rest_api/tests.py +++ /dev/null @@ -1 +0,0 @@ - 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/smart_settings/tests.py b/apps/smart_settings/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/smart_settings/tests.py +++ /dev/null @@ -1,22 +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/tests.py b/apps/sources/tests.py deleted file mode 100644 index 3b31148896..0000000000 --- a/apps/sources/tests.py +++ /dev/null @@ -1,22 +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/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/user_management/tests.py b/apps/user_management/tests.py deleted file mode 100644 index 2247054b35..0000000000 --- a/apps/user_management/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/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 -"""} - From af9be9084994ea2b1e62d0ea120270f25bda7058 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 11:56:18 -0400 Subject: [PATCH 457/484] Improve tag app menu highlighting --- apps/tags/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index ea2a2444b9..2bfcb2f508 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -49,7 +49,7 @@ register_model_list_columns(Document, [ 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, '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_path_regex=[r'^tags/[^d]'])#TODO: change to children view regex or list +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_remove', 'tag_multiple_remove', 'tag_attach'], [tag_attach], menu_name='sidebar') From f484e1a9c3902e2ba696aa8e417c6ea1b1215e7d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 11:57:00 -0400 Subject: [PATCH 458/484] PEP8 and general cleanups --- apps/django_gpg/api.py | 2 +- apps/django_gpg/forms.py | 1 - apps/django_gpg/runtime.py | 2 +- apps/django_gpg/views.py | 9 ++++----- apps/document_comments/views.py | 2 +- apps/document_indexing/api.py | 8 +++----- apps/document_indexing/tools.py | 2 +- apps/document_indexing/widgets.py | 5 ++--- apps/document_signatures/managers.py | 4 ++-- apps/linking/forms.py | 2 -- apps/linking/views.py | 1 - apps/mimetype/api.py | 3 ++- apps/ocr/__init__.py | 1 + apps/ocr/views.py | 2 -- apps/signaler/management/commands/collectstatic.py | 2 +- apps/sources/management/commands/bulk_upload.py | 13 +++++++------ apps/sources/models.py | 14 +++++++------- apps/sources/views.py | 8 ++++---- .../management/commands/import_users.py | 12 +++++++----- 19 files changed, 44 insertions(+), 49 deletions(-) diff --git a/apps/django_gpg/api.py b/apps/django_gpg/api.py index 38e60fde76..6d2feea14b 100644 --- a/apps/django_gpg/api.py +++ b/apps/django_gpg/api.py @@ -178,7 +178,7 @@ class GPG(object): self.keyservers = keyservers self.gpg = gnupg.GPG(**kwargs) - + def verify_file(self, file_input, detached_signature=None, fetch_key=False): """ Verify the signature of a file. diff --git a/apps/django_gpg/forms.py b/apps/django_gpg/forms.py index 9a9514fdb3..930298d4b1 100644 --- a/apps/django_gpg/forms.py +++ b/apps/django_gpg/forms.py @@ -1,6 +1,5 @@ from django import forms from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ugettext class KeySearchForm(forms.Form): diff --git a/apps/django_gpg/runtime.py b/apps/django_gpg/runtime.py index afb5d73867..257ba8e3fd 100644 --- a/apps/django_gpg/runtime.py +++ b/apps/django_gpg/runtime.py @@ -8,6 +8,6 @@ from .conf.settings import KEYSERVERS, GPG_HOME try: gpg = GPG(home=GPG_HOME, keyservers=KEYSERVERS) except Exception, e: - gpg = GPG(keyservers=KEYSERVERS) + gpg = GPG(keyservers=KEYSERVERS) sys.stderr.write(u'ERROR: GPG initialization error: %s\n' % e) sys.stderr.write(u'INFO: Initializating GPG with system default home\n') diff --git a/apps/django_gpg/views.py b/apps/django_gpg/views.py index 09a74d0a4d..b390dee333 100644 --- a/apps/django_gpg/views.py +++ b/apps/django_gpg/views.py @@ -9,12 +9,11 @@ from django.template import RequestContext from django.contrib import messages from permissions.models import Permission -from common.utils import (urlquote, encapsulate) +from common.utils import encapsulate -from .api import Key, SIGNATURE_STATES +from .api import Key from .runtime import gpg -from .exceptions import (GPGVerificationError, KeyFetchingError, - KeyImportError) +from .exceptions import KeyFetchingError, KeyImportError from .forms import KeySearchForm from .permissions import (PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, PERMISSION_KEYSERVER_QUERY, PERMISSION_KEY_RECEIVE) @@ -40,7 +39,7 @@ def key_receive(request, key_id): except (KeyImportError, KeyError, TypeError), e: messages.error( request, - _(u'Unable to import key id: %(key_id)s; %(error)s') % + _(u'Unable to import key id: %(key_id)s; %(error)s') % { 'key_id': key_id, 'error': e, diff --git a/apps/document_comments/views.py b/apps/document_comments/views.py index 7c089b3cda..4a87435fa3 100644 --- a/apps/document_comments/views.py +++ b/apps/document_comments/views.py @@ -34,7 +34,7 @@ def comment_delete(request, comment_id=None, comment_id_list=None): if not comments: messages.error(request, _(u'Must provide at least one comment.')) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) 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', '/'))) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 7112f1d3a2..49f262f35a 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -2,13 +2,11 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext -from django.core.urlresolvers import reverse from django.template.defaultfilters import slugify from metadata.classes import MetadataClass -from .models import (Index, IndexTemplateNode, IndexInstanceNode, - DocumentRenameCount) +from .models import Index, IndexInstanceNode, DocumentRenameCount from .conf.settings import (AVAILABLE_INDEXING_FUNCTIONS, MAX_SUFFIX_COUNT, SLUGIFY_PATHS) from .filesystem import (fs_create_index_directory, @@ -94,7 +92,7 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) fs_create_index_directory(index_instance) except Exception, exc: warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exc}) + 'expression': template_node.expression, 'exception': exc}) if template_node.link_documents: suffix = find_lowest_available_suffix(index_instance, document) @@ -109,7 +107,7 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) fs_create_document_link(index_instance, document, suffix) except Exception, exc: warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exc}) + 'expression': template_node.expression, 'exception': exc}) index_instance.documents.add(document) diff --git a/apps/document_indexing/tools.py b/apps/document_indexing/tools.py index 71837b0930..cc83183dae 100644 --- a/apps/document_indexing/tools.py +++ b/apps/document_indexing/tools.py @@ -10,7 +10,7 @@ from .api import update_indexes def do_rebuild_all_indexes(): for index in Index.objects.all(): fs_delete_directory_recusive(index) - + IndexInstanceNode.objects.all().delete() DocumentRenameCount.objects.all().delete() for document in Document.objects.all(): diff --git a/apps/document_indexing/widgets.py b/apps/document_indexing/widgets.py index e678feebb7..d1dea28b90 100644 --- a/apps/document_indexing/widgets.py +++ b/apps/document_indexing/widgets.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -#from django.utils.safestring import mark_safe -from django.utils.html import conditional_escape, mark_safe +from django.utils.html import mark_safe from .models import IndexInstanceNode @@ -73,7 +72,7 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou else: output.insert(0, u' / '.join(result)) return mark_safe(u' '.join(output)) - + def node_level(x): """ diff --git a/apps/document_signatures/managers.py b/apps/document_signatures/managers.py index e812f1935f..1052d6d988 100644 --- a/apps/document_signatures/managers.py +++ b/apps/document_signatures/managers.py @@ -69,7 +69,7 @@ class DocumentVersionSignatureManager(models.Manager): document_descriptor.close() if detached_signature: detached_signature.close() - + def clear_detached_signature(self, document): document_signature = self.get_document_signature(document) if not document_signature.signature_file: @@ -77,4 +77,4 @@ class DocumentVersionSignatureManager(models.Manager): document_signature.delete_detached_signature_file() document_signature.signature_file = None - document_signature.save() + document_signature.save() diff --git a/apps/linking/forms.py b/apps/linking/forms.py index 53c9639f53..46e92454d6 100644 --- a/apps/linking/forms.py +++ b/apps/linking/forms.py @@ -1,12 +1,10 @@ from __future__ import absolute_import from django import forms -from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.core.urlresolvers import reverse from django.utils.safestring import mark_safe from django.template.defaultfilters import capfirst -from django.conf import settings from documents.widgets import document_html_widget from tags.widgets import get_tags_inline_widget diff --git a/apps/linking/views.py b/apps/linking/views.py index 538badd895..e02fdabc29 100644 --- a/apps/linking/views.py +++ b/apps/linking/views.py @@ -127,7 +127,6 @@ def smart_link_list(request): except PermissionDenied: qs = AccessEntry.objects.filter_objects_by_access(PERMISSION_SMART_LINK_VIEW, request.user, qs) - return render_to_response('generic_list.html', { 'title': _(u'smart links'), 'object_list': qs, 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/ocr/__init__.py b/apps/ocr/__init__.py index 3a3b0ac7c9..22b55a9ae5 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -95,6 +95,7 @@ def document_post_save(sender, instance, **kwargs): # logger.debug('got call_queue signal: %s' % kwargs) # task_process_document_queues() + @receiver(post_syncdb, dispatch_uid='create_default_queue', sender=ocr_models) def create_default_queue_signal_handler(sender, **kwargs): create_default_queue() diff --git a/apps/ocr/views.py b/apps/ocr/views.py index fbeafc7b3a..92772ad03e 100644 --- a/apps/ocr/views.py +++ b/apps/ocr/views.py @@ -1,7 +1,5 @@ from __future__ import absolute_import -import socket - from django.http import HttpResponseRedirect from django.shortcuts import render_to_response, get_object_or_404 from django.template import RequestContext diff --git a/apps/signaler/management/commands/collectstatic.py b/apps/signaler/management/commands/collectstatic.py index e33b4d0ec1..28b63cd9f2 100644 --- a/apps/signaler/management/commands/collectstatic.py +++ b/apps/signaler/management/commands/collectstatic.py @@ -10,4 +10,4 @@ class Command(collectstatic.Command): def handle_noargs(self, *args, **kwargs): pre_collectstatic.send(sender=self) - super(Command, self).handle_noargs(*args, **kwargs) + super(Command, self).handle_noargs(*args, **kwargs) diff --git a/apps/sources/management/commands/bulk_upload.py b/apps/sources/management/commands/bulk_upload.py index 47c0a179d1..8fa11f652e 100644 --- a/apps/sources/management/commands/bulk_upload.py +++ b/apps/sources/management/commands/bulk_upload.py @@ -1,10 +1,11 @@ from __future__ import absolute_import -import os, sys +import os +import sys from optparse import make_option from django.core.management.base import BaseCommand, CommandError, LabelCommand -from django.utils.simplejson import loads, dumps +from django.utils.simplejson import loads from metadata.api import convert_dict_to_dict_list from documents.models import DocumentType @@ -25,7 +26,7 @@ class Command(LabelCommand): 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) @@ -53,10 +54,10 @@ class Command(LabelCommand): 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: @@ -71,7 +72,7 @@ class Command(LabelCommand): else: print 'Cancelled.' - + def _confirm(interactive): if not interactive: return 'yes' diff --git a/apps/sources/models.py b/apps/sources/models.py index ad20758bff..0941abd00d 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -9,7 +9,6 @@ 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 django.db.utils import DatabaseError from converter.api import get_available_transformations_choices from converter.literals import DIMENSION_SEPARATOR @@ -91,7 +90,7 @@ class BaseModel(models.Model): @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: @@ -99,7 +98,7 @@ class BaseModel(models.Model): document.save() apply_default_acls(document, user) - + if user: document.add_as_recent_document_for_user(user) create_history(HISTORY_DOCUMENT_CREATED, document, {'user': user}) @@ -113,7 +112,7 @@ class BaseModel(models.Model): if not new_version_data: new_version_data = {} - + try: new_version = document.new_version(file=file_object, **new_version_data) except Exception: @@ -121,7 +120,7 @@ class BaseModel(models.Model): # document.delete() transaction.rollback() raise - + if filename: document.rename(filename) @@ -129,11 +128,11 @@ class BaseModel(models.Model): 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) + warnings = update_indexes(document) class Meta: ordering = ('title',) @@ -288,6 +287,7 @@ class SourceTransformation(models.Model): 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/views.py b/apps/sources/views.py index 0c107d7365..775ddf2917 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -165,13 +165,13 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No else: 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: @@ -240,7 +240,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No 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) diff --git a/apps/user_management/management/commands/import_users.py b/apps/user_management/management/commands/import_users.py index b02d08d5b4..9ccfbe09dc 100644 --- a/apps/user_management/management/commands/import_users.py +++ b/apps/user_management/management/commands/import_users.py @@ -1,10 +1,11 @@ from __future__ import absolute_import -import csv, os, sys +import csv +import os +import sys from optparse import make_option from django.core.management.base import BaseCommand, CommandError, LabelCommand -from django.utils.simplejson import loads, dumps from django.contrib.auth.models import User from django.db.utils import IntegrityError @@ -17,11 +18,12 @@ def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs): # decode UTF-8 back to Unicode, cell by cell: yield [unicode(cell, 'utf-8') for cell in row] + def utf_8_encoder(unicode_csv_data): for line in unicode_csv_data: yield line.encode('utf-8') - + class Command(LabelCommand): args = '' help = 'Import users from a CSV file with the field order: username, firstname, lastname, email.' @@ -34,7 +36,7 @@ class Command(LabelCommand): make_option('--skip-repeated', action='store_true', dest='skip_repeated', default=False, help='Don\'t exit if the user already exists.'), ) - + def handle_label(self, label, **options): if not os.access(label, os.R_OK): raise CommandError("File '%s' is not readable." % label) @@ -68,7 +70,7 @@ class Command(LabelCommand): sys.exit() except csv.Error, e: - sys.exit('file %s, line %d: %s' % (label, reader.line_num, e)) + sys.exit('file %s, line %d: %s' % (label, reader.line_num, e)) else: print 'Finish.' else: From edca055856f6f2336fbcd0389fae3376c772b568 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 14:34:05 -0400 Subject: [PATCH 459/484] acl app cleanups --- apps/acls/forms.py | 4 ++-- apps/acls/managers.py | 15 ++++++--------- apps/acls/models.py | 3 +-- apps/acls/utils.py | 5 ++--- apps/acls/views.py | 24 ++++++++++-------------- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/apps/acls/forms.py b/apps/acls/forms.py index 3f2c048320..6182f8fc5f 100644 --- a/apps/acls/forms.py +++ b/apps/acls/forms.py @@ -52,7 +52,7 @@ class BaseHolderSelectionForm(forms.Form): class HolderSelectionForm(BaseHolderSelectionForm): special_holders = [AnonymousUserSingleton.objects.get()] - - + + class ClassHolderSelectionForm(BaseHolderSelectionForm): special_holders = [AnonymousUserSingleton.objects.get(), CreatorSingleton.objects.get()] diff --git a/apps/acls/managers.py b/apps/acls/managers.py index 061359d102..42ad2f7bc4 100644 --- a/apps/acls/managers.py +++ b/apps/acls/managers.py @@ -3,7 +3,6 @@ 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.auth.models import User @@ -14,8 +13,7 @@ from django.db.models import Q from common.models import AnonymousUserSingleton from permissions.models import Permission, RoleMember -from .classes import (EncapsulatedObject, AccessHolder, ClassAccessHolder, - get_source_object) +from .classes import AccessHolder, ClassAccessHolder, get_source_object logger = logging.getLogger(__name__) @@ -62,7 +60,6 @@ class AccessEntryManager(models.Manager): access_entry.delete() return True - def has_access(self, permission, actor, obj, db_only=False): """ Returns whether an actor has a specific permission for an object @@ -152,7 +149,7 @@ class AccessEntryManager(models.Manager): groups = actor.groups.all() else: groups = [] - + for group in groups: group_type = ContentType.objects.get_for_model(group) if related: @@ -162,8 +159,8 @@ class AccessEntryManager(models.Manager): if total_queries is None: total_queries = query else: - total_queries = total_queries | query - + total_queries = total_queries | query + if related: actor_query = Q(holder_type=actor_type, holder_id=actor.pk, permission=permission.get_stored_permission) master_list = [obj.content_object for obj in self.model.objects.select_related().filter(actor_query | total_queries)] @@ -189,9 +186,9 @@ class AccessEntryManager(models.Manager): holder_list = [] for access_entry in self.model.objects.filter(content_type=content_type, object_id=obj.pk): if access_entry.holder_object: - # Don't add references to non existant content type objects + # Don't add references to non existant content type objects entry = AccessHolder.encapsulate(access_entry.holder_object) - + if entry not in holder_list: holder_list.append(entry) diff --git a/apps/acls/models.py b/apps/acls/models.py index b5e7c2829b..6637c12a24 100644 --- a/apps/acls/models.py +++ b/apps/acls/models.py @@ -7,8 +7,6 @@ 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.core.exceptions import PermissionDenied -from django.core.exceptions import ObjectDoesNotExist from permissions.models import StoredPermission from common.models import Singleton, SingletonManager @@ -102,6 +100,7 @@ class CreatorSingletonManager(SingletonManager): else: return holder + class CreatorSingleton(Singleton): objects = CreatorSingletonManager() diff --git a/apps/acls/utils.py b/apps/acls/utils.py index 01673490e2..17029e18be 100644 --- a/apps/acls/utils.py +++ b/apps/acls/utils.py @@ -7,8 +7,7 @@ from django.contrib.contenttypes.models import ContentType from common.models import AnonymousUserSingleton from .models import AccessEntry, DefaultAccessEntry, CreatorSingleton -from .classes import (EncapsulatedObject, AccessHolder, ClassAccessHolder, - get_source_object) +from .classes import get_source_object logger = logging.getLogger(__name__) @@ -24,7 +23,7 @@ def apply_default_acls(obj, actor=None): for default_acl in DefaultAccessEntry.objects.filter(content_type=content_type): holder = CreatorSingleton.objects.passthru_check(default_acl.holder_object, actor) - + if holder: # When the creator is admin access_entry = AccessEntry( diff --git a/apps/acls/views.py b/apps/acls/views.py index 2325a31114..856b3edd00 100644 --- a/apps/acls/views.py +++ b/apps/acls/views.py @@ -120,7 +120,7 @@ def acl_detail_for(request, actor, obj): 'multi_select_item_properties': { 'permission_pk': lambda x: x.pk, 'holder_gid': lambda x: actor.gid, - 'object_gid': lambda x: obj.gid, + 'object_gid': lambda x: obj.gid, }, 'access_object': obj, 'navigation_object_list': [ @@ -138,10 +138,9 @@ def acl_detail_for(request, actor, obj): def acl_grant(request): items_property_list = loads(request.GET.get('items_property_list', [])) - post_action_redirect = None - 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))) + 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', '/'))) items = {} title_suffix = [] @@ -232,10 +231,9 @@ def acl_grant(request): def acl_revoke(request): items_property_list = loads(request.GET.get('items_property_list', [])) - post_action_redirect = None - 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))) + 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', '/'))) items = {} title_suffix = [] @@ -403,7 +401,7 @@ def acl_class_acl_list(request, access_object_class_gid): access_object_class = AccessObjectClass.get(gid=access_object_class_gid) logger.debug('access_object_class: %s' % access_object_class) - + context = { 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), 'title': _(u'default access control lists for class: %s') % access_object_class, @@ -496,10 +494,9 @@ def acl_class_new_holder_for(request, access_object_class_gid): def acl_class_multiple_grant(request): Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) - post_action_redirect = None - 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))) + 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', '/'))) items = {} title_suffix = [] @@ -576,10 +573,9 @@ def acl_class_multiple_grant(request): def acl_class_multiple_revoke(request): Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) - post_action_redirect = None - 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))) + 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', '/'))) items = {} title_suffix = [] From 27293d3396e0baa4cec055cf884b4bb8764f769d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 14:34:20 -0400 Subject: [PATCH 460/484] feedback app cleanups --- apps/feedback/__init__.py | 3 +-- apps/feedback/api.py | 2 +- apps/feedback/forms.py | 4 ++-- apps/feedback/views.py | 5 ++--- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/feedback/__init__.py b/apps/feedback/__init__.py index 1a6a97716c..8e6c005ae4 100644 --- a/apps/feedback/__init__.py +++ b/apps/feedback/__init__.py @@ -2,8 +2,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import (register_links, register_top_menu, - register_multi_item_links, register_sidebar_template) +from navigation.api import register_links from common import about_view, license_view form_view = {'text': _('Feedback'), 'view': 'form_view', 'famfam': 'telephone'} diff --git a/apps/feedback/api.py b/apps/feedback/api.py index b373f74408..083cd0e79e 100644 --- a/apps/feedback/api.py +++ b/apps/feedback/api.py @@ -9,4 +9,4 @@ TIMEOUT = 10 def submit_form(form): - r = requests.post(FORM_SUBMIT_URL, data={'formkey': FORM_KEY, FORM_RECEIVER_FIELD: dumps(form.cleaned_data)}, timeout=TIMEOUT) + requests.post(FORM_SUBMIT_URL, data={'formkey': FORM_KEY, FORM_RECEIVER_FIELD: dumps(form.cleaned_data)}, timeout=TIMEOUT) diff --git a/apps/feedback/forms.py b/apps/feedback/forms.py index afee457dbc..e7cfcd196c 100644 --- a/apps/feedback/forms.py +++ b/apps/feedback/forms.py @@ -50,7 +50,7 @@ class FeedbackForm(forms.Form): label=_(u'Are currently providing or planning to provide paid support for Mayan EDMS?'), required=False ) - + hosted = forms.BooleanField( label=_(u'Would you be interested in a cloud hosted solution for Mayan EDMS?'), required=False @@ -70,7 +70,7 @@ class FeedbackForm(forms.Form): label=_(u'Your email:'), required=False ) - + company = forms.CharField( label=_(u'Company name:'), required=False diff --git a/apps/feedback/views.py b/apps/feedback/views.py index b6c9d2b5b3..a4cf1ebca3 100644 --- a/apps/feedback/views.py +++ b/apps/feedback/views.py @@ -2,10 +2,9 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response, get_object_or_404 +from django.shortcuts import render_to_response from django.template import RequestContext from django.contrib import messages -from django.core.urlresolvers import reverse from .forms import FeedbackForm from .api import submit_form @@ -28,4 +27,4 @@ def form_view(request): 'title': _(u'feedback form'), 'form': form, }, - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) From 145afedd8988b677f91c4d7300bd76b090326a52 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 22 Feb 2012 14:37:11 -0400 Subject: [PATCH 461/484] tag app cleanups --- apps/tags/views.py | 3 +-- apps/tags/widgets.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/tags/views.py b/apps/tags/views.py index 4076571167..cb82ae0c64 100644 --- a/apps/tags/views.py +++ b/apps/tags/views.py @@ -14,9 +14,8 @@ from taggit.models import Tag from documents.models import Document from documents.views import document_list from documents.permissions import PERMISSION_DOCUMENT_VIEW -from common.utils import encapsulate from acls.models import AccessEntry, PermissionDenied -from acls.views import acl_list_for, acl_new_holder_for +from acls.views import acl_list_for from acls.utils import apply_default_acls from .forms import TagListForm, TagForm diff --git a/apps/tags/widgets.py b/apps/tags/widgets.py index 056d667498..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 @@ -41,7 +40,7 @@ def single_tag_widget(tag): tags_template = [] tags_template.append('