Merge branch 'development' into feature/multi-tenant

This commit is contained in:
Roberto Rosario
2016-05-17 17:02:00 -04:00
86 changed files with 1485 additions and 544 deletions

View File

@@ -1,6 +1,12 @@
2.1 (2016-XX)
=============
- Upgrade to use Django 1.8.8. Issue #246.
2.1.1 (2016-05-17)
==================
- Fix navigation issue that make it impossible to add new sources. GitLab issue #288.
- The Tesseract OCR backend now reports if the requested language file is missing. GitLab issue #289.
- Ensure the automatic default index is created after the default document type.
2.1 (2016-05-14)
================
- Upgrade to use Django 1.8.13. Issue #246.
- Upgrade requirements.
- Remove remaining references to Django's User model. GitLab issue #225
- Rename 'Content' search box to 'OCR'.
@@ -33,6 +39,8 @@
- Replace document type selection widget with an opened selection list.
- Add mailing documentation chapter.
- Add roadmap documentation chapter.
- API updates.
2.0.2 (2016-02-09)
==================

View File

@@ -59,8 +59,8 @@ Contribute
.. _`the repository`: http://gitlab.com/mayan-edms/mayan-edms
.. _`contributors file`: https://gitlab.com/mayan-edms/mayan-edms/blob/master/docs/topics/contributors.rst
.. |Build Status| image:: https://gitlab.com/ci/projects/6169/status.png?ref=master
:target: https://gitlab.com/ci/projects/6169?ref=master
.. |Build Status| image:: https://gitlab.com/mayan-edms/mayan-edms/badges/master/build.svg
:target: https://gitlab.com/mayan-edms/mayan-edms/commits/master
.. |Logo| image:: https://gitlab.com/mayan-edms/mayan-edms/raw/master/docs/_static/mayan_logo.png
.. |Animation| image:: https://gitlab.com/mayan-edms/mayan-edms/raw/master/docs/_static/overview.gif
.. |Installs badge| image:: http://img.shields.io/pypi/dm/mayan-edms.svg?style=flat

View File

@@ -18,7 +18,7 @@ sudo apt-get -qq update
sudo apt-get -y upgrade
echo -e "\n -> Installing core binaries \n"
sudo apt-get -y install git-core python-virtualenv gcc python-dev libjpeg-dev libpng-dev libtiff-dev tesseract-ocr poppler-utils unpaper libreoffice
sudo apt-get -y install git-core python-virtualenv gcc python-dev libjpeg-dev libpng-dev libtiff-dev tesseract-ocr poppler-utils libreoffice
echo -e "\n -> Cloning development branch of repository \n"
git clone /mayan-edms-repository/ $INSTALLATION_DIRECTORY

View File

@@ -20,7 +20,7 @@ apt-get -qq update
apt-get -y upgrade
echo -e "\n -> Installing core binaries \n"
apt-get install nginx supervisor redis-server postgresql libpq-dev libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv tesseract-ocr unpaper poppler-utils -y
apt-get install nginx supervisor redis-server postgresql libpq-dev libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv tesseract-ocr poppler-utils -y
echo -e "\n -> Setting up virtualenv \n"
rm -f ${INSTALLATION_DIRECTORY}

View File

@@ -27,7 +27,7 @@ update a lot of legacy HTML and CSS was removed, greatly simplifying the
existing template and allowing the removal of some.
Theming and re-branding
----------------------
-----------------------
All the presentation logic and markup has been moved into it's own app, the
'appearance' app. All modifications required to customize the entire look of
the Mayan EDMS can now be done in a single app. Very little markup remains
@@ -98,7 +98,7 @@ app are no longer required. These are:
* slate
ACL system re-factor
-------------------
--------------------
The Access Control System has been greatly simplified and optimized. The
logistics to grant and revoke permissions are now as follows: Only Roles can
hold permissions, groups and user can no longer on their own be granted a
@@ -135,7 +135,7 @@ support. Administrators wanting to make a group of documents public are
encouraged to create an user, group and role for that purpose.
Metadata validators re-factor
----------------------------
-----------------------------
The metadata validators have been split into: Validators and Parsers.
Validators will just check that the input value conforms to certain
specification, raising a validation error is not and blocking the user from
@@ -229,7 +229,7 @@ Support for allowing 3rd party apps to unbind links binded by the core apps
was added to further improve re-branding and customization.
Statistics re-factor
-------------------
--------------------
Statistics gathering and generation has been overhauled to allow for the
creation of scheduled statistics. This allows statistics computation to be
scheduled during low load times. A new management command was added to

87
docs/releases/2.1.1.rst Normal file
View File

@@ -0,0 +1,87 @@
===============================
Mayan EDMS v2.1.1 release notes
===============================
Released: May 17, 2016
What's new
==========
This is a bugfix release and all users are encouraged to upgrade.
Fix object column resolution issue in navigation app
----------------------------------------------------
Version 2.1 includes a navigation feature that allows model instances from a
queryset generated using the .defer() or .only() Django filter optimization
features to resolve to their parent class transparently. This optimization
caused problems with the sources app which uses a
Missing Tesseract language files
--------------------------------
The Tesseract OCR backend now reports if the tesseract language file is missing
for the requested document's language.
Other changes
-------------
- Ensure the automatic default index is created after the default document type.
Removals
--------
* None
Upgrading from a previous version
---------------------------------
Using PIP
~~~~~~~~~
Type in the console::
$ pip install -U mayan-edms
the requirements will also be updated automatically.
Using Git
~~~~~~~~~
If you installed Mayan EDMS by cloning the Git repository issue the commands::
$ git reset --hard HEAD
$ git pull
otherwise download the compressed archived and uncompress it overriding the
existing installation.
Next upgrade/add the new requirements::
$ pip install --upgrade -r requirements.txt
Common steps
~~~~~~~~~~~~
Migrate existing database schema with::
$ mayan-edms.py performupgrade
Add new static media::
$ mayan-edms.py collectstatic --noinput
The upgrade procedure is now complete.
Backward incompatible changes
=============================
* None
Bugs fixed or issues closed
===========================
* `GitLab issue #288 <https://gitlab.com/mayan-edms/mayan-edms/issues/288>`_ Can't add sources in mayan-edms 2.1.
* `GitLab issue #289 <https://gitlab.com/mayan-edms/mayan-edms/issues/289>`_ OCR fails with Exception.
.. _PyPI: https://pypi.python.org/pypi/mayan-edms/

View File

@@ -1,13 +1,13 @@
===============================
=============================
Mayan EDMS v2.1 release notes
===============================
=============================
Released: April, 2016
Released: May 14, 2016
What's new
==========
Upgrade to use Django 1.8.11
Upgrade to use Django 1.8.13
----------------------------
With the end of life support for Django 1.7, moving to the next Mayan EDMS
minor version was a target for this release. The Django minor release chosen was
@@ -33,13 +33,13 @@ Improve generation of success and error messages for class based views
----------------------------------------------------------------------
In the past success messages for actions would show a generic mention to the
object being manipulated (document, folder, tag). Now the errors and success
messages with be more explcit in describing what the view has or was trying
messages with be more explicit in describing what the view has or was trying
to manipulate.
Remove ownership concept from folders
-------------------------------------
Currently Folders in Mayan EDMS have a field that stores a reference to the
user that has created that folders. One of the design decissions of Mayan EDMS
user that has created that folders. One of the design decisions of Mayan EDMS
is that there should never be any explicit ownership of any object. Ownership
is relative and is defined by the Access Control List of an object. The
removal of the user field from the Folders model brings this app in line with
@@ -48,7 +48,7 @@ the defined behavior.
Replacement of strip_spaces middleware with the spaceless template tag
----------------------------------------------------------------------
As a size optimization technique HTML content was dynamically stripped of spaces
as it was being served. The techique used involved detecting the MIME type of
as it was being served. The technique used involved detecting the MIME type of
the content being served and if found to be of text/HTML type spaces between
tags were stripped. An edge case was found where this did not worked always.
The approached has been changed to use Django's official tag to strip spaces.
@@ -84,7 +84,13 @@ Fixed date locale handling in document properties, checkout and user detail view
A few releases back the ability to for users to set their timezone was added.
This change also included a smart date rendering update to adjust the dates
and times fields to the user's timezone. Some users reported a few views where
this timezone adjustment was not happeding, this has been fully fixed.
this timezone adjustment was not happening, this has been fully fixed.
Default index
-------------
During new installations a default index that organizes document by year/month
when they were uploaded will be created to help users better understand the
concept of indexes in Mayan EDMS.
HTML5 upload widget
-------------------
@@ -98,7 +104,7 @@ Message of the Day app
Administrators wanting to display announcements has no other way to do so
than to customize the login template. To avoid this a new app has been added
that allows for the creation of messages to be shown at the user login
screen. These messages can have an activation and an experiation date and
screen. These messages can have an activation and an expiration date and
time. These messages are useful for display company access policies,
maintenance announcement, etc.
@@ -112,7 +118,7 @@ if signed, verify the validity of the signature. However, to sign documents
user had to download the document, sign the document offline, and either
re-upload the signed document as a new version or upload a detached
signature for the existing document version. Aside from being now able to sign
documents from the web user iterface, the way keys are handled has been
documents from the web user interface, the way keys are handled has been
rewritten from scratch to support distributed key storage. This means that
a key uploaded in one computer by one user can be used transparently by
other users in other computers to sign documents. The relevant access control
@@ -136,6 +142,20 @@ Other changes
- Update Document model's uuid field to use Django's native UUIDField class.
- Add new split view index navigation
- Newly uploaded documents appear in the Recent document list of the user.
- Start migration from django-sendfile to django-downloadview.
- Index more model fields.
- Navigation system support querysets using .defer() or .only() optimizations.
- API fixes and improvements.
- Increase total test count to 311.
- Increase test coverage to 77%.
- Documentation improvements.
- Handle unicode filenames in staging folders.
- Add staging file deletion permission.
- New document_signature_view permission.
- Instead of multiple keyservers only one keyserver is now supported.
- Replace document type selection widget with an opened selection list.
- Add roadmap documentation chapter.
Removals
--------
@@ -190,11 +210,29 @@ Backward incompatible changes
Bugs fixed or issues closed
===========================
* `GitLab issue #137 <https://gitlab.com/mayan-edms/mayan-edms/issues/137>`_ Add app creation chapter to documentation.
* `GitLab issue #147 <https://gitlab.com/mayan-edms/mayan-edms/issues/147>`_ Add in app document signing.
* `GitLab issue #161 <https://gitlab.com/mayan-edms/mayan-edms/issues/161>`_ Email backend setup documentation.
* `GitLab issue #162 <https://gitlab.com/mayan-edms/mayan-edms/issues/162>`_ Add HTML5 file uploader.
* `GitLab issue #191 <https://gitlab.com/mayan-edms/mayan-edms/issues/191>`_ Split index contents title into title and path/breadcrumb widget.
* `GitLab issue #206 <https://gitlab.com/mayan-edms/mayan-edms/issues/206>`_ Support for dynamic LOGIN_EXEMPT_URLS.
* `GitLab issue #208 <https://gitlab.com/mayan-edms/mayan-edms/issues/208>`_ Add tagging step to upload wizard.
* `GitLab issue #218 <https://gitlab.com/mayan-edms/mayan-edms/issues/218>`_ Cookie cutter template for Mayan apps.
* `GitLab issue #222 <https://gitlab.com/mayan-edms/mayan-edms/issues/222>`_ Add notice board or Message of the Day.
* `GitLab issue #225 <https://gitlab.com/mayan-edms/mayan-edms/issues/225>`_ Remove hard coded User model.
* `GitLab issue #232 <https://gitlab.com/mayan-edms/mayan-edms/issues/232>`_ "Create documents" is a blanket permission for a user to create a document of any document type.
* `GitLab issue #246 <https://gitlab.com/mayan-edms/mayan-edms/issues/246>`_ Upgrade to Django version 1.8 as Django 1.7 is end-of-life.
* `GitLab issue #251 <https://gitlab.com/mayan-edms/mayan-edms/issues/251>`_ Add method to disable metadata edit form "update" checkbox when not needed.
* `GitLab issue #255 <https://gitlab.com/mayan-edms/mayan-edms/issues/255>`_ UnicodeDecodeError in apps/common/middleware/strip_spaces_widdleware.py.
* `GitLab issue #256 <https://gitlab.com/mayan-edms/mayan-edms/issues/256>`_ typo in locale settings (Dutch).
* `GitLab issue #261 <https://gitlab.com/mayan-edms/mayan-edms/issues/261>`_ Feature: Document Access Audit Logging.
* `GitLab issue #265 <https://gitlab.com/mayan-edms/mayan-edms/issues/265>`_ Indexes show list (show indexe only if the user has ACLs on document type).
* `GitLab issue #266 <https://gitlab.com/mayan-edms/mayan-edms/issues/266>`_ Smart links : Dynamic label with Postgresql.
* `GitLab issue #267 <https://gitlab.com/mayan-edms/mayan-edms/issues/267>`_ Release 2.1 RC1 : Notes and ideas.
* `GitLab issue #268 <https://gitlab.com/mayan-edms/mayan-edms/issues/268>`_ Release 2.1 RC1 : Bug to access inside an indexes.
* `GitLab issue #270 <https://gitlab.com/mayan-edms/mayan-edms/issues/270>`_ Release 2.1 RC1 : Bug statistics.
* `GitLab issue #274 <https://gitlab.com/mayan-edms/mayan-edms/issues/274>`_ [Release 2.1 RC2] Web Tests.
* `GitLab issue #275 <https://gitlab.com/mayan-edms/mayan-edms/issues/275>`_ [Release 2.1 RC2] Notes.
* `GitLab issue #276 <https://gitlab.com/mayan-edms/mayan-edms/issues/276>`_ [Release 2.1 RC2] API Tests.
.. _PyPI: https://pypi.python.org/pypi/mayan-edms/

View File

@@ -22,9 +22,11 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1
2.0
2.0.1
2.1.1
2.1
2.0.2
2.0.1
2.0
1.0 series
----------

View File

@@ -17,6 +17,7 @@ Introductions to all the key parts of Mayan EDMS you'll need to know:
signatures
ocr_backend
indexes
languages
smart_links
tags
mailing

19
docs/topics/languages.rst Normal file
View File

@@ -0,0 +1,19 @@
=========
Languages
=========
The list of languages choices in the language dropdown used for documents is
based on the current ISO 639 list. This list can be quite extensive. To reduce
the number of languages available use the settings ``DOCUMENTS_LANGUAGE_CHOICES``,
and set it to a nested list of abbreviations + languages names like::
DOCUMENTS_LANGUAGE_CHOICES = (('eng', 'English'), ('spa', 'Spanish'))
The default language to appear on the dropdown can also be configured using::
DOCUMENTS_LANGUAGE = 'spa'
Use the correct ISO 639-3 language abbreviation (https://en.wikipedia.org/wiki/ISO_639)
as this code is used in several subsystems in Mayan EDMS such as the OCR app
to determine how to interpret the document.

View File

@@ -1,10 +1,10 @@
from __future__ import unicode_literals
__title__ = 'Mayan EDMS'
__version__ = '2.1rc2'
__build__ = 0x020100
__version__ = '2.1.1'
__build__ = 0x020101
__author__ = 'Roberto Rosario'
__author_email__ = 'roberto.rosario@mayan-edms.com'
__description__ = 'Free Open Source Electronic Document Management System'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2011-2015 Roberto Rosario'
__copyright__ = 'Copyright 2011-2016 Roberto Rosario'

View File

@@ -23,8 +23,9 @@ def get_kwargs_factory(variable_name):
link_acl_delete = Link(
permissions=(permission_acl_edit,), tags='dangerous', text=_('Delete'),
view='acls:acl_delete', args='resolved_object.pk'
permissions=(permission_acl_edit,), permissions_related='content_object',
tags='dangerous', text=_('Delete'), view='acls:acl_delete',
args='resolved_object.pk'
)
link_acl_list = Link(
permissions=(permission_acl_view,), text=_('ACLs'), view='acls:acl_list',
@@ -35,6 +36,7 @@ link_acl_create = Link(
view='acls:acl_create', kwargs=get_kwargs_factory('resolved_object')
)
link_acl_permissions = Link(
permissions=(permission_acl_edit,), text=_('Permissions'),
view='acls:acl_permissions', args='resolved_object.pk'
permissions=(permission_acl_edit,), permissions_related='content_object',
text=_('Permissions'), view='acls:acl_permissions',
args='resolved_object.pk'
)

View File

@@ -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:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:09-0400\n"
"PO-Revision-Date: 2016-03-21 21:03+0000\n"
"PO-Revision-Date: 2016-05-09 01:48+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:14 links.py:30
@@ -31,6 +30,7 @@ msgid "Permissions"
msgstr "Permisos"
#: apps.py:26 models.py:38
#| msgid "Roles"
msgid "Role"
msgstr "Rol"
@@ -39,6 +39,7 @@ msgid "Delete"
msgstr "Borrar"
#: links.py:34
#| msgid "View ACLs"
msgid "New ACL"
msgstr "Nueva LCA"
@@ -77,8 +78,9 @@ msgstr "Nueva lista de control de acceso para: %s"
#: views.py:109
#, python-format
#| msgid "Default ACLs"
msgid "Delete ACL: %s"
msgstr ""
msgstr "Borrar LCA: %s"
#: views.py:151
#, python-format
@@ -196,10 +198,8 @@ msgstr "Los permisos inactivos se heredan de un objeto precedente."
#~ msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgid ""
#~ "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgstr ""
#~ "%(actor)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 "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgid "Add new holder for: %s"
#~ msgstr "add new holder for: %s"

View File

@@ -45,7 +45,11 @@ class AccessControlList(models.Model):
verbose_name_plural = _('Access entries')
def __str__(self):
return '{} <=> {}'.format(self.content_object, self.role)
return _('Permissions "%(permissions)s" to role "%(role)s" for "%(object)s"') % {
'permissions': self.get_permission_titles(),
'object': self.content_object,
'role': self.role
}
def get_inherited_permissions(self):
return AccessControlList.objects.get_inherited_permissions(

View File

@@ -0,0 +1,103 @@
from __future__ import unicode_literals
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from documents.tests.test_views import GenericDocumentViewTestCase
from user_management.tests.literals import (
TEST_USER_PASSWORD, TEST_USER_USERNAME
)
from ..links import (
link_acl_delete, link_acl_list, link_acl_create, link_acl_permissions
)
from ..models import AccessControlList
from ..permissions import permission_acl_edit, permission_acl_view
class ACLsLinksTestCase(GenericDocumentViewTestCase):
def test_document_acl_create_link(self):
acl = AccessControlList.objects.create(
content_object=self.document, role=self.role
)
acl.permissions.add(permission_acl_edit.stored_permission)
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
self.add_test_view(test_object=self.document)
context = self.get_test_view()
resolved_link = link_acl_create.resolve(context=context)
self.assertNotEqual(resolved_link, None)
content_type = ContentType.objects.get_for_model(self.document)
kwargs = {
'app_label': content_type.app_label,
'model': content_type.model,
'object_id': self.document.pk
}
self.assertEqual(
resolved_link.url, reverse('acls:acl_create', kwargs=kwargs)
)
def test_document_acl_delete_link(self):
acl = AccessControlList.objects.create(
content_object=self.document, role=self.role
)
acl.permissions.add(permission_acl_edit.stored_permission)
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
self.add_test_view(test_object=acl)
context = self.get_test_view()
resolved_link = link_acl_delete.resolve(context=context)
self.assertNotEqual(resolved_link, None)
self.assertEqual(
resolved_link.url, reverse('acls:acl_delete', args=(acl.pk,))
)
def test_document_acl_edit_link(self):
acl = AccessControlList.objects.create(
content_object=self.document, role=self.role
)
acl.permissions.add(permission_acl_edit.stored_permission)
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
self.add_test_view(test_object=acl)
context = self.get_test_view()
resolved_link = link_acl_permissions.resolve(context=context)
self.assertNotEqual(resolved_link, None)
self.assertEqual(
resolved_link.url, reverse('acls:acl_permissions', args=(acl.pk,))
)
def test_document_acl_list_link(self):
acl = AccessControlList.objects.create(
content_object=self.document, role=self.role
)
acl.permissions.add(permission_acl_view.stored_permission)
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
self.add_test_view(test_object=self.document)
context = self.get_test_view()
resolved_link = link_acl_list.resolve(context=context)
self.assertNotEqual(resolved_link, None)
content_type = ContentType.objects.get_for_model(self.document)
kwargs = {
'app_label': content_type.app_label,
'model': content_type.model,
'object_id': self.document.pk
}
self.assertEqual(
resolved_link.url, reverse('acls:acl_list', kwargs=kwargs)
)

View File

@@ -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:
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:09-0400\n"
"PO-Revision-Date: 2016-03-21 21:06+0000\n"
"PO-Revision-Date: 2016-05-09 01:48+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:11
@@ -45,8 +44,8 @@ msgstr "Error de servidor"
#: templates/500.html:11
msgid ""
"There's been an error. It's been reported to the site administrators via e-"
"mail and should be fixed shortly. Thanks for your patience."
"There's been an error. It's been reported to the site administrators via "
"e-mail and should be fixed shortly. Thanks for your patience."
msgstr ""
#: templates/500.html:14
@@ -138,7 +137,7 @@ msgstr "Confirmar eliminación"
#: templates/appearance/generic_confirm.html:27
#, python-format
msgid "Delete: %(object)s?"
msgstr ""
msgstr "¿Borrar: %(object)s?"
#: templates/appearance/generic_confirm.html:47
msgid "Yes"
@@ -181,9 +180,7 @@ msgstr "Ningún resultado"
msgid ""
"Total (%(start)s - %(end)s out of %(total)s) (Page %(page_number)s of "
"%(total_pages)s)"
msgstr ""
"Total (%(start)s - %(end)s de %(total)s) (Página %(page_number)s de "
"%(total_pages)s)"
msgstr "Total (%(start)s - %(end)s de %(total)s) (Página %(page_number)s de %(total_pages)s)"
#: templates/appearance/generic_list_subtemplate.html:14
#: templates/appearance/generic_list_subtemplate.html:17
@@ -231,8 +228,7 @@ msgstr "Primer inicio de sesión"
msgid ""
"You have just finished installing <strong>Mayan EDMS</strong>, "
"congratulations!"
msgstr ""
"!Felicitaciones! Acaba de terminar de instalar <strong>Mayan EDMS</strong>"
msgstr "!Felicitaciones! Acaba de terminar de instalar <strong>Mayan EDMS</strong>"
#: templates/appearance/login.html:25
msgid "Login using the following credentials:"
@@ -257,9 +253,7 @@ msgstr "Contraseña: <strong>%(password)s</strong>"
msgid ""
"Be sure to change the password to increase security and to disable this "
"message."
msgstr ""
"Asegúrese de cambiar su contraseña para aumentar la seguridad y para "
"desactivar este mensaje"
msgstr "Asegúrese de cambiar su contraseña para aumentar la seguridad y para desactivar este mensaje"
#: templates/appearance/login.html:45 templates/appearance/login.html.py:54
msgid "Sign in"

View File

@@ -0,0 +1,12 @@
/*
* jquery-match-height 0.7.0 by @liabru
* http://brm.io/jquery-match-height/
* License MIT
*/
!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){var e=-1,o=-1,i=function(t){return parseFloat(t)||0},a=function(e){var o=1,a=t(e),n=null,r=[];return a.each(function(){var e=t(this),a=e.offset().top-i(e.css("margin-top")),s=r.length>0?r[r.length-1]:null;null===s?r.push(e):Math.floor(Math.abs(n-a))<=o?r[r.length-1]=s.add(e):r.push(e),n=a}),r},n=function(e){var o={
byRow:!0,property:"height",target:null,remove:!1};return"object"==typeof e?t.extend(o,e):("boolean"==typeof e?o.byRow=e:"remove"===e&&(o.remove=!0),o)},r=t.fn.matchHeight=function(e){var o=n(e);if(o.remove){var i=this;return this.css(o.property,""),t.each(r._groups,function(t,e){e.elements=e.elements.not(i)}),this}return this.length<=1&&!o.target?this:(r._groups.push({elements:this,options:o}),r._apply(this,o),this)};r.version="0.7.0",r._groups=[],r._throttle=80,r._maintainScroll=!1,r._beforeUpdate=null,
r._afterUpdate=null,r._rows=a,r._parse=i,r._parseOptions=n,r._apply=function(e,o){var s=n(o),h=t(e),l=[h],c=t(window).scrollTop(),p=t("html").outerHeight(!0),d=h.parents().filter(":hidden");return d.each(function(){var e=t(this);e.data("style-cache",e.attr("style"))}),d.css("display","block"),s.byRow&&!s.target&&(h.each(function(){var e=t(this),o=e.css("display");"inline-block"!==o&&"flex"!==o&&"inline-flex"!==o&&(o="block"),e.data("style-cache",e.attr("style")),e.css({display:o,"padding-top":"0",
"padding-bottom":"0","margin-top":"0","margin-bottom":"0","border-top-width":"0","border-bottom-width":"0",height:"100px",overflow:"hidden"})}),l=a(h),h.each(function(){var e=t(this);e.attr("style",e.data("style-cache")||"")})),t.each(l,function(e,o){var a=t(o),n=0;if(s.target)n=s.target.outerHeight(!1);else{if(s.byRow&&a.length<=1)return void a.css(s.property,"");a.each(function(){var e=t(this),o=e.attr("style"),i=e.css("display");"inline-block"!==i&&"flex"!==i&&"inline-flex"!==i&&(i="block");var a={
display:i};a[s.property]="",e.css(a),e.outerHeight(!1)>n&&(n=e.outerHeight(!1)),o?e.attr("style",o):e.css("display","")})}a.each(function(){var e=t(this),o=0;s.target&&e.is(s.target)||("border-box"!==e.css("box-sizing")&&(o+=i(e.css("border-top-width"))+i(e.css("border-bottom-width")),o+=i(e.css("padding-top"))+i(e.css("padding-bottom"))),e.css(s.property,n-o+"px"))})}),d.each(function(){var e=t(this);e.attr("style",e.data("style-cache")||null)}),r._maintainScroll&&t(window).scrollTop(c/p*t("html").outerHeight(!0)),
this},r._applyDataApi=function(){var e={};t("[data-match-height], [data-mh]").each(function(){var o=t(this),i=o.attr("data-mh")||o.attr("data-match-height");i in e?e[i]=e[i].add(o):e[i]=o}),t.each(e,function(){this.matchHeight(!0)})};var s=function(e){r._beforeUpdate&&r._beforeUpdate(e,r._groups),t.each(r._groups,function(){r._apply(this.elements,this.options)}),r._afterUpdate&&r._afterUpdate(e,r._groups)};r._update=function(i,a){if(a&&"resize"===a.type){var n=t(window).width();if(n===e)return;e=n;
}i?-1===o&&(o=setTimeout(function(){s(a),o=-1},r._throttle)):s(a)},t(r._applyDataApi),t(window).bind("load",function(t){r._update(!1,t)}),t(window).bind("resize orientationchange",function(t){r._update(!0,t)})});

View File

@@ -1,6 +1,7 @@
{% extends 'appearance/base.html' %}
{% load i18n %}
{% load static %}
{% load navigation_tags %}
@@ -24,3 +25,12 @@
</div>
{% endblock %}
{% block javascript %}
<script type="text/javascript" src="{% static 'appearance/packages/jquery.matchHeight-min.js' %}"></script>
<script type="text/javascript">
$(function() {
$('.btn-block').matchHeight();
});
</script>
{% endblock %}

View File

@@ -1,25 +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.
#
#
# Translators:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# jmcainzos <jmcainzos@vodafone.es>, 2015
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:10-0400\n"
"PO-Revision-Date: 2016-03-21 21:08+0000\n"
"PO-Revision-Date: 2016-05-09 01:42+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:72 settings.py:9
@@ -59,7 +59,7 @@ msgstr ""
#: generics.py:299
#, python-format
msgid "%(object)s created successfully."
msgstr ""
msgstr "%(object)s creado con éxito."
#: generics.py:324
#, python-format
@@ -69,7 +69,7 @@ msgstr ""
#: generics.py:335
#, python-format
msgid "%(object)s deleted successfully."
msgstr ""
msgstr "%(object)s borrado con éxito."
#: generics.py:380
#, python-format
@@ -79,7 +79,7 @@ msgstr ""
#: generics.py:391
#, python-format
msgid "%(object)s updated successfully."
msgstr ""
msgstr "%(object)s actualizado con éxito."
#: links.py:9
msgid "About"
@@ -178,20 +178,18 @@ msgid "User locale profiles"
msgstr "Perfiles de localización de usuario"
#: settings.py:13
#| msgid ""
#| "ary directory used site wide to store thumbnails, previews and porary es. "
#| "If none is specified, one will be created using pfile.mkdtemp()"
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 ""
"El directorio temporaro es el utilizado por todo el proyecto para almacenar "
"miniaturas, previsualizaciones y los archivos temporales. Si no se "
"especifica ninguno, se creará utilizando tempfile.mkdtemp ()."
"temporary files. If none is specified, one will be created using "
"tempfile.mkdtemp()."
msgstr "El directorio temporaro es el utilizado por todo el proyecto para almacenar miniaturas, previsualizaciones y los archivos temporales. Si no se especifica ninguno, se creará utilizando tempfile.mkdtemp ()."
#: settings.py:22
msgid "A storage backend that all workers can use to share files."
msgstr ""
"Un soporte de almacenamiento que todos los 'workers' puedan utilizar para "
"compartir archivos."
msgstr "Un soporte de almacenamiento que todos los 'workers' puedan utilizar para compartir archivos."
#: settings.py:28
msgid "An integer specifying how many objects should be displayed per page."
@@ -203,7 +201,8 @@ msgstr ""
#: settings.py:40
msgid ""
"Time to delay background tasks that depend on a database commit to propagate."
"Time to delay background tasks that depend on a database commit to "
"propagate."
msgstr ""
#: views.py:37
@@ -223,6 +222,7 @@ msgid "Edit current user locale profile details"
msgstr "Editar los detalles del perfil del usuario local"
#: views.py:113
#| msgid "Selection"
msgid "Filter selection"
msgstr ""
@@ -232,6 +232,7 @@ msgid "Results for filter: %s"
msgstr ""
#: views.py:136
#| msgid "Page not found"
msgid "Filter not found"
msgstr "Filtro no encontrado"
@@ -285,11 +286,11 @@ msgstr "Ninguno"
#~ msgstr "Email"
#~ msgid ""
#~ "Please enter a correct email and password. Note that the password field "
#~ "is case-sensitive."
#~ "Please enter a correct email and password. Note that the password field is "
#~ "case-sensitive."
#~ msgstr ""
#~ "Please enter a correct email and password. Note that the password fields "
#~ "is case-sensitive."
#~ "Please enter a correct email and password. Note that the password fields is "
#~ "case-sensitive."
#~ msgid "This account is inactive."
#~ msgstr "This account is inactive."
@@ -298,11 +299,11 @@ msgstr "Ninguno"
#~ msgstr "change password"
#~ msgid ""
#~ "Controls the mechanism used to authenticated user. Options are: "
#~ "username, email"
#~ "Controls the mechanism used to authenticated user. Options are: username, "
#~ "email"
#~ msgstr ""
#~ "Controls the mechanism used to authenticated user. Options are: "
#~ "username, email"
#~ "Controls the mechanism used to authenticated user. Options are: username, "
#~ "email"
#~ msgid "Allow non authenticated users, access to all views"
#~ msgstr "Allow non authenticated users, access to all views"

View File

@@ -9,7 +9,7 @@ class Command(management.BaseCommand):
help = 'Performs the required steps after a version upgrade.'
def handle(self, *args, **options):
management.call_command('migrate', interactive=False)
management.call_command('migrate', fake_initial=True, interactive=False)
management.call_command('purgeperiodictasks', interactive=False)
perform_upgrade.send(sender=self)
post_upgrade.send(sender=self)

View File

@@ -33,13 +33,13 @@ class CurrentUserDetailsView(SingleObjectDetailView):
def get_extra_context(self, **kwargs):
return {
'object': self.get_object(),
'object': None,
'title': _('Current user details'),
}
class CurrentUserEditView(SingleObjectEditView):
extra_context = {'title': _('Edit current user details')}
extra_context = {'object': None, 'title': _('Edit current user details')}
form_class = UserForm
post_action_redirect = reverse_lazy('common:current_user_details')

View File

@@ -1,24 +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:
# Translators:
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:10-0400\n"
"PO-Revision-Date: 2016-03-21 21:06+0000\n"
"PO-Revision-Date: 2016-05-09 01:47+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:18 permissions.py:7 settings.py:7
@@ -40,16 +39,17 @@ msgstr "Argumentos"
#: backends/python.py:87 backends/python.py:101
#, python-format
msgid "Exception determining PDF page count; %s"
msgstr ""
msgstr "Excepción determinando el número de páginas del PDF; %s"
#: classes.py:98
#| msgid "suported file formats"
msgid "Not an office file format."
msgstr ""
msgstr "No es un formato de archivo de la oficina."
#: classes.py:121
#, python-format
msgid "LibreOffice not installed or not found at path: %s"
msgstr ""
msgstr "LibreOffice no instalado o no encontrado en: %s"
#: classes.py:254
msgid "Resize"
@@ -65,7 +65,7 @@ msgstr "Ampliar"
#: classes.py:324
msgid "Crop"
msgstr ""
msgstr "Recortar"
#: links.py:31
msgid "Create new transformation"
@@ -87,7 +87,7 @@ msgstr "Transformaciones"
msgid ""
"Order in which the transformations will be executed. If left unchanged, an "
"automatic order value will be assigned."
msgstr ""
msgstr "Orden de ejecución de las transformaciones. Si lo deja en blanco, un valor de orden sera asignado automáticamente. "
#: models.py:38
msgid "Name"
@@ -97,7 +97,7 @@ msgstr "Nombre"
msgid ""
"Enter the arguments for the transformation as a YAML dictionary. ie: "
"{\"degrees\": 180}"
msgstr ""
msgstr "Entre el argumento de la transformación como un diccionario YAML. Ejemplo: {\"degrees\": 180}"
#: permissions.py:10
msgid "Create new transformations"
@@ -112,12 +112,13 @@ msgid "Edit transformations"
msgstr "Editar transformaciones"
#: permissions.py:19
#| msgid "Raw application information"
msgid "View existing transformations"
msgstr "Ver transformaciones existentes"
#: settings.py:10
msgid "Graphics conversion backend to use."
msgstr ""
msgstr "Módulo de conversión de gráficos a ser usado."
#: settings.py:16
msgid "Path to the libreoffice program."
@@ -129,12 +130,12 @@ msgstr "Ruta al programa pdftoppm de Poppler."
#: validators.py:22
msgid "Enter a valid YAML value."
msgstr ""
msgstr "Entre un valor YAML."
#: views.py:71
#, python-format
msgid "Delete transformation \"%(transformation)s\" for: %(content_object)s?"
msgstr ""
msgstr "¿Borrar transformación \"%(transformation)s\" para: %(content_object)s?"
#: views.py:139
#, python-format
@@ -188,13 +189,14 @@ msgstr "Transformaciones para: %s"
#~ msgstr "File path to graphicsmagick's program."
#~ msgid ""
#~ "Graphics conversion backend to use. Options are: converter.backends."
#~ "imagemagick.ImageMagick, converter.backends.graphicsmagick.GraphicsMagick "
#~ "and converter.backends.python.Python"
#~ "Graphics conversion backend to use. Options are: "
#~ "converter.backends.imagemagick.ImageMagick, "
#~ "converter.backends.graphicsmagick.GraphicsMagick and "
#~ "converter.backends.python.Python"
#~ msgstr ""
#~ "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."
#~ msgid "Help"
#~ msgstr "Help"
@@ -507,11 +509,9 @@ msgstr "Transformaciones para: %s"
#~ msgstr "Magick Image File Format"
#~ msgid ""
#~ "Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib "
#~ "1.2.3.3,1.2.3.4)"
#~ "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)"
#~ "Multiple-image Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
#~ msgid "Raw Bi-level bitmap in least-significant-byte first order"
#~ msgstr "Raw Bi-level bitmap in least-significant-byte first order"
@@ -627,8 +627,7 @@ msgstr "Transformaciones para: %s"
#~ msgid "Joint Photographic Experts Group JFIF format (62)"
#~ msgstr "Joint Photographic Experts Group JFIF format (62)"
#~ msgid ""
#~ "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
#~ 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)"

View File

@@ -6,12 +6,13 @@
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:10-0400\n"
"PO-Revision-Date: 2016-04-27 18:22+0000\n"
"PO-Revision-Date: 2016-05-09 01:46+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/language/es/)\n"
"MIME-Version: 1.0\n"
@@ -22,7 +23,7 @@ msgstr ""
#: apps.py:30
msgid "Django GPG"
msgstr ""
msgstr "Django GPG"
#: apps.py:73 apps.py:76 forms.py:17
msgid "Key ID"
@@ -30,7 +31,7 @@ msgstr "Identificador de clave"
#: apps.py:74 apps.py:87 forms.py:19 models.py:67
msgid "User ID"
msgstr ""
msgstr "ID de usuario"
#: apps.py:77 forms.py:34 models.py:70
msgid "Type"
@@ -46,7 +47,7 @@ msgstr "Fecha de expiración"
#: apps.py:83
msgid "No expiration"
msgstr ""
msgstr "No expira"
#: apps.py:85 forms.py:32 models.py:62
msgid "Length"
@@ -58,11 +59,11 @@ msgstr "Ninguno"
#: forms.py:31 models.py:59
msgid "Fingerprint"
msgstr ""
msgstr "Huella"
#: forms.py:33 models.py:65
msgid "Algorithm"
msgstr ""
msgstr "Algoritmo"
#: forms.py:47
msgid "Term"
@@ -99,7 +100,7 @@ msgstr "Gestión de claves"
#: links.py:37
#| msgid "Import key"
msgid "Upload key"
msgstr ""
msgstr "Subir llave"
#: links.py:41 views.py:160
msgid "Private keys"
@@ -155,28 +156,28 @@ msgstr "El documento ha sido firmado y la firma ha sido validada."
#: models.py:47
msgid "ASCII armored version of the key."
msgstr ""
msgstr "Versión ASCII de la llave"
#: models.py:48
msgid "Key data"
msgstr ""
msgstr "Datos de llave"
#: models.py:76
#| msgid "Key ID"
msgid "Key"
msgstr ""
msgstr "Llave"
#: models.py:77
msgid "Keys"
msgstr ""
msgstr "Llaves"
#: models.py:86
msgid "Invalid key data"
msgstr ""
msgstr "Datos de llave invalidos"
#: models.py:89
msgid "Key already exists."
msgstr ""
msgstr "Llave ya existe."
#: permissions.py:10
msgid "Delete keys"
@@ -184,7 +185,7 @@ msgstr "Borrar claves"
#: permissions.py:13
msgid "Download keys"
msgstr ""
msgstr "Descargar llaves"
#: permissions.py:16
msgid "Import keys from keyservers"
@@ -192,12 +193,12 @@ msgstr "Importar llaves del servidores de claves"
#: permissions.py:19
msgid "Use keys to sign content"
msgstr ""
msgstr "Usar llaves para firmar contenido"
#: permissions.py:22
#| msgid "public keys"
msgid "Upload keys"
msgstr ""
msgstr "Subir llaves"
#: permissions.py:25
msgid "View keys"
@@ -219,24 +220,24 @@ msgstr "Ruta al binario GPG."
#: settings.py:25
#| msgid "List of keyservers to be queried for unknown keys."
msgid "Keyserver used to query for keys."
msgstr ""
msgstr "Servidor usado para buscar llaves."
#: views.py:38
#, python-format
#| msgid "Delete keys"
msgid "Delete key: %s"
msgstr ""
msgstr "Borrar llave: %s"
#: views.py:48
#, python-format
msgid "Details for key: %s"
msgstr ""
msgstr "Detalles para llave: %s"
#: views.py:68
#, python-format
#| msgid "Import key"
msgid "Import key ID: %s?"
msgstr ""
msgstr "¿Importar llave: %s?"
#: views.py:69
msgid "Import key"
@@ -246,12 +247,12 @@ msgstr "Importar clave"
#, python-format
#| msgid "Unable to import key id: %(key_id)s; %(error)s"
msgid "Unable to import key: %(key_id)s; %(error)s"
msgstr ""
msgstr "No se pudo importar la llave: %(key_id)s; %(error)s "
#: views.py:85
#, python-format
msgid "Successfully received key: %(key_id)s"
msgstr ""
msgstr "Llave: %(key_id)s, recibida con éxito"
#: views.py:107
msgid "Search"
@@ -263,11 +264,11 @@ msgstr "Consultar servidor de claves"
#: views.py:119
msgid "Key query results"
msgstr ""
msgstr "Resultado de búsqueda de llaves"
#: views.py:138
msgid "Upload new key"
msgstr ""
msgstr "Subir una nueva llave"
#~ msgid "Unknown"
#~ msgstr "unknown"

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_gpg', '0005_remove_key_key_id'),
]
operations = [
migrations.AlterField(
model_name='key',
name='key_data',
field=models.TextField(help_text='ASCII armored version of the key.', verbose_name='Key data'),
),
]

View File

@@ -16,14 +16,15 @@ from common import (
)
from common.classes import Package
from common.widgets import two_state_template
from documents.signals import post_document_created
from documents.signals import post_document_created, post_initial_document_type
from mayan.celery import app
from navigation import SourceColumn
from rest_api.classes import APIEndPoint
from .handlers import (
document_created_index_update, document_index_delete,
document_metadata_index_update, document_metadata_index_post_delete
document_created_index_update, create_default_document_index,
document_index_delete, document_metadata_index_update,
document_metadata_index_post_delete
)
from .links import (
link_document_index_list, link_index_main_menu, link_index_setup,
@@ -54,6 +55,10 @@ class DocumentIndexingApp(MayanAppConfig):
app_label='documents', model_name='Document'
)
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
)
DocumentMetadata = apps.get_model(
app_label='metadata', model_name='DocumentMetadata'
)
@@ -232,6 +237,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
document_created_index_update,
dispatch_uid='document_created_index_update', sender=Document
)
post_initial_document_type.connect(
create_default_document_index,
dispatch_uid='create_default_document_index', sender=DocumentType
)
post_save.connect(
document_metadata_index_update,
dispatch_uid='document_metadata_index_update',

View File

@@ -1,8 +1,36 @@
from __future__ import unicode_literals
from django.apps import apps
from django.utils.translation import ugettext_lazy as _
from .tasks import task_delete_empty_index_nodes, task_index_document
def create_default_document_index(sender, **kwargs):
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
)
Index = apps.get_model(
app_label='document_indexing', model_name='Index'
)
index = Index.objects.create(
label=_('Creation date'), slug='creation_date'
)
for document_type in DocumentType.objects.all():
index.document_types.add(document_type)
root_template_node = index.template_root
node = root_template_node.get_children().create(
expression='{{ document.date_added|date:"Y" }}', index=index,
parent=root_template_node
)
node.get_children().create(
expression='{{ document.date_added|date:"m" }}',
index=index, link_documents=True, parent=node
)
def document_created_index_update(sender, **kwargs):
task_index_document.apply_async(
kwargs=dict(document_id=kwargs['instance'].pk)

View File

@@ -1,24 +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:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:11-0400\n"
"PO-Revision-Date: 2016-03-21 21:09+0000\n"
"PO-Revision-Date: 2016-05-09 01:48+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: admin.py:24
@@ -30,6 +30,7 @@ msgid "Document types"
msgstr "Tipos de documento"
#: apps.py:48
#| msgid "document indexes"
msgid "Document indexing"
msgstr ""
@@ -39,7 +40,7 @@ msgstr "Etiqueta"
#: apps.py:121 models.py:30
msgid "Slug"
msgstr ""
msgstr "Identificador"
#: apps.py:123 apps.py:143 models.py:38 models.py:126
msgid "Enabled"
@@ -99,19 +100,17 @@ msgstr "nuevo nodo secundario"
msgid ""
"Error indexing document: %(document)s; expression: %(expression)s; "
"%(exception)s"
msgstr ""
"Error indexando documento: %(document)s; expresión: %(expression)s; "
"%(exception)s"
msgstr "Error indexando documento: %(document)s; expresión: %(expression)s; %(exception)s"
#: models.py:29
#| msgid "Internal name used to reference this index."
msgid "This values will be used by other apps to reference this index."
msgstr ""
#: models.py:35
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."
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:82 models.py:109
msgid "Index"
@@ -137,17 +136,13 @@ msgstr "expresión de indexación"
#: models.py:123
msgid "Causes this node to be visible and updated when document data changes."
msgstr ""
"Hace que este nodo sea visible y actualizado cuando los datos de los "
"documentos son cambiados."
msgstr "Hace que este nodo sea visible y actualizado cuando los datos de los documentos son cambiados."
#: models.py:131
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 actúe como un contenedor de documentos y "
"no como un padre para otros nodos secundarios."
"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 actúe como un contenedor de documentos y no como un padre para otros nodos secundarios."
#: models.py:134
msgid "Link documents"
@@ -219,8 +214,9 @@ msgstr "Generar índices de documentos"
#: views.py:51
#, python-format
#| msgid "Delete document indexes"
msgid "Delete the index: %s?"
msgstr ""
msgstr "¿Borrar el indice: %s?"
#: views.py:64
#, python-format
@@ -229,7 +225,7 @@ msgstr "Editar índice: %s"
#: views.py:81
msgid "Available document types"
msgstr ""
msgstr "Tipos de documentos disponibles"
#: views.py:83
msgid "Document types linked"
@@ -263,7 +259,7 @@ msgstr ""
#: views.py:286
#, python-format
msgid "Navigation: %s"
msgstr ""
msgstr "Navegación: %s"
#: views.py:291
#, python-format
@@ -277,9 +273,7 @@ msgstr ""
#: views.py:341
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."
msgstr "En bases de datos de gran tamaño esta operación puede tardar algún tiempo en ejecutarse."
#: views.py:342
msgid "Rebuild all indexes?"
@@ -350,11 +344,9 @@ msgstr "Reconstrucción de Índices en espera de forma exitosa."
#~ msgstr "Maximum suffix (%s) count reached."
#~ msgid ""
#~ "Error in document indexing update expression: %(expression)s; "
#~ "%(exception)s"
#~ "Error in document indexing update expression: %(expression)s; %(exception)s"
#~ msgstr ""
#~ "Error in document indexing update expression: %(expression)s; "
#~ "%(exception)s"
#~ "Error in document indexing update expression: %(expression)s; %(exception)s"
#~ msgid "Unable to delete document indexing node; %s"
#~ msgstr "Unable to delete document indexing node; %s"
@@ -391,11 +383,11 @@ msgstr "Reconstrucción de Índices en espera de forma exitosa."
#~ msgstr "documents rename count"
#~ 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 ""
#~ "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."
#~ msgid "Index rebuild error: %s"
#~ msgstr "Index rebuild error: %s"

View File

@@ -7,13 +7,13 @@
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2012,2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:11-0400\n"
"PO-Revision-Date: 2016-04-27 18:23+0000\n"
"PO-Revision-Date: 2016-05-09 01:19+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/language/es/)\n"
"MIME-Version: 1.0\n"
@@ -38,7 +38,7 @@ msgstr "Identificador de clave"
#: apps.py:98 forms.py:71 models.py:41
#| msgid "Signature ID: %s"
msgid "Signature ID"
msgstr ""
msgstr "ID de firma"
#: apps.py:99 forms.py:83
msgid "None"
@@ -50,64 +50,64 @@ msgstr "Tipo"
#: forms.py:23
msgid "Key"
msgstr ""
msgstr "Llave"
#: forms.py:27
msgid "Passphrase"
msgstr ""
msgstr "Contraseña"
#: forms.py:53
#| msgid "Signature file"
msgid "Signature is embedded?"
msgstr ""
msgstr "¿Firma integrada?"
#: forms.py:55
#| msgid "Signature file"
msgid "Signature date"
msgstr ""
msgstr "Fecha de la firma"
#: forms.py:58
#| msgid "Signature ID: %s"
msgid "Signature key ID"
msgstr ""
msgstr "ID de llave de firma"
#: forms.py:60
#| msgid "Signature type: %s"
msgid "Signature key present?"
msgstr ""
msgstr "¿Llave de la firma presente?"
#: forms.py:73
msgid "Key fingerprint"
msgstr ""
msgstr "Huella de la llave"
#: forms.py:77
msgid "Key creation date"
msgstr ""
msgstr "Fecha de creación de la llave"
#: forms.py:82
msgid "Key expiration date"
msgstr ""
msgstr "Fecha de expiración de la llave"
#: forms.py:87
msgid "Key length"
msgstr ""
msgstr "Tamaño de la llave"
#: forms.py:91
msgid "Key algorithm"
msgstr ""
msgstr "Algoritmo de la llave"
#: forms.py:95
msgid "Key user ID"
msgstr ""
msgstr "ID de usuario de la llave"
#: forms.py:99
msgid "Key type"
msgstr ""
msgstr "Tipo de llave"
#: links.py:32
#| msgid "Verify document signatures"
msgid "Verify all documents"
msgstr ""
msgstr "Verificar todos los documents"
#: links.py:39
msgid "Signatures"
@@ -123,7 +123,7 @@ msgstr "Detalles"
#: links.py:57
msgid "Signature list"
msgstr ""
msgstr "Lista de firmas"
#: links.py:63
msgid "Download"
@@ -135,11 +135,11 @@ msgstr "Subir firma"
#: links.py:75
msgid "Sign detached"
msgstr ""
msgstr "Firma aparte"
#: links.py:81
msgid "Sign embedded"
msgstr ""
msgstr "Firma integrada"
#: models.py:31
msgid "Document version"
@@ -147,11 +147,11 @@ msgstr "Versión de documento"
#: models.py:35
msgid "Date signed"
msgstr ""
msgstr "Fecha firmado"
#: models.py:45
msgid "Public key fingerprint"
msgstr ""
msgstr "Huella de llave publica"
#: models.py:51
msgid "Document version signature"
@@ -191,15 +191,15 @@ msgstr ""
#: models.py:130
msgid "signature"
msgstr ""
msgstr "firma"
#: permissions.py:13
msgid "Sign documents with detached signatures"
msgstr ""
msgstr "Firmar documentos con firma aparte"
#: permissions.py:17
msgid "Sign documents with embedded signatures"
msgstr ""
msgstr "Firmar documentos con firma integrada"
#: permissions.py:21
msgid "Delete detached signatures"
@@ -208,12 +208,12 @@ msgstr "Borrar firmas separadas"
#: permissions.py:25
#| msgid "Download detached signatures"
msgid "Download detached document signatures"
msgstr ""
msgstr "Descargar firma aparte de documentos"
#: permissions.py:29
#| msgid "Upload detached signatures"
msgid "Upload detached document signatures"
msgstr ""
msgstr "Subir firmas aparte de documentos"
#: permissions.py:33
msgid "Verify document signatures"
@@ -222,50 +222,50 @@ msgstr "Verificar firmas de documentos"
#: permissions.py:37
#| msgid "Verify document signatures"
msgid "View details of document signatures"
msgstr ""
msgstr "Ver detalles de firma de documentos"
#: views.py:67 views.py:172
msgid "Passphrase is needed to unlock this key."
msgstr ""
msgstr "Se necesita contraseña para acceder a esta llave."
#: views.py:77 views.py:182
msgid "Passphrase is incorrect."
msgstr ""
msgstr "Contraseña incorrecta."
#: views.py:98 views.py:202
msgid "Document version signed successfully."
msgstr ""
msgstr "Versión de documento firmada con éxito."
#: views.py:129
#, python-format
msgid "Sign document version \"%s\" with a detached signature"
msgstr ""
msgstr "Firmar versión de documento \"%s\" con una firma aparte "
#: views.py:240
#, python-format
msgid "Sign document version \"%s\" with a embedded signature"
msgstr ""
msgstr "Firmar versión de documento \"%s\" con una firma integrada"
#: views.py:267
#, python-format
msgid "Delete detached signature: %s"
msgstr ""
msgstr "Borrar firma aparte: %s"
#: views.py:292
#, python-format
#| msgid "Document signatures"
msgid "Details for signature: %s"
msgstr ""
msgstr "Detalles para la firma: %s"
#: views.py:339
#, python-format
msgid "Signatures for document version: %s"
msgstr ""
msgstr "Firmas para la versión de documento: %s"
#: views.py:375
#, python-format
msgid "Upload detached signature for document version: %s"
msgstr ""
msgstr "Subir firma aparte para la versión de documento: %s"
#: views.py:392
msgid "On large databases this operation may take some time to execute."
@@ -274,11 +274,11 @@ msgstr "En bases de datos de gran tamaño esta operación puede tardar algún ti
#: views.py:393
#| msgid "Verify document signatures"
msgid "Verify all document for signatures?"
msgstr ""
msgstr "¿Verificar todos los documentos para firmas?"
#: views.py:403
msgid "Signature verification queued successfully."
msgstr ""
msgstr "Verificación de firmas colocada en la cola."
#~ msgid "Signature status: %s"
#~ msgstr "Signature type: %s"

View File

@@ -1,27 +1,27 @@
# 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, 2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:11-0400\n"
"PO-Revision-Date: 2016-03-21 21:09+0000\n"
"PO-Revision-Date: 2016-05-09 01:51+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:31
msgid "Document states"
msgstr ""
msgstr "Estados de documentos"
#: apps.py:47
msgid "Initial state"
@@ -49,7 +49,7 @@ msgstr "Fecha y hora"
#: apps.py:72 apps.py:99 models.py:79
msgid "Completion"
msgstr ""
msgstr "Cantidad de completación"
#: apps.py:86 forms.py:39 links.py:79 models.py:187
msgid "Transition"
@@ -77,7 +77,7 @@ msgstr "Flujos de trabajo"
#: links.py:20
msgid "Create workflow"
msgstr ""
msgstr "Crear flujo de trabajo"
#: links.py:25 links.py:46 links.py:63
msgid "Delete"
@@ -123,9 +123,7 @@ msgstr "Flujo de trabajo"
msgid ""
"Select if this will be the state with which you want the workflow to start "
"in. Only one state can be the initial state."
msgstr ""
"Seleccione si este va a ser el estado con el que desea que el flujo de "
"trabajo comience. Sólo un estado puede ser el estado inicial."
msgstr "Seleccione si este va a ser el estado con el que desea que el flujo de trabajo comience. Sólo un estado puede ser el estado inicial."
#: models.py:73
msgid "Initial"
@@ -135,7 +133,7 @@ msgstr "Inicial"
msgid ""
"Enter the percent of completion that this state represents in relation to "
"the workflow. Use numbers without the percent sign."
msgstr ""
msgstr "Introduzca el porcentaje de finalización que este estado representa en relación con el flujo de trabajo. Utilice números sin el signo de porcentaje."
#: models.py:92
msgid "Workflow state"
@@ -179,7 +177,7 @@ msgstr "Entradas de registro de las instancias de flujos de trabajo"
#: permissions.py:7
msgid "Document workflows"
msgstr ""
msgstr "Flujos de trabajo de document"
#: permissions.py:10
msgid "Create workflows"
@@ -199,7 +197,7 @@ msgstr "Ver flujos de trabajo"
#: permissions.py:26
msgid "Transition workflows"
msgstr ""
msgstr "Realizar transiciones"
#: views.py:57
#, python-format
@@ -209,7 +207,7 @@ msgstr "Flujos de trabajo para el documento: %s"
#: views.py:91
#, python-format
msgid "Documents with the workflow: %s"
msgstr ""
msgstr "Documentos con el flujo de trabajo: %s"
#: views.py:116
#, python-format
@@ -227,11 +225,11 @@ msgstr "Realizar la transición de flujo de trabajo: %s"
#: views.py:215
msgid "Available document types"
msgstr ""
msgstr "Tipos de documentos disponibles"
#: views.py:216
msgid "Document types assigned this workflow"
msgstr ""
msgstr "Tipos de documentos asignados a este flujo de trabajo"
#: views.py:226
#, python-format

View File

@@ -39,7 +39,7 @@ logger = logging.getLogger(__name__)
class APIDeletedDocumentListView(generics.ListAPIView):
"""
Returns a list of all the deleted documents.
Returns a list of all the trashed documents.
"""
filter_backends = (MayanObjectPermissionsFilter,)
@@ -51,7 +51,7 @@ class APIDeletedDocumentListView(generics.ListAPIView):
class APIDeletedDocumentView(generics.RetrieveDestroyAPIView):
"""
Returns the selected deleted document details.
Returns the selected trashed document details.
"""
mayan_object_permissions = {
@@ -63,7 +63,7 @@ class APIDeletedDocumentView(generics.RetrieveDestroyAPIView):
def delete(self, *args, **kwargs):
"""
Delete the selected document.
Delete the trashed document.
"""
return super(APIDeletedDocumentView, self).delete(*args, **kwargs)
@@ -71,7 +71,7 @@ class APIDeletedDocumentView(generics.RetrieveDestroyAPIView):
class APIDeletedDocumentRestoreView(generics.GenericAPIView):
"""
Restore a deleted document.
Restore a trashed document.
"""
mayan_object_permissions = {

View File

@@ -1,7 +1,9 @@
from __future__ import unicode_literals
from django.apps import apps
from django.utils.translation import ugettext_lazy as _
from .literals import DEFAULT_DOCUMENT_TYPE_LABEL
from .signals import post_initial_document_type
def create_default_document_type(sender, **kwargs):
@@ -10,4 +12,9 @@ def create_default_document_type(sender, **kwargs):
)
if not DocumentType.objects.count():
DocumentType.objects.create(label=_('Default'))
document_type = DocumentType.objects.create(
label=DEFAULT_DOCUMENT_TYPE_LABEL
)
post_initial_document_type.send(
sender=DocumentType, instance=document_type
)

View File

@@ -11,6 +11,7 @@ DELETE_STALE_STUBS_INTERVAL = 60 * 10 # 10 minutes
DEFAULT_DELETE_PERIOD = 30
DEFAULT_DELETE_TIME_UNIT = TIME_DELTA_UNIT_DAYS
DEFAULT_ZIP_FILENAME = 'document_bundle.zip'
DEFAULT_DOCUMENT_TYPE_LABEL = _('Default')
DOCUMENT_IMAGE_TASK_TIMEOUT = 20
STUB_EXPIRATION_INTERVAL = 60 * 60 * 24 # 24 hours
UPDATE_PAGE_COUNT_RETRY_DELAY = 10

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:11-0400\n"
"PO-Revision-Date: 2016-04-27 18:22+0000\n"
"PO-Revision-Date: 2016-05-09 01:41+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/language/es/)\n"
"MIME-Version: 1.0\n"
@@ -458,7 +458,7 @@ msgstr "Versión de documento"
#: models.py:632
msgid "Quick label"
msgstr ""
msgstr "Etiqueta rapida"
#: models.py:650
msgid "Page number"

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('documents', '0033_auto_20160325_0052'),
]
operations = [
migrations.AlterField(
model_name='document',
name='in_trash',
field=models.BooleanField(default=False, verbose_name='In trash?', db_index=True, editable=False),
),
migrations.AlterField(
model_name='document',
name='is_stub',
field=models.BooleanField(default=True, editable=False, help_text='A document stub is a document with an entry on the database but no file uploaded. This could be an interrupted upload or a deferred upload via the API.', verbose_name='Is stub?', db_index=True),
),
]

View File

@@ -176,7 +176,8 @@ class Document(models.Model):
verbose_name=_('Language')
)
in_trash = models.BooleanField(
default=False, editable=False, verbose_name=_('In trash?')
db_index=True, default=False, editable=False,
verbose_name=_('In trash?')
)
# TODO: set editable to False
deleted_date_time = models.DateTimeField(
@@ -184,10 +185,11 @@ class Document(models.Model):
verbose_name=_('Date and time trashed')
)
is_stub = models.BooleanField(
default=True, editable=False, help_text=_(
db_index=True, default=True, editable=False, help_text=_(
'A document stub is a document with an entry on the database but '
'no file uploaded. This could be an interrupted upload or a '
'deferred upload via the API.'), verbose_name=_('Is stub?')
'deferred upload via the API.'
), verbose_name=_('Is stub?')
)
objects = DocumentManager()

View File

@@ -7,3 +7,6 @@ post_document_type_change = Signal(
providing_args=('instance',), use_caching=True
)
post_document_created = Signal(providing_args=('instance',), use_caching=True)
post_initial_document_type = Signal(
providing_args=('instance',), use_caching=True
)

View File

@@ -173,7 +173,7 @@ class DocumentAPITestCase(APITestCase):
self.assertEqual(Document.trash.count(), 1)
self.client.delete(
reverse('rest_api:deleteddocument-detail', args=(document.pk,))
reverse('rest_api:trasheddocument-detail', args=(document.pk,))
)
self.assertEqual(Document.trash.count(), 0)
@@ -187,7 +187,7 @@ class DocumentAPITestCase(APITestCase):
document.delete()
self.client.post(
reverse('rest_api:deleteddocument-restore', args=(document.pk,))
reverse('rest_api:trasheddocument-restore', args=(document.pk,))
)
self.assertEqual(Document.trash.count(), 0)

View File

@@ -243,16 +243,16 @@ urlpatterns = patterns(
api_urls = patterns(
'',
url(
r'^deleted_documents/$', APIDeletedDocumentListView.as_view(),
name='deleteddocument-list'
r'^trashed_documents/$', APIDeletedDocumentListView.as_view(),
name='trasheddocument-list'
),
url(
r'^deleted_documents/(?P<pk>[0-9]+)/$',
APIDeletedDocumentView.as_view(), name='deleteddocument-detail'
r'^trashed_documents/(?P<pk>[0-9]+)/$',
APIDeletedDocumentView.as_view(), name='trasheddocument-detail'
),
url(
r'^deleted_documents/(?P<pk>[0-9]+)/restore/$',
APIDeletedDocumentRestoreView.as_view(), name='deleteddocument-restore'
r'^trashed_documents/(?P<pk>[0-9]+)/restore/$',
APIDeletedDocumentRestoreView.as_view(), name='trasheddocument-restore'
),
url(r'^documents/$', APIDocumentListView.as_view(), name='document-list'),
url(

View File

@@ -85,7 +85,7 @@ class DocumentListView(SingleObjectListView):
object_permission = permission_document_view
def get_document_queryset(self):
return Document.objects.filter(document_type__organization__id=settings.ORGANIZATION_ID)
return Document.objects.filter(document_type__organization__id=settings.ORGANIZATION_ID).defer('description', 'uuid', 'date_added', 'language', 'in_trash', 'deleted_date_time').all()
def get_queryset(self):
self.queryset = self.get_document_queryset().filter(is_stub=False)

View File

@@ -1,26 +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.
#
#
# Translators:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2012,2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:12-0400\n"
"PO-Revision-Date: 2016-03-21 21:11+0000\n"
"PO-Revision-Date: 2016-05-09 01:41+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:33 links.py:16 links.py:44 models.py:45 permissions.py:7
@@ -74,35 +73,37 @@ msgstr "Fecha y hora que fue creado"
#: models.py:63
msgid "Document folder"
msgstr ""
msgstr "Carpeta de documento"
#: models.py:64
msgid "Document folders"
msgstr ""
msgstr "Carpetas de documento"
#: permissions.py:10
msgid "Create folders"
msgstr ""
msgstr "Crear carpetas"
#: permissions.py:13
msgid "Edit folders"
msgstr ""
msgstr "Editar carpetas"
#: permissions.py:16
#| msgid "Delete new folders"
msgid "Delete folders"
msgstr ""
msgstr "Borrar carpetas"
#: permissions.py:19
msgid "Remove documents from folders"
msgstr "Eliminar documentos de las carpetas"
#: permissions.py:22
#| msgid "Edit new folders"
msgid "View folders"
msgstr ""
msgstr "Ver carpetas"
#: permissions.py:27
msgid "Add documents to folders"
msgstr ""
msgstr "Agregar documentos a carpetas"
#: serializers.py:58
msgid "Primary key of the document to be added."
@@ -110,6 +111,7 @@ msgstr "Llave primaria del documento a ser agregado."
#: views.py:54
#, python-format
#| msgid "Delete new folders"
msgid "Delete the folder: %s?"
msgstr "¿Eliminar la carpeta: %s?"
@@ -215,11 +217,11 @@ msgstr[1] "¿Eliminar los documentos seleccionados de la carpeta: %(folder)s?"
#~ msgstr "Add documents: %s to folder."
#~ 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 ""
#~ "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\"?"
#~ msgid "Document"
#~ msgstr "document"
@@ -252,12 +254,12 @@ msgstr[1] "¿Eliminar los documentos seleccionados de la carpeta: %(folder)s?"
#~ msgstr "What are folders?"
#~ 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."
#~ "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 ""
#~ "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."
#~ "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."

View File

@@ -54,7 +54,7 @@ class LinkingApp(MayanAppConfig):
SourceColumn(
source=ResolvedSmartLink, label=_('Label'),
func=lambda context: context['object'].get_dynamic_label(
context['resolved_object']
context['document']
)
)

View File

@@ -1,24 +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:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:13-0400\n"
"PO-Revision-Date: 2016-03-21 21:10+0000\n"
"PO-Revision-Date: 2016-05-09 01:40+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:33
@@ -31,7 +31,7 @@ msgstr "Etiqueta"
#: apps.py:62 models.py:25
msgid "Dynamic label"
msgstr ""
msgstr "Etiqueta dinámica"
#: apps.py:66 apps.py:71 models.py:27 models.py:124
msgid "Enabled"
@@ -145,20 +145,18 @@ msgstr "está en la expresión regular (no sensible a mayúsculas)"
#: models.py:21 models.py:114
msgid ""
"Enter a template to render. Use Django's default templating language "
"(https://docs.djangoproject.com/en/1.7/ref/templates/builtins/). The "
"{{ document }} context variable is available."
msgstr ""
"(https://docs.djangoproject.com/en/1.7/ref/templates/builtins/). The {{ "
"document }} context variable is available."
msgstr "Introduzca una plantilla para generar. Use el lenguaje de plantillas de Django (https://docs.djangoproject.com/en/1.7/ref/templates/builtins/). La variable {{ document }} está disponible en el contexto de la plantilla."
#: models.py:43
#, python-format
msgid "Error generating dynamic label; %s"
msgstr ""
msgstr "Error generando etiqueta dinámica; %s"
#: models.py:52
msgid "This smart link is not allowed for the selected document's type."
msgstr ""
"Este enlace inteligente no está permitido para el tipo de documento "
"seleccionado."
msgstr "Este enlace inteligente no está permitido para el tipo de documento seleccionado."
#: models.py:88 models.py:100
msgid "Smart link"
@@ -224,17 +222,16 @@ msgstr "Documentos en enlace inteligente: %s"
#: views.py:81
#, python-format
msgid ""
"Documents in smart link \"%(smart_link)s\" as related to \"%(document)s\""
msgstr ""
msgid "Documents in smart link \"%(smart_link)s\" as related to \"%(document)s\""
msgstr "Los documentos en enlace inteligente \"%(smart_link)s\" en relación con \"%(document)s\""
#: views.py:97
msgid "Available document types"
msgstr ""
msgstr "Tipos de documentos disponibles"
#: views.py:99
msgid "Document types enabled"
msgstr ""
msgstr "Tipos de documentos seleccionados"
#: views.py:108
#, python-format
@@ -253,8 +250,9 @@ msgstr "Editar enlace inteligente: %s"
#: views.py:210
#, python-format
#| msgid "Delete smart links"
msgid "Delete smart link: %s"
msgstr ""
msgstr "Borrar enlace inteligente: %s"
#: views.py:222
#, python-format
@@ -272,8 +270,9 @@ msgstr "Editar condición de enlace inteligente"
#: views.py:334
#, python-format
#| msgid "Edit smart link condition"
msgid "Delete smart link condition: \"%s\"?"
msgstr ""
msgstr "¿Borrar condición de enlace inteligente: \"%s\"?"
#~ msgid "Smart link condition: \"%s\" created successfully."
#~ msgstr "Smart link condition: \"%s\" created successfully."
@@ -379,14 +378,14 @@ msgstr ""
#~ msgstr "What are smart links?"
#~ 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."
#~ "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 ""
#~ "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."
#~ "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."

View File

@@ -0,0 +1,5 @@
from __future__ import unicode_literals
TEST_SMART_LINK_DYNAMIC_LABEL = '{{ document.label }}'
TEST_SMART_LINK_EDITED_LABEL = 'test edited label'
TEST_SMART_LINK_LABEL = 'test label'

View File

@@ -13,8 +13,7 @@ from user_management.tests.literals import (
from ..models import SmartLink
TEST_SMART_LINK_LABEL = 'test label'
TEST_SMART_LINK_DYNAMIC_LABEL = '{{ document.label }}'
from .literals import TEST_SMART_LINK_LABEL, TEST_SMART_LINK_DYNAMIC_LABEL
@override_settings(OCR_AUTO_OCR=False)

View File

@@ -1,5 +1,6 @@
from __future__ import absolute_import, unicode_literals
from documents.permissions import permission_document_view
from documents.tests.test_views import GenericDocumentViewTestCase
from user_management.tests import (
TEST_USER_USERNAME, TEST_USER_PASSWORD
@@ -8,11 +9,13 @@ from user_management.tests import (
from ..models import SmartLink
from ..permissions import (
permission_smart_link_create, permission_smart_link_delete,
permission_smart_link_edit
permission_smart_link_edit, permission_smart_link_view
)
TEST_SMART_LINK_LABEL = 'test label'
TEST_SMART_LINK_EDITED_LABEL = 'test edited label'
from .literals import (
TEST_SMART_LINK_DYNAMIC_LABEL, TEST_SMART_LINK_EDITED_LABEL,
TEST_SMART_LINK_LABEL
)
class SmartLinkViewTestCase(GenericDocumentViewTestCase):
@@ -105,3 +108,61 @@ class SmartLinkViewTestCase(GenericDocumentViewTestCase):
smart_link = SmartLink.objects.get(pk=smart_link.pk)
self.assertContains(response, text='update', status_code=200)
self.assertEqual(smart_link.label, TEST_SMART_LINK_EDITED_LABEL)
def setup_smart_links(self):
smart_link = SmartLink.objects.create(
label=TEST_SMART_LINK_LABEL,
dynamic_label=TEST_SMART_LINK_DYNAMIC_LABEL
)
smart_link.document_types.add(self.document_type)
smart_link_2 = SmartLink.objects.create(
label=TEST_SMART_LINK_LABEL,
dynamic_label=TEST_SMART_LINK_DYNAMIC_LABEL
)
smart_link_2.document_types.add(self.document_type)
def test_document_smart_link_list_view_no_permission(self):
self.setup_smart_links()
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
self.role.permissions.add(
permission_document_view.stored_permission
)
response = self.get(
'linking:smart_link_instances_for_document',
args=(self.document.pk,)
)
# Text must appear 2 times, only for the windows title and template
# heading. The two smart links are not shown.
self.assertContains(
response, text=self.document.label, count=2, status_code=200
)
def test_document_smart_link_list_view_with_permission(self):
self.setup_smart_links()
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
self.role.permissions.add(
permission_smart_link_view.stored_permission
)
self.role.permissions.add(
permission_document_view.stored_permission
)
response = self.get(
'linking:smart_link_instances_for_document',
args=(self.document.pk,)
)
# Text must appear 4 times: 2 for the windows title and template
# heading, plus 2 for the test.
self.assertContains(
response, text=self.document.label, count=4, status_code=200
)

View File

@@ -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:
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:13-0400\n"
"PO-Revision-Date: 2016-03-21 21:07+0000\n"
"PO-Revision-Date: 2016-05-09 01:36+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:25
msgid "Mailer"
msgstr ""
msgstr "Correspondencia"
#: apps.py:37
msgid "Date and time"
@@ -55,7 +54,7 @@ msgstr "Enviar enlace"
#: links.py:22 views.py:31
msgid "Document mailing error log"
msgstr ""
msgstr "Biracora de errores de envío"
#: literals.py:7
#, python-format
@@ -64,7 +63,7 @@ msgid ""
"\n"
" --------\n"
" This email has been sent from %(project_title)s (%(project_website)s)"
msgstr ""
msgstr "Se adjunta a este correo electrónico es el documento: {{ document }}\n\n\n--------\nEste correo electrónico ha sido enviado desde %(project_title)s (%(project_website)s)"
#: literals.py:13
#, python-format
@@ -73,7 +72,7 @@ msgid ""
"\n"
"--------\n"
" This email has been sent from %(project_title)s (%(project_website)s)"
msgstr ""
msgstr "Para acceder a este documento, haga clic en el siguiente enlace: {{ link }}\n\n\n--------\nEste correo electrónico ha sido enviado desde %(project_title)s (%(project_website)s)"
#: models.py:13
msgid "Date time"
@@ -101,7 +100,7 @@ msgstr "Enviar documento por correo electrónico"
#: permissions.py:16
msgid "View document mailing error log"
msgstr ""
msgstr "Ver bitácora de errores de envío"
#: settings.py:14
msgid "Link for document: {{ document }}"
@@ -109,15 +108,11 @@ msgstr "Enlace para el documento: {{ documento }}"
#: settings.py:15
msgid "Template for the document link email form subject line."
msgstr ""
"Plantilla para la línea de asunto del correo electrónico para envío de "
"enlace del documento."
msgstr "Plantilla para la línea de asunto del correo electrónico para envío de enlace del documento."
#: settings.py:20
msgid "Template for the document link email form body line."
msgstr ""
"Plantilla para el cuerpo del correo electrónico de envío de enlace de "
"documento."
msgstr "Plantilla para el cuerpo del correo electrónico de envío de enlace de documento."
#: settings.py:24
msgid "Document: {{ document }}"
@@ -125,15 +120,11 @@ msgstr "Documento: {{ document }}"
#: settings.py:25
msgid "Template for the document email form subject line."
msgstr ""
"Plantilla para la línea de sujeto del correo electrónico de envio de "
"documento."
msgstr "Plantilla para la línea de sujeto del correo electrónico de envio de documento."
#: settings.py:30
msgid "Template for the document email form body line."
msgstr ""
"Plantilla para la línea de cuerpo del correo electrónico para envío de "
"documento."
msgstr "Plantilla para la línea de cuerpo del correo electrónico para envío de documento."
#: views.py:56
msgid "Must provide at least one document."
@@ -141,9 +132,7 @@ msgstr "Debe proveer al menos un documento"
#: views.py:105
msgid "Successfully queued for delivery via email."
msgstr ""
"Añadido de forma exitosa a la lista de espera para envío de correo "
"electrónico"
msgstr "Añadido de forma exitosa a la lista de espera para envío de correo electrónico"
#: views.py:114
msgid "Send"

View File

@@ -15,7 +15,7 @@ from permissions import Permission
from rest_api.filters import MayanObjectPermissionsFilter
from rest_api.permissions import MayanPermission
from .models import DocumentMetadata, MetadataType
from .models import DocumentMetadata, DocumentTypeMetadataType, MetadataType
from .permissions import (
permission_metadata_document_add, permission_metadata_document_remove,
permission_metadata_document_edit, permission_metadata_document_view,
@@ -23,8 +23,9 @@ from .permissions import (
permission_metadata_type_edit, permission_metadata_type_view
)
from .serializers import (
DocumentMetadataSerializer, DocumentTypeNewMetadataTypeSerializer,
MetadataTypeSerializer, DocumentTypeMetadataTypeSerializer
DocumentMetadataSerializer, DocumentNewMetadataSerializer,
DocumentTypeNewMetadataTypeSerializer, MetadataTypeSerializer,
DocumentTypeMetadataTypeSerializer
)
@@ -89,15 +90,14 @@ class APIMetadataTypeView(generics.RetrieveUpdateDestroyAPIView):
class APIDocumentMetadataListView(generics.ListCreateAPIView):
permission_classes = (MayanPermission,)
serializer_class = DocumentMetadataSerializer
def get_document(self):
return get_object_or_404(Document, pk=self.kwargs['document_pk'])
return get_object_or_404(Document, pk=self.kwargs['pk'])
def get_queryset(self):
document = self.get_document()
if self.request == 'GET':
if self.request.method == 'GET':
# Make sure the use has the permission to see the metadata for
# this document
try:
@@ -111,7 +111,7 @@ class APIDocumentMetadataListView(generics.ListCreateAPIView):
)
else:
return document.metadata.all()
elif self.request == 'POST':
elif self.request.method == 'POST':
# Make sure the use has the permission to add metadata to this
# document
try:
@@ -126,8 +126,11 @@ class APIDocumentMetadataListView(generics.ListCreateAPIView):
else:
return document.metadata.all()
def pre_save(self, serializer):
serializer.document = self.get_document()
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentMetadataSerializer
elif self.request.method == 'POST':
return DocumentNewMetadataSerializer
def get(self, *args, **kwargs):
"""
@@ -135,6 +138,10 @@ class APIDocumentMetadataListView(generics.ListCreateAPIView):
"""
return super(APIDocumentMetadataListView, self).get(*args, **kwargs)
def perform_create(self, serializer):
serializer.document = self.get_document()
serializer.save()
def post(self, *args, **kwargs):
"""
Add an existing metadata type and value to the selected document.
@@ -265,10 +272,15 @@ class APIDocumentTypeMetadataTypeOptionalListView(generics.ListCreateAPIView):
metadata_type = get_object_or_404(
MetadataType, pk=serializer.data['metadata_type_pk']
)
document_type.metadata_type.add(
metadata_type, required=self.required_metadata
document_type_metadata_type = document_type.metadata.create(
metadata_type=metadata_type, required=self.required_metadata
)
return Response(
status=status.HTTP_201_CREATED,
data={
'pk': document_type_metadata_type.pk
}
)
return Response(status=status.HTTP_201_CREATED)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
@@ -291,18 +303,19 @@ class APIDocumentTypeMetadataTypeRequiredListView(APIDocumentTypeMetadataTypeOpt
"""
return super(
APIDocumentTypeMetadataTypeRequiredListView, self
).get(*args, **kwargs)
).post(request, *args, **kwargs)
class APIDocumentTypeMetadataTypeRequiredView(views.APIView):
class APIDocumentTypeMetadataTypeView(views.APIView):
def delete(self, request, *args, **kwargs):
"""
Remove a metadata type from a document type.
"""
document_type = get_object_or_404(
DocumentType, pk=self.kwargs['document_type_pk']
document_type_metadata_type = get_object_or_404(
DocumentTypeMetadataType, pk=self.kwargs['pk']
)
try:
Permission.check_permissions(
self.request.user, (permission_document_type_edit,)
@@ -310,11 +323,8 @@ class APIDocumentTypeMetadataTypeRequiredView(views.APIView):
except PermissionDenied:
AccessControlList.objects.check_access(
permission_document_type_edit, self.request.user,
document_type
document_type_metadata_type.document_type
)
metadata_type = get_object_or_404(
MetadataType, pk=self.kwargs['metadata_type_pk']
)
document_type.metadata_type.remove(metadata_type)
document_type_metadata_type.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

View File

@@ -66,7 +66,7 @@ class MetadataApp(MayanAppConfig):
DocumentTypeMetadataType = self.get_model('DocumentTypeMetadataType')
MetadataType = self.get_model('MetadataType')
APIEndPoint(app=self, version_string='1')
APIEndPoint(app=self, version_string='2')
Document.add_to_class(
'metadata_value_of', DocumentMetadataHelper.constructor

View File

@@ -1,6 +1,7 @@
from __future__ import unicode_literals
from django import forms
from django.core.exceptions import ValidationError
from django.forms.formsets import formset_factory
from django.utils.translation import string_concat, ugettext_lazy as _
@@ -81,6 +82,19 @@ class MetadataForm(forms.Form):
)
def clean(self):
metadata_type = getattr(self, 'metadata_type', None)
if metadata_type:
required = self.metadata_type.get_required_for(
document_type=self.document_type
)
if required and not self.cleaned_data.get('update'):
raise ValidationError(
_(
'"%s" is required for this document type.'
) % self.metadata_type.label
)
if self.cleaned_data.get('update') and hasattr(self, 'metadata_type'):
self.cleaned_data['value'] = self.metadata_type.validate_value(
document_type=self.document_type,

View File

@@ -1,25 +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.
#
#
# Translators:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2012,2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:13-0400\n"
"PO-Revision-Date: 2016-03-21 21:03+0000\n"
"PO-Revision-Date: 2016-05-09 01:52+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:52 apps.py:142 links.py:39 permissions.py:7 settings.py:10
@@ -38,9 +38,7 @@ msgstr ""
msgid ""
"Queryset containing a MetadataType instance reference and a value for that "
"metadata type"
msgstr ""
"QuerySet que contiene una referencia de instancia de tipo de meta datos y un "
"valor para ese tipo de meta datos "
msgstr "QuerySet que contiene una referencia de instancia de tipo de meta datos y un valor para ese tipo de meta datos "
#: apps.py:118
msgid "Metadata type name"
@@ -102,6 +100,7 @@ msgid "Default value error: %s"
msgstr ""
#: forms.py:116
#| msgid " Available models: %s"
msgid " Available template context variables: "
msgstr ""
@@ -146,6 +145,7 @@ msgid "Metadata types"
msgstr "Tipos de metadatos"
#: models.py:42
#| msgid "Do not use python reserved words, or spaces."
msgid ""
"Name used by other apps to reference this value. Do not use python reserved "
"words, or spaces."
@@ -168,8 +168,8 @@ msgstr "Por defecto"
#: models.py:60
msgid ""
"Enter a template to render. Must result in a comma delimited string. Use "
"Django's default templating language (https://docs.djangoproject.com/en/1.7/"
"ref/templates/builtins/)."
"Django's default templating language "
"(https://docs.djangoproject.com/en/1.7/ref/templates/builtins/)."
msgstr ""
#: models.py:65
@@ -184,11 +184,12 @@ msgstr ""
#: models.py:72
msgid "Validator"
msgstr ""
msgstr "Validador"
#: models.py:76
msgid ""
"The parser will reformat the value entered to conform to the expected format."
"The parser will reformat the value entered to conform to the expected "
"format."
msgstr ""
#: models.py:78
@@ -197,11 +198,11 @@ msgstr ""
#: models.py:124
msgid "This metadata is required for this document type."
msgstr ""
msgstr "Este metadato es requerido para este tipo de documento."
#: models.py:131
msgid "Value is not one of the provided options."
msgstr ""
msgstr "El valor no es una de las opciones provistas."
#: models.py:153
msgid "Document"
@@ -314,25 +315,20 @@ msgstr[1] "Editar meta datos de documentos"
msgid ""
"Error adding metadata type \"%(metadata_type)s\" to document: %(document)s; "
"%(exception)s"
msgstr ""
"Error al añadir tipo de metadatos \"%(metadata_type)s\" al documento: "
"%(document)s; %(exception)s"
msgstr "Error al añadir tipo de metadatos \"%(metadata_type)s\" al documento: %(document)s; %(exception)s"
#: views.py:272
#, python-format
msgid ""
"Metadata type: %(metadata_type)s successfully added to document %(document)s."
msgstr ""
"Tipo de metadatos: %(metadata_type)s añadido con éxito al documento "
"Metadata type: %(metadata_type)s successfully added to document "
"%(document)s."
msgstr "Tipo de metadatos: %(metadata_type)s añadido con éxito al documento %(document)s."
#: views.py:282
#, python-format
msgid ""
"Metadata type: %(metadata_type)s already present in document %(document)s."
msgstr ""
"Tipo de metadatos: %(metadata_type)s ya presente en el documento "
"%(document)s."
msgstr "Tipo de metadatos: %(metadata_type)s ya presente en el documento %(document)s."
#: views.py:313
msgid "Add metadata types to document"
@@ -345,18 +341,14 @@ msgstr[1] "Añadir tipos de meta datos a los documentos"
msgid ""
"Successfully remove metadata type \"%(metadata_type)s\" from document: "
"%(document)s."
msgstr ""
"Remoción con éxito el tipo de meta datos \"%(metadata_type)s\" del "
"documento: %(document)s."
msgstr "Remoción con éxito el tipo de meta datos \"%(metadata_type)s\" del documento: %(document)s."
#: views.py:439
#, python-format
msgid ""
"Error removing metadata type \"%(metadata_type)s\" from document: "
"%(document)s; %(exception)s"
msgstr ""
"Error al eliminar el tipo de metadatos \"%(metadata_type)s\" del documento: "
"%(document)s; %(exception)s"
msgstr "Error al eliminar el tipo de metadatos \"%(metadata_type)s\" del documento: %(document)s; %(exception)s"
#: views.py:461
msgid "Remove metadata types from the document"
@@ -375,8 +367,9 @@ msgstr "Crear tipo de metadatos"
#: views.py:529
#, python-format
#| msgid "Delete metadata types"
msgid "Delete the metadata type: %s?"
msgstr ""
msgstr "¿Borrar el tipo de metadato: %s?"
#: views.py:542
#, python-format
@@ -388,12 +381,13 @@ msgid "Internal name"
msgstr "Nombre interno"
#: views.py:568
#| msgid "View metadata types"
msgid "Available metadata types"
msgstr ""
msgstr "Tipos de metadatos disponibles"
#: views.py:569
msgid "Metadata types assigned"
msgstr ""
msgstr "Tipos de metadatos asignados"
#: views.py:600
#, python-format
@@ -565,47 +559,47 @@ msgstr "Tipos de metadata requerida para tipo de documento: %s"
#~ msgstr "What are metadata sets?"
#~ 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."
#~ "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 ""
#~ "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."
#~ "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."
#~ msgid "What are metadata types?"
#~ msgstr "What are metadata types?"
#~ 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."
#~ "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 ""
#~ "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."
#~ "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."
#~ msgid " Available functions: %s"
#~ msgstr " Available functions: %s"
#~ msgid ""
#~ "Enter a string to be evaluated. Example: [user.get_full_name() for user "
#~ "in User.objects.all()].%s"
#~ "Enter a string to be evaluated. Example: [user.get_full_name() for user in "
#~ "User.objects.all()].%s"
#~ msgstr ""
#~ "Enter a string to be evaluated. Example: [user.get_full_name() for user "
#~ "in User.objects.all()].%s"
#~ "Enter a string to be evaluated. Example: [user.get_full_name() for user in "
#~ "User.objects.all()].%s"
#~ msgid "Error deleting document indexes; %s"
#~ msgstr "Error deleting document indexes; %s"

View File

@@ -121,7 +121,7 @@ class MetadataType(models.Model):
if not value and self.get_required_for(document_type=document_type):
raise ValidationError(
_('This metadata is required for this document type.')
_('"%s" is required for this document type.') % self.label
)
if self.lookup:

View File

@@ -19,6 +19,7 @@ class DocumentMetadataSerializer(serializers.ModelSerializer):
class Meta:
fields = ('document', 'id', 'metadata_type', 'value',)
model = DocumentMetadata
read_only_fields = ('metadata_type',)
class DocumentTypeMetadataTypeSerializer(serializers.ModelSerializer):
@@ -28,16 +29,34 @@ class DocumentTypeMetadataTypeSerializer(serializers.ModelSerializer):
class DocumentNewMetadataSerializer(serializers.Serializer):
metadata_type = serializers.IntegerField(
help_text=_('Primary key of the metadata type to be added.')
metadata_type_pk = serializers.IntegerField(
help_text=_('Primary key of the metadata type to be added.'),
write_only=True
)
metadata_type = MetadataTypeSerializer(read_only=True)
pk = serializers.IntegerField(
help_text=_('Primary key of the document metadata type.'),
read_only=True
)
value = serializers.CharField(
max_length=255,
help_text=_('Value of the corresponding metadata type instance.')
)
def create(self, validated_data):
metadata_type = MetadataType.objects.get(
pk=validated_data['metadata_type_pk']
)
instance = self.document.metadata.create(
metadata_type=metadata_type, value=validated_data['value']
)
return instance
class DocumentTypeNewMetadataTypeSerializer(serializers.Serializer):
metadata_type = serializers.IntegerField(
metadata_type_pk = serializers.IntegerField(
help_text=_('Primary key of the metadata type to be added.')
)

View File

@@ -0,0 +1,293 @@
from __future__ import unicode_literals
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.test import override_settings
from rest_framework.test import APITestCase
from documents.models import DocumentType
from documents.tests import TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
from user_management.tests.literals import (
TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME
)
from ..models import DocumentMetadata, DocumentTypeMetadataType, MetadataType
from .literals import (
TEST_METADATA_TYPE_LABEL, TEST_METADATA_TYPE_LABEL_2,
TEST_METADATA_TYPE_NAME, TEST_METADATA_TYPE_NAME_2
)
TEST_METADATA_VALUE = 'test value'
TEST_METADATA_VALUE_EDITED = 'test value edited'
class MetadataTypeAPITestCase(APITestCase):
def setUp(self):
self.admin_user = get_user_model().objects.create_superuser(
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
password=TEST_ADMIN_PASSWORD
)
self.client.login(
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
)
def tearDown(self):
self.admin_user.delete()
def test_metadata_type_create(self):
response = self.client.post(
reverse('rest_api:metadatatype-list'), data={
'label': TEST_METADATA_TYPE_LABEL,
'name': TEST_METADATA_TYPE_NAME
}
)
metadata_type = MetadataType.objects.first()
self.assertEqual(response.status_code, 201)
self.assertEqual(response.data['id'], metadata_type.pk)
self.assertEqual(response.data['label'], TEST_METADATA_TYPE_LABEL)
self.assertEqual(response.data['name'], TEST_METADATA_TYPE_NAME)
self.assertEqual(metadata_type.label, TEST_METADATA_TYPE_LABEL)
self.assertEqual(metadata_type.name, TEST_METADATA_TYPE_NAME)
def test_metadata_type_delete(self):
metadata_type = MetadataType.objects.create(
label=TEST_METADATA_TYPE_LABEL, name=TEST_METADATA_TYPE_NAME
)
response = self.client.delete(
reverse('rest_api:metadatatype-detail', args=(metadata_type.pk,))
)
self.assertEqual(response.status_code, 204)
self.assertEqual(MetadataType.objects.count(), 0)
def test_metadata_type_edit(self):
metadata_type = MetadataType.objects.create(
label=TEST_METADATA_TYPE_LABEL, name=TEST_METADATA_TYPE_NAME
)
response = self.client.put(
reverse('rest_api:metadatatype-detail', args=(metadata_type.pk,)),
data={
'label': TEST_METADATA_TYPE_LABEL_2,
'name': TEST_METADATA_TYPE_NAME_2
}
)
self.assertEqual(response.status_code, 200)
metadata_type.refresh_from_db()
self.assertEqual(metadata_type.label, TEST_METADATA_TYPE_LABEL_2)
self.assertEqual(metadata_type.name, TEST_METADATA_TYPE_NAME_2)
class DocumentTypeMetadataTypeAPITestCase(APITestCase):
def setUp(self):
self.admin_user = get_user_model().objects.create_superuser(
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
password=TEST_ADMIN_PASSWORD
)
self.client.login(
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
)
self.document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE
)
self.metadata_type = MetadataType.objects.create(
label=TEST_METADATA_TYPE_LABEL, name=TEST_METADATA_TYPE_NAME
)
def tearDown(self):
self.admin_user.delete()
self.document_type.delete()
def test_document_type_metadata_type_optional_create(self):
response = self.client.post(
reverse(
'rest_api:documenttypeoptionalmetadatatype-list',
args=(self.document_type.pk,)
), data={'metadata_type_pk': self.metadata_type.pk}
)
self.assertEqual(response.status_code, 201)
document_type_metadata_type = DocumentTypeMetadataType.objects.filter(
document_type=self.document_type, required=False
).first()
self.assertEqual(response.data['pk'], document_type_metadata_type.pk)
self.assertEqual(
document_type_metadata_type.metadata_type, self.metadata_type
)
def test_document_type_metadata_type_required_create(self):
response = self.client.post(
reverse(
'rest_api:documenttyperequiredmetadatatype-list',
args=(self.document_type.pk,)
), data={'metadata_type_pk': self.metadata_type.pk}
)
self.assertEqual(response.status_code, 201)
document_type_metadata_type = DocumentTypeMetadataType.objects.filter(
document_type=self.document_type, required=True
).first()
self.assertEqual(response.data['pk'], document_type_metadata_type.pk)
self.assertEqual(
document_type_metadata_type.metadata_type, self.metadata_type
)
def test_document_type_metadata_type_delete(self):
document_type_metadata_type = self.document_type.metadata.create(
metadata_type=self.metadata_type, required=True
)
response = self.client.delete(
reverse(
'rest_api:documenttypemetadatatype-detail',
args=(document_type_metadata_type.pk,)
),
)
self.assertEqual(response.status_code, 204)
self.assertEqual(self.document_type.metadata.all().count(), 0)
class DocumentMetadataAPITestCase(APITestCase):
@override_settings(OCR_AUTO_OCR=False)
def setUp(self):
self.admin_user = get_user_model().objects.create_superuser(
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
password=TEST_ADMIN_PASSWORD
)
self.client.login(
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
)
self.document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE
)
self.metadata_type = MetadataType.objects.create(
label=TEST_METADATA_TYPE_LABEL, name=TEST_METADATA_TYPE_NAME
)
self.document_type.metadata.create(
metadata_type=self.metadata_type, required=False
)
with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
self.document = self.document_type.new_document(
file_object=file_object,
)
def tearDown(self):
self.admin_user.delete()
self.document_type.delete()
def test_document_metadata_create(self):
response = self.client.post(
reverse(
'rest_api:documentmetadata-list',
args=(self.document.pk,)
), data={
'metadata_type_pk': self.metadata_type.pk,
'value': TEST_METADATA_VALUE
}
)
document_metadata = DocumentMetadata.objects.get(
document=self.document
)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.data['pk'], document_metadata.pk)
self.assertEqual(document_metadata.metadata_type, self.metadata_type)
self.assertEqual(document_metadata.value, TEST_METADATA_VALUE)
def test_document_metadata_list(self):
document_metadata = self.document.metadata.create(
metadata_type=self.metadata_type, value=TEST_METADATA_VALUE
)
response = self.client.get(
reverse(
'rest_api:documentmetadata-list', args=(self.document.pk,)
)
)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.data['results'][0]['document'], self.document.pk
)
self.assertEqual(
response.data['results'][0]['metadata_type'], self.metadata_type.pk
)
self.assertEqual(
response.data['results'][0]['value'], TEST_METADATA_VALUE
)
self.assertEqual(
response.data['results'][0]['id'], document_metadata.pk
)
def test_document_metadata_edit(self):
document_metadata = self.document.metadata.create(
metadata_type=self.metadata_type, value=TEST_METADATA_VALUE
)
response = self.client.put(
reverse(
'rest_api:documentmetadata-detail',
args=(document_metadata.pk,)
), data={
'value': TEST_METADATA_VALUE_EDITED
}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.data['document'], self.document.pk
)
self.assertEqual(
response.data['metadata_type'], self.metadata_type.pk
)
self.assertEqual(
response.data['value'], TEST_METADATA_VALUE_EDITED
)
def test_document_metadata_delete(self):
document_metadata = self.document.metadata.create(
metadata_type=self.metadata_type, value=TEST_METADATA_VALUE
)
response = self.client.delete(
reverse(
'rest_api:documentmetadata-detail',
args=(document_metadata.pk,)
)
)
self.assertEqual(response.status_code, 204)
self.assertEqual(self.document.metadata.all().count(), 0)

View File

@@ -6,7 +6,7 @@ from .api_views import (
APIDocumentMetadataListView, APIDocumentMetadataView,
APIDocumentTypeMetadataTypeOptionalListView,
APIDocumentTypeMetadataTypeRequiredListView,
APIDocumentTypeMetadataTypeRequiredView, APIMetadataTypeListView,
APIDocumentTypeMetadataTypeView, APIMetadataTypeListView,
APIMetadataTypeView
)
from .views import (
@@ -75,11 +75,11 @@ urlpatterns = patterns(
api_urls = patterns(
'',
url(
r'^metadatatypes/$', APIMetadataTypeListView.as_view(),
r'^metadata_types/$', APIMetadataTypeListView.as_view(),
name='metadatatype-list'
),
url(
r'^metadatatypes/(?P<pk>[0-9]+)/$', APIMetadataTypeView.as_view(),
r'^metadata_types/(?P<pk>[0-9]+)/$', APIMetadataTypeView.as_view(),
name='metadatatype-detail'
),
url(
@@ -87,22 +87,22 @@ api_urls = patterns(
APIDocumentMetadataView.as_view(), name='documentmetadata-detail'
),
url(
r'^document/(?P<document_pk>[0-9]+)/metadata/$',
r'^document/(?P<pk>\d+)/metadata/$',
APIDocumentMetadataListView.as_view(), name='documentmetadata-list'
),
url(
r'^document_type/(?P<document_type_pk>[0-9]+)/metadatatypes/optional/$',
r'^document_type/(?P<document_type_pk>[0-9]+)/metadata_types/optional/$',
APIDocumentTypeMetadataTypeOptionalListView.as_view(),
name='documenttypemetadatatype-list'
name='documenttypeoptionalmetadatatype-list'
),
url(
r'^document_type/(?P<document_type_pk>[0-9]+)/metadatatypes/required/$',
r'^document_type/(?P<document_type_pk>[0-9]+)/metadata_types/required/$',
APIDocumentTypeMetadataTypeRequiredListView.as_view(),
name='documenttypemetadatatype-list'
name='documenttyperequiredmetadatatype-list'
),
url(
r'^document_type/(?P<document_type_pk>[0-9]+)/metadatatypes/(?P<metadata_type_pk>[0-9]+)/$',
APIDocumentTypeMetadataTypeRequiredView.as_view(),
r'^document_type_metadata_type/(?P<pk>\d+)/$',
APIDocumentTypeMetadataTypeView.as_view(),
name='documenttypemetadatatype-detail'
),
)

View File

@@ -213,13 +213,9 @@ class Command(management.BaseCommand):
help = 'Mount an index as a FUSE filesystem.'
def add_arguments(self, parser):
parser.add_argument('slug', nargs='?',
help='Index slug'
)
parser.add_argument('slug', nargs='?', help='Index slug')
parser.add_argument('mount_point', nargs='?',
help='Mount point'
)
parser.add_argument('mount_point', nargs='?', help='Mount point')
def handle(self, *args, **options):
if not options.get('slug') or not options.get('mount_point'):

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('motd', '0004_auto_20160314_0040'),
]
operations = [
migrations.AlterField(
model_name='message',
name='end_datetime',
field=models.DateTimeField(help_text='Date and time until when this message is to be displayed.', null=True, verbose_name='End date time', blank=True),
),
migrations.AlterField(
model_name='message',
name='label',
field=models.CharField(help_text='Short description of this message.', max_length=32, verbose_name='Label'),
),
migrations.AlterField(
model_name='message',
name='message',
field=models.TextField(help_text='The actual message to be displayed.', verbose_name='Message'),
),
migrations.AlterField(
model_name='message',
name='start_datetime',
field=models.DateTimeField(help_text='Date and time after which this message will be displayed.', null=True, verbose_name='Start date time', blank=True),
),
]

View File

@@ -136,6 +136,19 @@ class Menu(object):
resolved_links.append(resolved_link)
# No need for further content object match testing
break
else:
# Second try for objects using .defer() or .only()
if inspect.isclass(bound_source) and isinstance(resolved_navigation_object, bound_source):
for link in links:
resolved_link = link.resolve(
context=context,
resolved_object=resolved_navigation_object
)
if resolved_link:
resolved_links.append(resolved_link)
# No need for further content object match testing
break
except TypeError:
# When source is a dictionary
pass
@@ -212,6 +225,7 @@ class Link(object):
self.keep_query = keep_query
self.kwargs = kwargs or {}
self.permissions = permissions or []
self.permissions_related = permissions_related
self.remove_from_query = remove_from_query or []
self.tags = tags
self.text = text
@@ -246,7 +260,7 @@ class Link(object):
try:
AccessControlList.objects.check_access(
self.permissions, request.user, resolved_object,
related=getattr(self, 'permissions_related', None)
related=self.permissions_related
)
except PermissionDenied:
return None
@@ -349,7 +363,12 @@ class SourceColumn(object):
try:
return cls._registry[source.__class__]
except KeyError:
return ()
try:
# Special case for queryset items produced from
# .defer() or .only() optimizations
return cls._registry[source._meta.parents.items()[0][0]]
except (KeyError, IndexError):
return ()
except TypeError:
# unhashable type: list
return ()

View File

@@ -2,6 +2,8 @@ from __future__ import unicode_literals
import logging
import sh
from PIL import Image
import pytesseract
@@ -13,6 +15,23 @@ logger = logging.getLogger(__name__)
class Tesseract(OCRBackendBase):
def __init__(self, *args, **kwargs):
super(Tesseract, self).__init__(*args, **kwargs)
try:
self.binary = sh.Command(setting_tesseract_path.value)
except sh.CommandNotFound:
self.binary = None
def get_languages(self):
if self.binary:
result = self.binary(list_langs=True)
return [
language for language in result.stderr.split('\n') if language
]
else:
return ()
def execute(self, *args, **kwargs):
"""
Execute the command line binary of tesseract
@@ -29,6 +48,11 @@ class Tesseract(OCRBackendBase):
# re-run it with no language parameter
except Exception as exception:
error_message = 'Exception calling pytesseract with language option: {}; {}'.format(self.language, exception)
if self.binary:
if self.language not in self.get_languages():
error_message = '{}\nThe requested Tesseract language file for "{}" is not available and needs to be installed.\nIf using Debian or Ubuntu run: apt-get install tesseract-ocr-{}'.format(error_message, self.language, self.language)
logger.error(error_message)
raise OCRError(error_message)

View File

@@ -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:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:14-0400\n"
"PO-Revision-Date: 2016-03-21 21:11+0000\n"
"PO-Revision-Date: 2016-05-09 01:31+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:58 apps.py:116 apps.py:154 links.py:14 permissions.py:7
@@ -65,6 +64,7 @@ msgid "Contents"
msgstr "Contenido"
#: links.py:18 links.py:25
#| msgid "Submit documents for OCR"
msgid "Submit for OCR"
msgstr "Enviar para OCR"
@@ -94,11 +94,11 @@ msgstr "Automatically queue newly created documents for OCR."
#: models.py:24
msgid "Document type settings"
msgstr ""
msgstr "Configuración del tipo de documento"
#: models.py:25
msgid "Document types settings"
msgstr ""
msgstr "Configuraciones de tipos de documento"
#: models.py:31
msgid "Document version"
@@ -129,6 +129,7 @@ msgid "Document page content"
msgstr "Contenido de página de documento"
#: models.py:63
#| msgid "Document pages content clean up error: %s"
msgid "Document pages contents"
msgstr "Contenido de página de documento"
@@ -140,7 +141,7 @@ msgstr "Error interpretando página: %s "
#: parsers.py:130
#, python-format
msgid "Cannot find pdftotext executable at: %s"
msgstr ""
msgstr "Si no encontró el ejecutable pdftotext en: %s"
#: permissions.py:10
msgid "Submit documents for OCR"
@@ -155,15 +156,15 @@ msgid "Change document type OCR settings"
msgstr ""
#: settings.py:10
#| msgid "File path to unpaper program."
msgid "File path to tesseract program."
msgstr ""
#: settings.py:15
msgid ""
"File path to poppler's pdftotext program used to extract text from PDF files."
msgstr ""
"Ruta de acceso al programa de poppler llamado pdftotext utilizado para "
"extraer texto de archivos PDF."
"File path to poppler's pdftotext program used to extract text from PDF "
"files."
msgstr "Ruta de acceso al programa de poppler llamado pdftotext utilizado para extraer texto de archivos PDF."
#: settings.py:22
msgid "Full path to the backend to be used to do OCR."
@@ -174,6 +175,7 @@ msgid "Set new document types to perform OCR automatically by default."
msgstr ""
#: views.py:28
#| msgid "Submit documents for OCR"
msgid "Submit all documents for OCR?"
msgstr "¿Enviar todos los documentos para OCR?"
@@ -193,17 +195,18 @@ msgid "Document: %(document)s was added to the OCR queue."
msgstr "Documento: %(document)s fue añadido a la lista de espera de OCR"
#: views.py:87
#| msgid "Submit documents for OCR"
msgid "Submit the selected documents to the OCR queue?"
msgstr ""
#: views.py:94
#| msgid "Submit documents for OCR"
msgid "Submit all documents of a type for OCR"
msgstr ""
#: views.py:109
#, python-format
msgid ""
"%(count)d documents of type \"%(document_type)s\" added to the OCR queue."
msgid "%(count)d documents of type \"%(document_type)s\" added to the OCR queue."
msgstr ""
#: views.py:132
@@ -213,8 +216,9 @@ msgstr ""
#: views.py:154
#, python-format
#| msgid "Queued documents: %d"
msgid "OCR result for document: %s"
msgstr ""
msgstr "Resultados del OCR para documento: %s"
#~ msgid "Delete"
#~ msgstr "delete"
@@ -384,11 +388,11 @@ msgstr ""
#~ msgstr "Are you sure you wish to activate document queue: %s"
#~ msgid ""
#~ "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."
#~ msgstr ""
#~ "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."
#~ msgid "Maximum amount of concurrent document OCRs a node can perform."
#~ msgstr "Maximum amount of concurrent document OCRs a node can perform."
@@ -445,11 +449,9 @@ msgstr ""
#~ msgstr "Error deleting queue transformation; %(error)s"
#~ msgid ""
#~ "Are you sure you wish to delete queue transformation \"%(transformation)s"
#~ "\""
#~ "Are you sure you wish to delete queue transformation \"%(transformation)s\""
#~ msgstr ""
#~ "Are you sure you wish to delete queue transformation \"%(transformation)s"
#~ "\""
#~ "Are you sure you wish to delete queue transformation \"%(transformation)s\""
#~ msgid "Queue transformation created successfully"
#~ msgstr "Queue transformation created successfully"

View File

@@ -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:
# Translators:
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2012
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:15-0400\n"
"PO-Revision-Date: 2016-03-21 21:02+0000\n"
"PO-Revision-Date: 2016-05-09 01:32+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:18 permissions.py:7
@@ -52,7 +51,7 @@ msgstr "Ajustes"
#: permissions.py:10
msgid "View settings"
msgstr ""
msgstr "Ver configuraciones"
#: views.py:15
msgid "Setting namespaces"

View File

@@ -1,26 +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.
#
#
# Translators:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# jmcainzos <jmcainzos@vodafone.es>, 2015
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:15-0400\n"
"PO-Revision-Date: 2016-03-21 21:11+0000\n"
"PO-Revision-Date: 2016-05-09 01:31+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:37 links.py:31 models.py:145 views.py:521
@@ -28,6 +27,7 @@ msgid "Sources"
msgstr "Fuentes"
#: apps.py:53
#| msgid "Create new document sources"
msgid "Create a document source"
msgstr "Crear una nueva fuente de documentos"
@@ -36,10 +36,7 @@ msgid ""
"Document sources are the way in which new documents are feed to Mayan EDMS, "
"create at least a web form source to be able to upload documents from a "
"browser."
msgstr ""
"Las fuentes de documentos son la manera en la que se almacenan nuevos "
"documentos en Mayan EDMS. Crea por lo menos una fuente del tipo formulario "
"web para poder cargar documentos desde un navegador."
msgstr "Las fuentes de documentos son la manera en la que se almacenan nuevos documentos en Mayan EDMS. Crea por lo menos una fuente del tipo formulario web para poder cargar documentos desde un navegador."
#: apps.py:65
msgid "Created"
@@ -67,8 +64,7 @@ msgstr "Expandir archivos comprimidos"
#: forms.py:46
msgid "Upload a compressed file's contained files as individual documents"
msgstr ""
"Subir los archivos de un archivo comprimido como documentos individuales"
msgstr "Subir los archivos de un archivo comprimido como documentos individuales"
#: forms.py:67 views.py:432
msgid "Staging file"
@@ -250,8 +246,7 @@ msgstr "Intérvalo"
#: models.py:273
msgid "Assign a document type to documents uploaded from this source."
msgstr ""
"Asignar un tipo de documento a los documentos subidos desde esta fuente"
msgstr "Asignar un tipo de documento a los documentos subidos desde esta fuente"
#: models.py:275
msgid "Document type"
@@ -281,9 +276,7 @@ msgstr "SSL"
msgid ""
"Typical choices are 110 for POP3, 995 for POP3 over SSL, 143 for IMAP, 993 "
"for IMAP over SSL."
msgstr ""
"Las opciones típicas son 110 para POP3, 995 para POP3 sobre SSL, 143 para "
"IMAP, 993 para IMAP sobre SSL."
msgstr "Las opciones típicas son 110 para POP3, 995 para POP3 sobre SSL, 143 para IMAP, 993 para IMAP sobre SSL."
#: models.py:338
msgid "Port"
@@ -302,7 +295,7 @@ msgid ""
"Name of the attachment that will contains the metadata type names and value "
"pairs to be assigned to the rest of the downloaded attachments. Note: This "
"attachment has to be the first attachment."
msgstr ""
msgstr "Nombre del archivo adjunto que contiene los nombres de los tipos de metadatos y los pares de valores que se asignará al resto de los archivos adjuntos descargados. Nota: Este anejo tiene que ser el primer archivo adjunto."
#: models.py:349
msgid "Metadata attachment name"
@@ -315,8 +308,9 @@ msgid ""
msgstr ""
#: models.py:356
#| msgid "Current metadata"
msgid "Subject metadata type"
msgstr ""
msgstr "Tipo de metadatos de asunto "
#: models.py:360
msgid ""
@@ -326,15 +320,15 @@ msgstr ""
#: models.py:363
msgid "From metadata type"
msgstr ""
msgstr "Tipo de metadato de remitente"
#: models.py:367
msgid "Store the body of the email as a text document."
msgstr ""
msgstr "Almacenar el cuerpo del correo electrónico como un documento de texto."
#: models.py:368
msgid "Store email body"
msgstr ""
msgstr "Almacenar cuerpo del correo electrónico"
#: models.py:377
#, python-format
@@ -417,6 +411,7 @@ msgstr ""
#: tasks.py:31
#, python-format
#| msgid "Error creating source; %s"
msgid "Error processing source: %s"
msgstr "Error procesando fuente: %s"
@@ -431,13 +426,12 @@ msgstr "Entradas de bitácora para fuente: %s"
#: views.py:129 wizards.py:49
msgid ""
"No interactive document sources have been defined or none have been enabled, "
"create one before proceeding."
msgstr ""
"No se han definido fuentes de documentos interactivos o no hay ninguna "
"habilitada, cree una antes de continuar."
"No interactive document sources have been defined or none have been enabled,"
" create one before proceeding."
msgstr "No se han definido fuentes de documentos interactivos o no hay ninguna habilitada, cree una antes de continuar."
#: views.py:155 views.py:173
#| msgid "Document sources"
msgid "Document properties"
msgstr "Propiedades de documento"
@@ -460,10 +454,9 @@ msgid "Document \"%s\" is blocked from uploading new versions."
msgstr ""
#: views.py:381
msgid "New document version queued for uploaded and will be available shortly."
msgstr ""
"Nueva versión del documento en cola para ser cargado, estará disponible en "
"breve."
msgid ""
"New document version queued for uploaded and will be available shortly."
msgstr "Nueva versión del documento en cola para ser cargado, estará disponible en breve."
#: views.py:419
#, python-format
@@ -477,6 +470,7 @@ msgstr "Crear nuevo tipo de fuente: %s"
#: views.py:480
#, python-format
#| msgid "Delete document sources"
msgid "Delete the source: %s?"
msgstr "¿Eliminar la fuente: %s?"
@@ -595,11 +589,9 @@ msgstr ""
#~ msgstr "Error deleting source transformation; %(error)s"
#~ msgid ""
#~ "Are you sure you wish to delete source transformation \"%(transformation)s"
#~ "\""
#~ "Are you sure you wish to delete source transformation \"%(transformation)s\""
#~ msgstr ""
#~ "Are you sure you wish to delete source transformation \"%(transformation)s"
#~ "\""
#~ "Are you sure you wish to delete source transformation \"%(transformation)s\""
#~ msgid "Source transformation created successfully"
#~ msgstr "Source transformation created successfully"

View File

@@ -25,9 +25,12 @@ from user_management.tests import (
from ..links import link_upload_version
from ..literals import SOURCE_CHOICE_WEB_FORM
from ..models import StagingFolderSource, WebFormSource
from ..permissions import permission_staging_file_delete
from ..permissions import (
permission_sources_setup_create, permission_sources_setup_delete,
permission_sources_setup_view, permission_staging_file_delete
)
TEST_SOURCE_LABEL = 'test'
TEST_SOURCE_LABEL = 'test source'
TEST_SOURCE_UNCOMPRESS_N = 'n'
TEST_STAGING_PREVIEW_WIDTH = 640
@@ -285,3 +288,125 @@ class StagingFolderTestCase(GenericViewTestCase):
self.assertContains(response, 'deleted', status_code=200)
self.assertEqual(len(list(staging_folder.get_files())), 0)
class SourcesTestCase(GenericDocumentViewTestCase):
def create_web_source(self):
self.source = WebFormSource.objects.create(
enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N
)
def test_source_list_view_with_permission(self):
self.create_web_source()
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
)
self.role.permissions.add(
permission_sources_setup_view.stored_permission
)
response = self.get(viewname='sources:setup_source_list')
self.assertContains(response, text=self.source.label, status_code=200)
def test_source_list_view_no_permission(self):
self.create_web_source()
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
)
response = self.get(viewname='sources:setup_source_list')
self.assertEqual(response.status_code, 403)
def test_source_create_view_with_permission(self):
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
)
self.role.permissions.add(
permission_sources_setup_create.stored_permission
)
self.role.permissions.add(
permission_sources_setup_view.stored_permission
)
response = self.post(
args=(SOURCE_CHOICE_WEB_FORM,), follow=True,
viewname='sources:setup_source_create', data={
'enabled': True, 'label': TEST_SOURCE_LABEL,
'uncompress': TEST_SOURCE_UNCOMPRESS_N
}
)
webform_source = WebFormSource.objects.first()
self.assertEqual(webform_source.label, TEST_SOURCE_LABEL)
self.assertEqual(webform_source.uncompress, TEST_SOURCE_UNCOMPRESS_N)
self.assertEquals(response.status_code, 200)
def test_source_create_view_no_permission(self):
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
)
self.role.permissions.add(
permission_sources_setup_view.stored_permission
)
response = self.post(
args=(SOURCE_CHOICE_WEB_FORM,), follow=True,
viewname='sources:setup_source_create', data={
'enabled': True, 'label': TEST_SOURCE_LABEL,
'uncompress': TEST_SOURCE_UNCOMPRESS_N
}
)
self.assertEqual(response.status_code, 403)
self.assertEqual(WebFormSource.objects.count(), 0)
def test_source_delete_view_with_permission(self):
self.create_web_source()
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
)
self.role.permissions.add(
permission_sources_setup_delete.stored_permission
)
self.role.permissions.add(
permission_sources_setup_view.stored_permission
)
response = self.post(
args=(self.source.pk,), follow=True,
viewname='sources:setup_source_delete'
)
self.assertEqual(response.status_code, 200)
self.assertEqual(WebFormSource.objects.count(), 0)
def test_source_delete_view_no_permission(self):
self.create_web_source()
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
)
self.role.permissions.add(
permission_sources_setup_view.stored_permission
)
response = self.post(
args=(self.source.pk,), follow=True,
viewname='sources:setup_source_delete'
)
self.assertEqual(response.status_code, 403)
self.assertEqual(WebFormSource.objects.count(), 1)

View File

@@ -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:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2015
# Roberto Rosario, 2015-2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:16-0400\n"
"PO-Revision-Date: 2016-03-21 21:12+0000\n"
"PO-Revision-Date: 2016-05-09 01:32+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:33 apps.py:73 apps.py:90 forms.py:34 forms.py:52 links.py:40
@@ -37,7 +36,7 @@ msgstr "Documentos"
#: forms.py:53
msgid "Tags to attach to the document."
msgstr ""
msgstr "Etiquetas para anejar al documento."
#: links.py:14
msgid "Remove tag"
@@ -190,16 +189,22 @@ msgstr "Quitar etiqueta de los documentos: %s."
#: views.py:344
#, python-format
#| msgid ""
#| "u sure you wish to remove the tag \"%(tag)s\" from the document: ment)s?"
msgid "Remove the tag \"%(tag)s\" from the document: %(document)s?"
msgstr "¿Remover la etiqueta \"%(tag)s\" del documento: %(document)s?"
#: views.py:351
#, python-format
#| msgid ""
#| "u sure you wish to remove the tag \"%(tag)s\" from the documents: ments)s?"
msgid "Remove the tag \"%(tag)s\" from the documents: %(documents)s?"
msgstr "¿Remover la etiqueta \"%(tag)s\" de los documentos: %(documents)s?"
#: views.py:360
#, python-format
#| msgid ""
#| "u sure you wish to remove the tags: %(tags)s from the document: ment)s?"
msgid "Remove the tags: %(tags)s from the document: %(document)s?"
msgstr "¿Remover las etiquetas: %(tags)s del documento: %(document)s?"
@@ -216,8 +221,7 @@ msgstr "Documento \"%(document)s\" no estaba etiquetado como \"%(tag)s \""
#: views.py:388
#, python-format
msgid "Tag \"%(tag)s\" removed successfully from document \"%(document)s\"."
msgstr ""
"Etiqueta \"%(tag)s\" eliminada con éxito del documento \"%(document)s\"."
msgstr "Etiqueta \"%(tag)s\" eliminada con éxito del documento \"%(document)s\"."
#~ msgid "remove tags"
#~ msgstr "remove tags"

View File

@@ -1,26 +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:
# Translators:
# jmcainzos <jmcainzos@vodafone.es>, 2014
# jmcainzos <jmcainzos@vodafone.es>, 2015
# Lory977 <helga.carrero@gmail.com>, 2015
# Roberto Rosario, 2012,2015
# Roberto Rosario, 2016
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-27 14:16-0400\n"
"PO-Revision-Date: 2016-03-21 21:12+0000\n"
"PO-Revision-Date: 2016-05-09 01:33+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/"
"language/es/)\n"
"Language: es\n"
"Language-Team: Spanish (http://www.transifex.com/rosarior/mayan-edms/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"
#: apps.py:29 permissions.py:7
@@ -130,12 +130,13 @@ msgstr "Editar grupo: %s"
#: views.py:66
#, python-format
#| msgid "Delete existing groups"
msgid "Delete the group: %s?"
msgstr "¿Borrar el grupo: %s?"
#: views.py:72
msgid "Available users"
msgstr ""
msgstr "Usuarios disponibles"
#: views.py:73
msgid "Members of groups"
@@ -177,9 +178,7 @@ msgstr "Debe indicar al menos un usuario."
msgid ""
"Super user and staff user deleting is not allowed, use the admin interface "
"for these cases."
msgstr ""
"No se permite eliminar el super usuario y usuario de personal. Use la "
"interfaz de administración para estos casos."
msgstr "No se permite eliminar el super usuario y usuario de personal. Use la interfaz de administración para estos casos."
#: views.py:237
#, python-format
@@ -193,11 +192,13 @@ msgstr "Error eliminando el usuario \"%(user)s\": %(error)s "
#: views.py:255
#, python-format
#| msgid "Delete existing users"
msgid "Delete the user: %s?"
msgstr "¿Borrar el usuario: %s?"
#: views.py:257
#, python-format
#| msgid "Delete existing users"
msgid "Delete the users: %s?"
msgstr "¿Borrar los usuarios: %s?"
@@ -209,9 +210,7 @@ msgstr "Las contraseñas no coinciden. Vuelva a intentarlo."
msgid ""
"Super user and staff user password reseting is not allowed, use the admin "
"interface for these cases."
msgstr ""
"No se permite cambiar la contraseña del super usuario y del usuario de "
"personal. Use la interfaz de administración para estos casos."
msgstr "No se permite cambiar la contraseña del super usuario y del usuario de personal. Use la interfaz de administración para estos casos."
#: views.py:319
#, python-format
@@ -221,8 +220,7 @@ msgstr "Contraseña restablecida para el usuario: %s."
#: views.py:325
#, python-format
msgid "Error reseting password for user \"%(user)s\": %(error)s"
msgstr ""
"Error restaurando la contraseña para el usuario \"%(user)s\": %(error)s "
msgstr "Error restaurando la contraseña para el usuario \"%(user)s\": %(error)s "
#: views.py:342
#, python-format

View File

@@ -40,14 +40,14 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
write_only_fields = ('password',)
def create(self, validated_data):
groups = validated_data.pop('groups')
is_active = validated_data.pop('is_active')
validated_data.pop('groups')
validated_data.pop('is_active')
user = get_user_model().objects.create_user(**validated_data)
return user
def update(self, instance, validated_data):
groups = validated_data.pop('groups')
validated_data.pop('groups')
if 'password' in validated_data:
instance.set_password(validated_data['password'])

View File

@@ -4,7 +4,6 @@ from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from ..tests.literals import (
@@ -12,8 +11,8 @@ from ..tests.literals import (
)
from .literals import (
TEST_GROUP, TEST_USER_EMAIL, TEST_USER_PASSWORD, TEST_USER_PASSWORD_EDITED,
TEST_USER_USERNAME, TEST_USER_USERNAME_EDITED
TEST_USER_EMAIL, TEST_USER_PASSWORD, TEST_USER_USERNAME,
TEST_USER_USERNAME_EDITED
)

View File

@@ -1,2 +1,2 @@
-r base.txt
Django==1.8.11
Django==1.8.13

View File

@@ -56,13 +56,13 @@ def find_packages(directory):
return packages
install_requires = """
Django==1.8.11
Django==1.8.13
Pillow==3.1.0
PyYAML==3.11
celery==3.1.19
cssmin==0.2.0
django-activity-stream==0.6.0
django-autoadmin==1.1.0
django-autoadmin==1.1.1
django-celery==3.1.17
django-colorful==1.1.0
django-compressor==2.0