Merge branch 'hotfix/v0.12.1' into development

Conflicts:
	apps/converter/conf/settings.py
	apps/documents/__init__.py
	apps/main/__init__.py
	apps/metadata/__init__.py
	apps/navigation/templatetags/navigation_tags.py
	apps/ocr/__init__.py
	apps/ocr/conf/settings.py
	docs/intro/installation.rst
	docs/releases/index.rst
	requirements/production.txt
This commit is contained in:
Roberto Rosario
2012-06-03 22:50:33 -04:00
91 changed files with 2080 additions and 574 deletions

View File

@@ -3,14 +3,15 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# #
# Translators: # Translators:
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
# Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012. # Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-21 00:41+0000\n" "PO-Revision-Date: 2012-03-21 14:55+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -20,7 +21,7 @@ msgstr ""
#: __init__.py:14 #: __init__.py:14
msgid "ACLs" msgid "ACLs"
msgstr "" msgstr "ACL"
#: __init__.py:15 __init__.py:23 #: __init__.py:15 __init__.py:23
msgid "details" msgid "details"
@@ -36,19 +37,19 @@ msgstr "revocare"
#: __init__.py:18 __init__.py:24 forms.py:21 #: __init__.py:18 __init__.py:24 forms.py:21
msgid "New holder" msgid "New holder"
msgstr "" msgstr "Nuovo titolare"
#: __init__.py:20 #: __init__.py:20
msgid "Default ACLs" msgid "Default ACLs"
msgstr "" msgstr "Default ACL"
#: __init__.py:21 #: __init__.py:21
msgid "List of classes" msgid "List of classes"
msgstr "" msgstr "Elenco delle classi"
#: __init__.py:22 #: __init__.py:22
msgid "ACLs for class" msgid "ACLs for class"
msgstr "" msgstr "ACL per la classe"
#: forms.py:38 #: forms.py:38
msgid "Users" msgid "Users"
@@ -60,7 +61,7 @@ msgstr "Gruppi"
#: forms.py:44 #: forms.py:44
msgid "Roles" msgid "Roles"
msgstr "" msgstr "Ruoli"
#: forms.py:47 #: forms.py:47
msgid "Special" msgid "Special"
@@ -68,7 +69,7 @@ msgstr "Speciale"
#: managers.py:116 managers.py:128 #: managers.py:116 managers.py:128
msgid "Insufficient access." msgid "Insufficient access."
msgstr "" msgstr "Accesso insufficiente."
#: models.py:27 models.py:69 #: models.py:27 models.py:69
msgid "permission" msgid "permission"
@@ -76,19 +77,19 @@ msgstr "autorizzazione"
#: models.py:53 #: models.py:53
msgid "access entry" msgid "access entry"
msgstr "" msgstr "voce di accesso"
#: models.py:54 #: models.py:54
msgid "access entries" msgid "access entries"
msgstr "" msgstr "voci di accesso"
#: models.py:90 #: models.py:90
msgid "default access entry" msgid "default access entry"
msgstr "" msgstr "accesso voce predefinita"
#: models.py:91 #: models.py:91
msgid "default access entries" msgid "default access entries"
msgstr "" msgstr "voci di accesso predefinite "
#: models.py:109 #: models.py:109
msgid "Creator" msgid "Creator"
@@ -100,32 +101,32 @@ msgstr "creatore"
#: permissions.py:7 permissions.py:8 #: permissions.py:7 permissions.py:8
msgid "Access control lists" msgid "Access control lists"
msgstr "" msgstr "Liste di controllo accessi"
#: permissions.py:10 #: permissions.py:10
msgid "Edit ACLs" msgid "Edit ACLs"
msgstr "" msgstr "Modifica ACL"
#: permissions.py:11 #: permissions.py:11
msgid "View ACLs" msgid "View ACLs"
msgstr "" msgstr "Visualizza ACL"
#: permissions.py:13 #: permissions.py:13
msgid "Edit class default ACLs" msgid "Edit class default ACLs"
msgstr "" msgstr "Modifica ACL predefiniti di classe"
#: permissions.py:14 #: permissions.py:14
msgid "View class default ACLs" msgid "View class default ACLs"
msgstr "" msgstr "Visualizza classi ACL predefinite"
#: views.py:47 #: views.py:47
#, python-format #, python-format
msgid "access control lists for: %s" msgid "access control lists for: %s"
msgstr "" msgstr "lista controllo accessi per: %s"
#: views.py:49 views.py:411 #: views.py:49 views.py:411
msgid "holder" msgid "holder"
msgstr "" msgstr "titolare"
#: views.py:50 views.py:412 #: views.py:50 views.py:412
msgid "permissions" msgid "permissions"
@@ -138,11 +139,11 @@ msgstr "autorizzazioni disponibili per: %(actor)s per %(obj)s "
#: views.py:104 views.py:444 #: views.py:104 views.py:444
msgid "namespace" msgid "namespace"
msgstr "" msgstr "namespace"
#: views.py:105 views.py:445 #: views.py:105 views.py:445
msgid "label" msgid "label"
msgstr "" msgstr "etichetta"
#: views.py:107 views.py:447 #: views.py:107 views.py:447
msgid "has permission" msgid "has permission"
@@ -175,14 +176,14 @@ msgstr "Sei sicuro di voler concedere permessi %(title_suffix)s?"
#: views.py:199 views.py:542 #: views.py:199 views.py:542
#, python-format #, python-format
msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s." msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
msgstr "" msgstr "Permesso \"%(permission)s\" concesso%(actor)s per %(object)s."
#: views.py:205 views.py:548 #: views.py:205 views.py:548
#, python-format #, python-format
msgid "" msgid ""
"%(actor)s, already had the permission \"%(permission)s\" granted for " "%(actor)s, already had the permission \"%(permission)s\" granted for "
"%(object)s." "%(object)s."
msgstr "" msgstr "%(actor)s, ha già i permessi\"%(permission)s\" concessi per%(object)s."
#: views.py:281 views.py:610 #: views.py:281 views.py:610
#, python-format #, python-format
@@ -202,17 +203,17 @@ msgstr "Sei sicuro di voler revocare permessi %(title_suffix)s?"
#: views.py:293 views.py:622 #: views.py:293 views.py:622
#, python-format #, python-format
msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s." msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
msgstr "" msgstr "Permessi \"%(permission)s\" revocati al %(actor)s per %(object)s."
#: views.py:299 views.py:628 #: views.py:299 views.py:628
#, python-format #, python-format
msgid "%(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 "" msgstr "%(actor)s, non ha i permessi\"%(permission)s\" per %(object)s."
#: views.py:355 #: views.py:355
#, python-format #, python-format
msgid "add new holder for: %s" msgid "add new holder for: %s"
msgstr "" msgstr "aggiungi nuovo titolare per: %s"
#: views.py:356 views.py:488 #: views.py:356 views.py:488
msgid "Select" msgid "Select"
@@ -220,23 +221,23 @@ msgstr "Selezionare"
#: views.py:388 #: views.py:388
msgid "classes" msgid "classes"
msgstr "" msgstr "classi"
#: views.py:390 #: views.py:390
msgid "class" msgid "class"
msgstr "" msgstr "classe"
#: views.py:409 #: views.py:409
#, python-format #, python-format
msgid "default access control lists for class: %s" msgid "default access control lists for class: %s"
msgstr "" msgstr "lista di default per il controllo accessi per la classe: %s"
#: views.py:437 #: views.py:437
#, python-format #, python-format
msgid "permissions available to: %(actor)s for class %(class)s" msgid "permissions available to: %(actor)s for class %(class)s"
msgstr "" msgstr "permessi disponibili per: %(actor)s per la classe %(class)s"
#: views.py:486 #: views.py:486
#, python-format #, python-format
msgid "add new holder for class: %s" msgid "add new holder for class: %s"
msgstr "" msgstr "aggiungi un nuovo titolare per la calsse: %s"

View File

@@ -4,14 +4,15 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
# Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012. # Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-21 16:35+0000\n" "PO-Revision-Date: 2012-03-21 13:21+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -99,7 +100,7 @@ msgstr "Orizontale"
#: models.py:16 #: models.py:16
msgid "lock field" msgid "lock field"
msgstr "" msgstr "blocca campo"
#: models.py:43 #: models.py:43
msgid "Anonymous user" msgid "Anonymous user"

View File

@@ -396,3 +396,38 @@ def encapsulate(function):
def id_generator(size=6, chars=string.ascii_uppercase + string.digits): def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for x in range(size)) return ''.join(random.choice(chars) for x in range(size))
def get_descriptor(file_input, read=True):
try:
# Is it a file like object?
file_input.seek(0)
except AttributeError:
# If not, try open it.
if read:
return open(file_input, 'rb')
else:
return open(file_input, 'wb')
else:
return file_input
#http://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python
def copyfile(source, destination, buffer_size=1024 * 1024):
"""
Copy a file from source to dest. source and dest
can either be strings or any object with a read or
write method, like StringIO for example.
"""
source_descriptor = get_descriptor(source)
destination_descriptor = get_descriptor(destination, read=False)
while True:
copy_buffer = source_descriptor.read(buffer_size)
if copy_buffer:
destination_descriptor.write(copy_buffer)
else:
break
source_descriptor.close()
destination_descriptor.close()

View File

@@ -3,6 +3,7 @@ from __future__ import absolute_import
import os import os
import subprocess import subprocess
import hashlib import hashlib
import logging
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
@@ -20,6 +21,8 @@ from .exceptions import OfficeConversionError, UnknownFileFormat
HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest()
logger = logging.getLogger(__name__)
def cache_cleanup(input_filepath, *args, **kwargs): def cache_cleanup(input_filepath, *args, **kwargs):
try: try:
@@ -100,9 +103,11 @@ def convert(input_filepath, output_filepath=None, cleanup_files=False, mimetype=
def get_page_count(input_filepath): def get_page_count(input_filepath):
logger.debug('office_converter: %s' % office_converter)
if office_converter: if office_converter:
try: try:
office_converter.convert(input_filepath) office_converter.convert(input_filepath)
logger.debug('office_converter.exists: %s' % office_converter.exists)
if office_converter.exists: if office_converter.exists:
input_filepath = office_converter.output_filepath input_filepath = office_converter.output_filepath

View File

@@ -15,15 +15,6 @@ Setting(
exists=True, exists=True,
) )
Setting(
namespace=namespace,
name='IM_CONVERT_PATH',
global_name='CONVERTER_IM_CONVERT_PATH',
default=u'/usr/bin/convert',
description=_(u'File path to imagemagick\'s convert program.'),
exists=True,
)
Setting( Setting(
namespace=namespace, namespace=namespace,
name='IM_IDENTIFY_PATH', name='IM_IDENTIFY_PATH',
@@ -75,6 +66,16 @@ Setting(
description=_(u'Use alternate method of connection to LibreOffice using a pipe, it is slower but less prone to segmentation faults.'), description=_(u'Use alternate method of connection to LibreOffice using a pipe, it is slower but less prone to segmentation faults.'),
) )
Setting(
namespace=namespace,
name='LIBREOFFICE_PATH',
global_name='CONVERTER_LIBREOFFICE_PATH',
default=u'/usr/bin/libreoffice',
description=_(u'Path to the libreoffice program.'),
exists=True
)
#{'name': u'OCR_OPTIONS', 'global_name': u'CONVERTER_OCR_OPTIONS', 'default': u'-colorspace Gray -depth 8 -resample 200x200'}, #{'name': u'OCR_OPTIONS', 'global_name': u'CONVERTER_OCR_OPTIONS', 'default': u'-colorspace Gray -depth 8 -resample 200x200'},
#{'name': u'HIGH_QUALITY_OPTIONS', 'global_name': u'CONVERTER_HIGH_QUALITY_OPTIONS', 'default': u'-density 400'}, #{'name': u'HIGH_QUALITY_OPTIONS', 'global_name': u'CONVERTER_HIGH_QUALITY_OPTIONS', 'default': u'-density 400'},
#{'name': u'PRINT_QUALITY_OPTIONS', 'global_name': u'CONVERTER_PRINT_QUALITY_OPTIONS', 'default': u'-density 500'}, #{'name': u'PRINT_QUALITY_OPTIONS', 'global_name': u'CONVERTER_PRINT_QUALITY_OPTIONS', 'default': u'-density 500'},

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 14:53+0000\n" "PO-Revision-Date: 2011-12-09 14:53+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:15 #: __init__.py:15
@@ -474,8 +473,7 @@ msgstr "Magick Image File Format"
#: literals.py:177 #: literals.py:177
msgid "" 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 "" 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)"
#: literals.py:178 #: literals.py:178
msgid "Raw Bi-level bitmap in least-significant-byte first order" msgid "Raw Bi-level bitmap in least-significant-byte first order"
@@ -636,24 +634,19 @@ msgstr "Portable Network Graphics (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
#: literals.py:227 #: literals.py:227
msgid "" msgid ""
"24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)" "24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
msgstr "" msgstr "24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
"24-bit RGB PNG, opaque only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
#: literals.py:228 #: literals.py:228
msgid "" msgid ""
"32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib " "32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib "
"1.2.3.3,1.2.3.4)" "1.2.3.3,1.2.3.4)"
msgstr "" msgstr "32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
"32-bit RGBA PNG, semitransparency OK (libpng 1.2.42,1.2.44, zlib "
"1.2.3.3,1.2.3.4)"
#: literals.py:229 #: literals.py:229
msgid "" msgid ""
"8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib " "8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib "
"1.2.3.3,1.2.3.4)" "1.2.3.3,1.2.3.4)"
msgstr "" msgstr "8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib 1.2.3.3,1.2.3.4)"
"8-bit indexed PNG, binary transparency only (libpng 1.2.42,1.2.44, zlib "
"1.2.3.3,1.2.3.4)"
#: literals.py:230 #: literals.py:230
msgid "Portable anymap" msgid "Portable anymap"
@@ -913,12 +906,10 @@ msgstr "File path per il progarmma "
#: conf/settings.py:15 #: conf/settings.py:15
msgid "" msgid ""
"Graphics conversion backend to use. Options are: converter.backends." "Graphics conversion backend to use. Options are: "
"imagemagick, converter.backends.graphicsmagick and converter.backends.python." "converter.backends.imagemagick, converter.backends.graphicsmagick and "
msgstr "" "converter.backends.python."
"Backend da usare per la conversione grafica. Le opzioni sono: converter." msgstr "Backend da usare per la conversione grafica. Le opzioni sono: converter.backends.imagemagick, converter.backends.graphicsmagick e converter.backends.python."
"backends.imagemagick, converter.backends.graphicsmagick e converter.backends."
"python."
#: conf/settings.py:16 #: conf/settings.py:16
msgid "Path to the unoconv program." msgid "Path to the unoconv program."
@@ -926,11 +917,9 @@ msgstr "Path per il programma unoconv"
#: conf/settings.py:17 #: conf/settings.py:17
msgid "" msgid ""
"Use alternate method of connection to LibreOffice using a pipe, it is slower " "Use alternate method of connection to LibreOffice using a pipe, it is slower"
"but less prone to segmentation faults." " but less prone to segmentation faults."
msgstr "" msgstr "Utilizzare il metodo alternativo di collegamento a LibreOffice utilizzando questo collegamento, è più lento ma meno soggetto a errori di segmentazione."
"Utilizzare il metodo alternativo di collegamento a LibreOffice utilizzando "
"questo collegamento, è più lento ma meno soggetto a errori di segmentazione."
#: templates/converter_file_formats_help.html:3 #: templates/converter_file_formats_help.html:3
msgid "Help" msgid "Help"
@@ -941,6 +930,4 @@ msgstr "Aiuto"
msgid "" msgid ""
"These are the file formats supported by the currently selected converter " "These are the file formats supported by the currently selected converter "
"backend. In this case: '%(backend)s'" "backend. In this case: '%(backend)s'"
msgstr "" msgstr "Questi sono il formati file supportati dal backend selezionato.In questo caso : '%(backend)s'"
"Questi sono il formati file supportati dal backend selezionato.In questo "
"caso : '%(backend)s'"

View File

@@ -8,7 +8,7 @@ from mimetype.api import get_mimetype
from common.conf.settings import TEMPORARY_DIRECTORY from common.conf.settings import TEMPORARY_DIRECTORY
from common.utils import id_generator from common.utils import id_generator
from .conf.settings import UNOCONV_PATH, UNOCONV_USE_PIPE from .conf.settings import UNOCONV_PATH, UNOCONV_USE_PIPE, LIBREOFFICE_PATH
from .exceptions import (OfficeConversionError, from .exceptions import (OfficeConversionError,
OfficeBackendError, UnknownFileFormat) OfficeBackendError, UnknownFileFormat)
@@ -38,7 +38,7 @@ logger = logging.getLogger(__name__)
class OfficeConverter(object): class OfficeConverter(object):
def __init__(self): def __init__(self):
self.backend_class = OfficeConverterBackendUnoconv self.backend_class = OfficeConverterBackendDirect
self.backend = self.backend_class() self.backend = self.backend_class()
self.exists = False self.exists = False
self.mimetype = None self.mimetype = None
@@ -86,9 +86,9 @@ class OfficeConverterBackendUnoconv(object):
raise OfficeBackendError('cannot find unoconv executable') raise OfficeBackendError('cannot find unoconv executable')
def convert(self, input_filepath, output_filepath): def convert(self, input_filepath, output_filepath):
''' """
Executes the program unoconv using subprocess's Popen Executes the program unoconv using subprocess's Popen
''' """
self.input_filepath = input_filepath self.input_filepath = input_filepath
self.output_filepath = output_filepath self.output_filepath = output_filepath
@@ -118,3 +118,54 @@ class OfficeConverterBackendUnoconv(object):
raise OfficeBackendError(msg) raise OfficeBackendError(msg)
except Exception, msg: except Exception, msg:
logger.error('Unhandled exception', exc_info=msg) logger.error('Unhandled exception', exc_info=msg)
class OfficeConverterBackendDirect(object):
def __init__(self):
self.libreoffice_path = LIBREOFFICE_PATH if LIBREOFFICE_PATH else u'/usr/bin/libreoffice'
if not os.path.exists(self.libreoffice_path):
raise OfficeBackendError('cannot find LibreOffice executable')
logger.debug('self.libreoffice_path: %s' % self.libreoffice_path)
def convert(self, input_filepath, output_filepath):
"""
Executes libreoffice using subprocess's Popen
"""
self.input_filepath = input_filepath
self.output_filepath = output_filepath
command = []
command.append(self.libreoffice_path)
command.append(u'--headless')
command.append(u'--convert-to')
command.append(u'pdf')
command.append(self.input_filepath)
command.append(u'--outdir')
command.append(TEMPORARY_DIRECTORY)
logger.debug('command: %s' % command)
try:
os.environ['HOME'] = TEMPORARY_DIRECTORY
proc = subprocess.Popen(command, close_fds=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
return_code = proc.wait()
logger.debug('return_code: %s' % return_code)
readline = proc.stderr.readline()
logger.debug('stderr: %s' % readline)
if return_code != 0:
raise OfficeBackendError(readline)
filename, extension = os.path.splitext(os.path.basename(self.input_filepath))
logger.debug('filename: %s' % filename)
logger.debug('extension: %s' % extension)
converted_output = os.path.join(TEMPORARY_DIRECTORY, os.path.extsep.join([filename, 'pdf']))
logger.debug('converted_output: %s' % converted_output)
os.rename(converted_output, self.output_filepath)
except OSError, msg:
raise OfficeBackendError(msg)
except Exception, msg:
logger.error('Unhandled exception', exc_info=msg)

View File

@@ -4,29 +4,6 @@ from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module from django.utils.importlib import import_module
#http://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python
def copyfile(source, dest, buffer_size=1024 * 1024):
"""
Copy a file from source to dest. source and dest
can either be strings or any object with a read or
write method, like StringIO for example.
"""
if not hasattr(source, 'read'):
source = open(source, 'rb')
if not hasattr(dest, 'write'):
dest = open(dest, 'wb')
while 1:
copy_buffer = source.read(buffer_size)
if copy_buffer:
dest.write(copy_buffer)
else:
break
source.close()
dest.close()
def _lazy_load(fn): def _lazy_load(fn):
_cached = [] _cached = []

View File

@@ -4,19 +4,19 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:20+0000\n" "PO-Revision-Date: 2012-03-21 13:33+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:14 views.py:67 #: __init__.py:14 views.py:67
@@ -77,9 +77,7 @@ msgstr "Errore di firma"
#: api.py:60 #: api.py:60
msgid "Document is signed but no public key is available for verification." msgid "Document is signed but no public key is available for verification."
msgstr "" msgstr "Il documento è stato firmato, ma la chiave pubblica non è disponibile per la verifica"
"Il documento è stato firmato, ma la chiave pubblica non è disponibile per la "
"verifica"
#: api.py:64 #: api.py:64
msgid "Document is signed, and signature is good." msgid "Document is signed, and signature is good."
@@ -103,7 +101,7 @@ msgstr "Nome, e-mail,key ID , impronte digitali per cercare"
#: permissions.py:7 #: permissions.py:7
msgid "Key management" msgid "Key management"
msgstr "" msgstr "Gestione delle chiavi"
#: permissions.py:9 #: permissions.py:9
msgid "View keys" msgid "View keys"
@@ -119,7 +117,7 @@ msgstr "Interroga l'autorità per le chiavi"
#: permissions.py:12 #: permissions.py:12
msgid "Import keys from keyservers" msgid "Import keys from keyservers"
msgstr "" msgstr "Importa le chiavi dal server di chiavi"
#: views.py:38 #: views.py:38
#, python-format #, python-format
@@ -129,7 +127,7 @@ msgstr "Chiave: %s, importata con successo."
#: views.py:43 #: views.py:43
#, python-format #, python-format
msgid "Unable to import key id: %(key_id)s; %(error)s" msgid "Unable to import key id: %(key_id)s; %(error)s"
msgstr "" msgstr "Impossibile importare chiave id: %(key_id)s ; %(error)s "
#: views.py:52 #: views.py:52
msgid "Import key" msgid "Import key"
@@ -163,10 +161,7 @@ msgid ""
"Are you sure you wish to delete key: %s? If you try to delete a public key " "Are you sure you wish to delete key: %s? If you try to delete a public key "
"that is part of a public/private pair the private key will be deleted as " "that is part of a public/private pair the private key will be deleted as "
"well." "well."
msgstr "" msgstr "Sei sicuro di voler cancellare la chiave: %s? Se provi a cancellare una chiave pubblica che è parte di una coppia publica/privata anche la chiave privata sarà cancellata"
"Sei sicuro di voler cancellare la chiave: %s? Se provi a cancellare una "
"chiave pubblica che è parte di una coppia publica/privata anche la chiave "
"privata sarà cancellata"
#: views.py:129 #: views.py:129
msgid "Query key server" msgid "Query key server"
@@ -218,4 +213,4 @@ msgstr "Lista di server per chiavi che si possono interrogare."
#: conf/settings.py:16 #: conf/settings.py:16
msgid "Home directory used to store keys as well as configuration files." msgid "Home directory used to store keys as well as configuration files."
msgstr "" msgstr "Home directory utilizzata per memorizzare le chiavi così come i file di configurazione."

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:20+0000\n" "PO-Revision-Date: 2012-02-02 18:20+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:19 __init__.py:20 #: __init__.py:19 __init__.py:20

View File

@@ -4,19 +4,19 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:18+0000\n" "PO-Revision-Date: 2012-03-21 14:44+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36 #: __init__.py:31 __init__.py:45 __init__.py:47 models.py:42 views.py:36
@@ -30,23 +30,23 @@ msgstr "lista indici"
#: __init__.py:33 views.py:74 #: __init__.py:33 views.py:74
msgid "create index" msgid "create index"
msgstr "" msgstr "creare un indice"
#: __init__.py:34 __init__.py:39 #: __init__.py:34 __init__.py:39
msgid "edit" msgid "edit"
msgstr "" msgstr "modificare"
#: __init__.py:35 __init__.py:40 #: __init__.py:35 __init__.py:40
msgid "delete" msgid "delete"
msgstr "" msgstr "cancellare"
#: __init__.py:36 #: __init__.py:36
msgid "tree template" msgid "tree template"
msgstr "" msgstr "albero di template"
#: __init__.py:38 #: __init__.py:38
msgid "new child node" msgid "new child node"
msgstr "" msgstr "nuovo nodo figlio"
#: __init__.py:44 #: __init__.py:44
msgid "go up one level" msgid "go up one level"
@@ -73,17 +73,13 @@ msgstr "Massimo dei suffissi contati (%s) ."
#, python-format #, python-format
msgid "" msgid ""
"Error in document indexing update expression: %(expression)s; %(exception)s" "Error in document indexing update expression: %(expression)s; %(exception)s"
msgstr "" msgstr "Errore nella creazione dell'indice per l'espressione: %(expression)s; %(exception)s"
"Errore nella creazione dell'indice per l'espressione: %(expression)s; "
"%(exception)s"
#: api.py:96 api.py:111 #: api.py:96 api.py:111
#, python-format #, python-format
msgid "" msgid ""
"Error updating document index, expression: %(expression)s; %(exception)s" "Error updating document index, expression: %(expression)s; %(exception)s"
msgstr "" msgstr "Errore nell'aggiornamento delle'indice documento per l'espressione: %(expression)s; %(exception)s"
"Errore nell'aggiornamento delle'indice documento per l'espressione: "
"%(expression)s; %(exception)s"
#: api.py:150 #: api.py:150
#, python-format #, python-format
@@ -100,9 +96,7 @@ msgstr "Impossibile creare la directory per gli indici; %s"
msgid "" msgid ""
"Unable to create symbolic link, file exists and could not be deleted: " "Unable to create symbolic link, file exists and could not be deleted: "
"%(filepath)s; %(exc)s" "%(filepath)s; %(exc)s"
msgstr "" msgstr "Impossibile creare un link simbolico, il file già esiste e non può essere cancellato: %(filepath)s; %(exc)s"
"Impossibile creare un link simbolico, il file già esiste e non può essere "
"cancellato: %(filepath)s; %(exc)s"
#: filesystem.py:71 #: filesystem.py:71
#, python-format #, python-format
@@ -126,27 +120,28 @@ msgstr "Funzioni disponibili: %s"
#: models.py:17 views.py:40 #: models.py:17 views.py:40
msgid "name" msgid "name"
msgstr "" msgstr "nome"
#: models.py:17 #: models.py:17
msgid "Internal name used to reference this index." msgid "Internal name used to reference this index."
msgstr "" msgstr "Nome interno utilizzato per fare riferimento a questo indice."
#: models.py:18 views.py:41 #: models.py:18 views.py:41
msgid "title" msgid "title"
msgstr "" msgstr "titolo"
#: models.py:18 #: models.py:18
msgid "The name that will be visible to users." msgid "The name that will be visible to users."
msgstr "" msgstr "Il nome che sarà visibile agli utenti."
#: models.py:19 models.py:50 #: models.py:19 models.py:50
msgid "enabled" msgid "enabled"
msgstr "abilitato" msgstr "abilitato"
#: models.py:19 #: models.py:19
msgid "Causes this index to be visible and updated when document data changes." msgid ""
msgstr "" "Causes this index to be visible and updated when document data changes."
msgstr "Fa sì che questo indice possa essere visibile e aggiornato quando i dati del documento cambiano."
#: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159 #: models.py:41 models.py:47 views.py:101 views.py:132 views.py:159
#: views.py:195 views.py:225 views.py:265 #: views.py:195 views.py:225 views.py:265
@@ -163,7 +158,7 @@ msgstr "Inserisci una espressione python perchè possa essere valutata."
#: models.py:50 #: models.py:50
msgid "Causes this node to be visible and updated when document data changes." msgid "Causes this node to be visible and updated when document data changes."
msgstr "" msgstr "Fa sì che questo nodo possa essere visibili e aggiornato quando i dati del documento cambiano."
#: models.py:51 #: models.py:51
msgid "link documents" msgid "link documents"
@@ -171,17 +166,17 @@ msgstr "link al documento"
#: models.py:51 #: models.py:51
msgid "" msgid ""
"Check this option to have this node act as a container for documents and not " "Check this option to have this node act as a container for documents and not"
"as a parent for further nodes." " as a parent for further nodes."
msgstr "" msgstr "Selezionare questa opzione per questo specifico nodo quale contenitore per i documenti e non come un genitore per ulteriori nodi."
#: models.py:57 models.py:63 #: models.py:57 models.py:63
msgid "index template node" msgid "index template node"
msgstr "" msgstr "indice di nodo modello"
#: models.py:58 #: models.py:58
msgid "indexes template nodes" msgid "indexes template nodes"
msgstr "" msgstr "indici nodi modello"
#: models.py:64 #: models.py:64
msgid "value" msgid "value"
@@ -193,11 +188,11 @@ msgstr "documenti"
#: models.py:75 #: models.py:75
msgid "index instance node" msgid "index instance node"
msgstr "" msgstr "indice dell'istanza nodo"
#: models.py:76 #: models.py:76
msgid "indexes instance nodes" msgid "indexes instance nodes"
msgstr "" msgstr "indici esempio di nodi"
#: models.py:80 #: models.py:80
msgid "index instance" msgid "index instance"
@@ -221,19 +216,19 @@ msgstr "Indicizzazione"
#: permissions.py:9 #: permissions.py:9
msgid "Configure document indexes" msgid "Configure document indexes"
msgstr "" msgstr "Configura gli indici dei documenti"
#: permissions.py:10 #: permissions.py:10
msgid "Create new document indexes" msgid "Create new document indexes"
msgstr "" msgstr "Creare nuovi indici documento"
#: permissions.py:11 #: permissions.py:11
msgid "Edit document indexes" msgid "Edit document indexes"
msgstr "" msgstr "Modifica gli indici dei documenti"
#: permissions.py:12 #: permissions.py:12
msgid "Delete document indexes" msgid "Delete document indexes"
msgstr "" msgstr "Eliminare gli indici dei documenti"
#: permissions.py:14 #: permissions.py:14
msgid "View document indexes" msgid "View document indexes"
@@ -249,80 +244,80 @@ msgstr "indici dei documenti"
#: views.py:68 #: views.py:68
msgid "Index created successfully." msgid "Index created successfully."
msgstr "" msgstr "Indice creato con successo."
#: views.py:92 #: views.py:92
msgid "Index edited successfully" msgid "Index edited successfully"
msgstr "" msgstr "Indice modificato con successo"
#: views.py:98 #: views.py:98
#, python-format #, python-format
msgid "edit index: %s" msgid "edit index: %s"
msgstr "" msgstr "modifica indice: %s"
#: views.py:123 #: views.py:123
#, python-format #, python-format
msgid "Index: %s deleted successfully." msgid "Index: %s deleted successfully."
msgstr "" msgstr "Indice: %s cancellato con successo."
#: views.py:125 #: views.py:125
#, python-format #, python-format
msgid "Index: %(index)s delete error: %(error)s" msgid "Index: %(index)s delete error: %(error)s"
msgstr "" msgstr "Indice: %(index)s errore di cancellazione: %(error)s"
#: views.py:137 #: views.py:137
#, python-format #, python-format
msgid "Are you sure you with to delete the index: %s?" msgid "Are you sure you with to delete the index: %s?"
msgstr "" msgstr "Sei sicuro di voler cancella l'indice: %s?"
#: views.py:162 #: views.py:162
#, python-format #, python-format
msgid "tree template nodes for index: %s" msgid "tree template nodes for index: %s"
msgstr "" msgstr "modello nodi della struttura per l'indice: %s"
#: views.py:165 #: views.py:165
msgid "level" msgid "level"
msgstr "" msgstr "livello"
#: views.py:186 #: views.py:186
msgid "Index template node created successfully." msgid "Index template node created successfully."
msgstr "" msgstr "Modello nodo indice creato con successo."
#: views.py:192 #: views.py:192
msgid "create child node" msgid "create child node"
msgstr "" msgstr "creare nodo figlio"
#: views.py:213 #: views.py:213
msgid "Index template node edited successfully" msgid "Index template node edited successfully"
msgstr "" msgstr "Template nodo Indice modificato con successo"
#: views.py:219 #: views.py:219
#, python-format #, python-format
msgid "edit index template node: %s" msgid "edit index template node: %s"
msgstr "" msgstr "modifica index template node: %s"
#: views.py:226 views.py:266 views.py:334 #: views.py:226 views.py:266 views.py:334
msgid "node" msgid "node"
msgstr "" msgstr "nodo"
#: views.py:248 #: views.py:248
#, python-format #, python-format
msgid "Node: %s deleted successfully." msgid "Node: %s deleted successfully."
msgstr "" msgstr "Nodo: %s cancellato con succcesso."
#: views.py:250 #: views.py:250
#, python-format #, python-format
msgid "Node: %(node)s delete error: %(error)s" msgid "Node: %(node)s delete error: %(error)s"
msgstr "" msgstr "Nodo: %(node)s errore di cancellazione: %(error)s"
#: views.py:259 #: views.py:259
#, python-format #, python-format
msgid "Are you sure you with to delete the index template node: %s?" msgid "Are you sure you with to delete the index template node: %s?"
msgstr "" msgstr "Sei sicuro di voler cancellare index template node: %s?"
#: views.py:283 #: views.py:283
msgid "nodes" msgid "nodes"
msgstr "" msgstr "nodi"
#: views.py:316 #: views.py:316
#, python-format #, python-format
@@ -339,9 +334,7 @@ msgstr "Sei sicuro di voler ricostruire l'indice ?"
#: views.py:364 #: views.py:364
msgid "On large databases this operation may take some time to execute." msgid "On large databases this operation may take some time to execute."
msgstr "" msgstr "Per un database di grosse dimensioni l'operazione protrebbe aver bisogno di tempo."
"Per un database di grosse dimensioni l'operazione protrebbe aver bisogno di "
"tempo."
#: views.py:370 #: views.py:370
msgid "Index rebuild completed successfully." msgid "Index rebuild completed successfully."
@@ -359,9 +352,9 @@ msgstr "Gli indici contengono: %s"
#: conf/settings.py:22 #: conf/settings.py:22
msgid "" msgid ""
"A dictionary that maps the index name and where on the filesystem that index " "A dictionary that maps the index name and where on the filesystem that index"
"will be mirrored." " will be mirrored."
msgstr "" msgstr "Un dizionario che associa il nome dell'indice e dove sul filesystem verrà copiato."
#: templates/indexing_help.html:3 #: templates/indexing_help.html:3
msgid "What are indexes?" msgid "What are indexes?"
@@ -369,6 +362,4 @@ msgstr "Cosa sono gli indici ?"
#: templates/indexing_help.html:4 #: templates/indexing_help.html:4
msgid "Indexes group documents into a tree like hierarchical structure." msgid "Indexes group documents into a tree like hierarchical structure."
msgstr "" msgstr "Gli Indici dei documenti rappresentano , nella forma di albero, la struttura gerarchica dei documenti stessi.."
"Gli Indici dei documenti rappresentano , nella forma di albero, la struttura "
"gerarchica dei documenti stessi.."

View File

@@ -3,19 +3,19 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# #
# Translators: # Translators:
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:20+0000\n" "PO-Revision-Date: 2012-03-21 14:23+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:83 #: __init__.py:83
@@ -36,7 +36,7 @@ msgstr "File della firma"
#: models.py:20 #: models.py:20
msgid "document version" msgid "document version"
msgstr "" msgstr "versione del documento"
#: models.py:21 #: models.py:21
msgid "signature file" msgid "signature file"
@@ -44,19 +44,19 @@ msgstr "file della firma"
#: models.py:22 #: models.py:22
msgid "has embedded signature" msgid "has embedded signature"
msgstr "" msgstr "ha incorporato la firma"
#: models.py:35 #: models.py:35
msgid "document version signature" msgid "document version signature"
msgstr "" msgstr "versione della firma del documento"
#: models.py:36 #: models.py:36
msgid "document version signatures" msgid "document version signatures"
msgstr "" msgstr "versione delle firme documento "
#: permissions.py:7 #: permissions.py:7
msgid "Document signatures" msgid "Document signatures"
msgstr "" msgstr "Firme documento"
#: permissions.py:8 #: permissions.py:8
msgid "Verify document signatures" msgid "Verify document signatures"

View File

@@ -4,14 +4,15 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
# Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012. # Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-21 00:37+0000\n" "PO-Revision-Date: 2012-03-21 13:44+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -102,13 +103,13 @@ msgstr "Trovare i file di documenti mancanti"
#: __init__.py:86 #: __init__.py:86
msgid "Clear the document image cache" msgid "Clear the document image cache"
msgstr "" msgstr "Svuota la cache immagine del documento"
#: __init__.py:86 #: __init__.py:86
msgid "" msgid ""
"Clear the graphics representations used to speed up the documents' display " "Clear the graphics representations used to speed up the documents' display "
"and interactive transformations results." "and interactive transformations results."
msgstr "" msgstr "Cancella le rappresentazioni grafiche utilizzate per accellerare la visualizzazione dei documenti e dei risultati interattivi trasformazioni."
#: __init__.py:89 #: __init__.py:89
msgid "page transformations" msgid "page transformations"
@@ -241,7 +242,7 @@ msgstr "Pagine nel documento (%s)"
#: forms.py:162 #: forms.py:162
msgid "Use the new version filename as the document filename" msgid "Use the new version filename as the document filename"
msgstr "" msgstr "Utilizza il nuovo nome di versione il nome del documento"
#: forms.py:178 #: forms.py:178
msgid "Quick document rename" msgid "Quick document rename"
@@ -253,11 +254,11 @@ msgstr "Versione aggiornamento"
#: forms.py:190 #: forms.py:190
msgid "Release level" msgid "Release level"
msgstr "" msgstr "Livello di versione"
#: forms.py:196 #: forms.py:196
msgid "Release level serial" msgid "Release level serial"
msgstr "" msgstr "Livello di versione sequenziale"
#: forms.py:204 #: forms.py:204
msgid "Comment" msgid "Comment"
@@ -280,7 +281,7 @@ msgid ""
"Download the document in the original format or in a compressed manner. " "Download the document in the original format or in a compressed manner. "
"This option is selectable only when downloading one document, for multiple " "This option is selectable only when downloading one document, for multiple "
"documents, the bundle will always be downloads as a compressed file." "documents, the bundle will always be downloads as a compressed file."
msgstr "" msgstr "Scarica il documento nel formato originale o in modo compresso. Questa opzione è selezionabile solo quando il download di un documento, per i documenti multipli, il bundle sarà sempre download come un file compresso."
#: literals.py:10 #: literals.py:10
msgid "Document creation" msgid "Document creation"
@@ -328,23 +329,23 @@ msgstr "Documento \"%(document)s\" cancellato il %(datetime)s da %(fullname)s."
#: literals.py:42 #: literals.py:42
msgid "final" msgid "final"
msgstr "" msgstr "finale"
#: literals.py:43 #: literals.py:43
msgid "alpha" msgid "alpha"
msgstr "" msgstr "alfa"
#: literals.py:44 #: literals.py:44
msgid "beta" msgid "beta"
msgstr "" msgstr "beta"
#: literals.py:45 #: literals.py:45
msgid "release candidate" msgid "release candidate"
msgstr "" msgstr "Release Candidate"
#: literals.py:46 #: literals.py:46
msgid "hotfix" msgid "hotfix"
msgstr "" msgstr "hotfix"
#: models.py:61 #: models.py:61
msgid "name" msgid "name"
@@ -375,37 +376,37 @@ msgstr "documento"
#: models.py:287 #: models.py:287
#, python-format #, python-format
msgid "Major %(major)i.%(minor)i, (new release)" msgid "Major %(major)i.%(minor)i, (new release)"
msgstr "" msgstr "Magiore %(major)i.%(minor)i, (new release)"
#: models.py:288 #: models.py:288
#, python-format #, python-format
msgid "Minor %(major)i.%(minor)i, (some updates)" msgid "Minor %(major)i.%(minor)i, (some updates)"
msgstr "" msgstr "Minore %(major)i.%(minor)i, (some updates)"
#: models.py:289 #: models.py:289
#, python-format #, python-format
msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)" msgid "Micro %(major)i.%(minor)i.%(micro)i, (fixes)"
msgstr "" msgstr "Micro %(major)i.%(minor)i.%(micro)i, (fixes)"
#: models.py:301 #: models.py:301
msgid "mayor" msgid "mayor"
msgstr "" msgstr "maggiore"
#: models.py:302 #: models.py:302
msgid "minor" msgid "minor"
msgstr "" msgstr "minore"
#: models.py:303 #: models.py:303
msgid "micro" msgid "micro"
msgstr "" msgstr "micro"
#: models.py:304 #: models.py:304
msgid "release level" msgid "release level"
msgstr "" msgstr "Livello di release"
#: models.py:305 #: models.py:305
msgid "serial" msgid "serial"
msgstr "" msgstr "sequenziale"
#: models.py:306 #: models.py:306
msgid "timestamp" msgid "timestamp"
@@ -732,7 +733,7 @@ msgstr "Il documento \"%s\" è ancora in modifica"
#: views.py:342 #: views.py:342
msgid "documents to be downloaded" msgid "documents to be downloaded"
msgstr "" msgstr "documenti da scaricare"
#: views.py:352 views.py:1337 #: views.py:352 views.py:1337
msgid "version" msgid "version"
@@ -740,11 +741,11 @@ msgstr "versione"
#: views.py:409 #: views.py:409
msgid "Download" msgid "Download"
msgstr "" msgstr "Scarica"
#: views.py:411 #: views.py:411
msgid "Return" msgid "Return"
msgstr "" msgstr "Ritorno"
#: views.py:445 #: views.py:445
#, python-format #, python-format
@@ -980,16 +981,16 @@ msgstr "crea il nome file per i documenti di tipo:%s"
#: views.py:1306 #: views.py:1306
msgid "Document image cache cleared successfully" msgid "Document image cache cleared successfully"
msgstr "" msgstr "Cancellata con successo la cache delle immagini dei documenti"
#: views.py:1308 #: views.py:1308
#, python-format #, python-format
msgid "Error clearing document image cache; %s" msgid "Error clearing document image cache; %s"
msgstr "" msgstr "Errore nella pulizia della cache del documento; %s"
#: views.py:1314 #: views.py:1314
msgid "Are you sure you wish to clear the document image cache?" msgid "Are you sure you wish to clear the document image cache?"
msgstr "" msgstr "Sei sicuro di voler cancellare la cache delle immagini del documento?"
#: views.py:1331 #: views.py:1331
#, python-format #, python-format
@@ -998,15 +999,15 @@ msgstr "versioni per documento: %s"
#: views.py:1341 #: views.py:1341
msgid "time and date" msgid "time and date"
msgstr "" msgstr "data e ora"
#: views.py:1345 #: views.py:1345
msgid "mimetype" msgid "mimetype"
msgstr "" msgstr "mimetype"
#: views.py:1349 #: views.py:1349
msgid "encoding" msgid "encoding"
msgstr "" msgstr "codifica"
#: views.py:1380 #: views.py:1380
msgid "Document version reverted successfully" msgid "Document version reverted successfully"

View File

@@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'DocumentVersion.mimetype'
db.alter_column('documents_documentversion', 'mimetype', self.gf('django.db.models.fields.CharField')(max_length=64, null=True))
# Changing field 'DocumentVersion.encoding'
db.alter_column('documents_documentversion', 'encoding', self.gf('django.db.models.fields.CharField')(max_length=64, null=True))
def backwards(self, orm):
# Changing field 'DocumentVersion.mimetype'
db.alter_column('documents_documentversion', 'mimetype', self.gf('django.db.models.fields.CharField')(max_length=64))
# Changing field 'DocumentVersion.encoding'
db.alter_column('documents_documentversion', 'encoding', self.gf('django.db.models.fields.CharField')(max_length=64))
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'comments.comment': {
'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"},
'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'object_pk': ('django.db.models.fields.TextField', [], {}),
'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}),
'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'documents.document': {
'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'},
'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'})
},
'documents.documentpage': {
'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'},
'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'})
},
'documents.documentpagetransformation': {
'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'},
'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'})
},
'documents.documenttype': {
'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '32'})
},
'documents.documenttypefilename': {
'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'},
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'documents.documentversion': {
'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'},
'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}),
'encoding': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {})
},
'documents.recentdocument': {
'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'},
'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'taggit.tag': {
'Meta': {'object_name': 'Tag'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
},
'taggit.taggeditem': {
'Meta': {'object_name': 'TaggedItem'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"})
}
}
complete_apps = ['documents']

View File

@@ -331,8 +331,8 @@ class DocumentVersion(models.Model):
# File related fields # File related fields
file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file'))
mimetype = models.CharField(max_length=64, default='', editable=False) mimetype = models.CharField(max_length=64, null=True, blank=True, editable=False)
encoding = models.CharField(max_length=64, default='', editable=False) encoding = models.CharField(max_length=64, null=True, blank=True, editable=False)
filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True)
checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False)

View File

@@ -21,7 +21,11 @@ def get_used_size(path, file_list):
def storage_count(path=u'.'): def storage_count(path=u'.'):
try:
directories, files = STORAGE_BACKEND().listdir(path) directories, files = STORAGE_BACKEND().listdir(path)
except OSError:
return 0, 0
else:
total_count = len(files) total_count = len(files)
total_size = get_used_size(path, files) total_size = get_used_size(path, files)
@@ -53,15 +57,15 @@ def get_statistics():
except NotImplementedError: except NotImplementedError:
pass pass
document_stats = DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Min('page_count'), Max('page_count'), Avg('page_count'))
paragraphs.extend( paragraphs.extend(
[ [
_(u'Document pages in database: %d') % DocumentPage.objects.only('pk',).count(), _(u'Document pages in database: %d') % DocumentPage.objects.only('pk',).count(),
_(u'Minimum amount of pages per document: %(page_count__min)d') % DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Min('page_count')), _(u'Minimum amount of pages per document: %d') % (document_stats['page_count__max'] or 0),
_(u'Maximum amount of pages per document: %(page_count__max)d') % DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Max('page_count')), _(u'Maximum amount of pages per document: %d') % (document_stats['page_count__max'] or 0),
_(u'Average amount of pages per document: %(page_count__avg)f') % DocumentVersion.objects.annotate(page_count=Count('documentpage')).aggregate(Avg('page_count')), _(u'Average amount of pages per document: %f') % (document_stats['page_count__avg'] or 0),
] ]
) )
#[(day_count['date_added'].strftime('%Y-%m-%d'), day_count['id__count']) for day_count in Document.objects.values('date_added').annotate(Count("id"))]
return { return {
'title': _(u'Document statistics'), 'title': _(u'Document statistics'),

View File

@@ -2,30 +2,6 @@ import os
from common.conf.settings import TEMPORARY_DIRECTORY from common.conf.settings import TEMPORARY_DIRECTORY
#http://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python
def copyfile(source, dest, buffer_size=1024 * 1024):
"""
Copy a file from source to dest. source and dest
can either be strings or any object with a read or
write method, like StringIO for example.
"""
if not hasattr(source, 'read'):
source = open(source, 'rb')
if not hasattr(dest, 'write'):
dest = open(dest, 'wb')
while True:
copy_buffer = source.read(buffer_size)
if copy_buffer:
dest.write(copy_buffer)
else:
break
source.close()
dest.close()
def document_save_to_temp_dir(document, filename, buffer_size=1024 * 1024): def document_save_to_temp_dir(document, filename, buffer_size=1024 * 1024):
temporary_path = os.path.join(TEMPORARY_DIRECTORY, filename) temporary_path = os.path.join(TEMPORARY_DIRECTORY, filename)
return document.save_to_file(temporary_path, buffer_size) return document.save_to_file(temporary_path, buffer_size)

View File

@@ -129,8 +129,8 @@ def document_view(request, document_id, advanced=False):
if advanced: if advanced:
document_properties_form = DocumentPropertiesForm(instance=document, extra_fields=[ document_properties_form = DocumentPropertiesForm(instance=document, extra_fields=[
{'label': _(u'Filename'), 'field': 'filename'}, {'label': _(u'Filename'), 'field': 'filename'},
{'label': _(u'File mimetype'), 'field': 'file_mimetype'}, {'label': _(u'File mimetype'), 'field': lambda x: x.file_mimetype or _(u'None')},
{'label': _(u'File mime encoding'), 'field': 'file_mime_encoding'}, {'label': _(u'File mime encoding'), 'field': lambda x: x.file_mime_encoding or _(u'None')},
{'label': _(u'File size'), 'field':lambda x: pretty_size(x.size) if x.size else '-'}, {'label': _(u'File size'), 'field':lambda x: pretty_size(x.size) if x.size else '-'},
{'label': _(u'Exists in storage'), 'field': 'exists'}, {'label': _(u'Exists in storage'), 'field': 'exists'},
{'label': _(u'File path in storage'), 'field': 'file'}, {'label': _(u'File path in storage'), 'field': 'file'},

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 15:32+0000\n" "PO-Revision-Date: 2011-12-09 15:32+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:5 #: __init__.py:5
@@ -62,8 +61,7 @@ msgstr "risultati della ricerca"
#: views.py:33 #: views.py:33
#, python-format #, python-format
msgid "results, (showing only %(shown_result_count)s out of %(result_count)s)" msgid "results, (showing only %(shown_result_count)s out of %(result_count)s)"
msgstr "" msgstr "risultati, (mostra esclusivamente %(shown_result_count)s di %(result_count)s)"
"risultati, (mostra esclusivamente %(shown_result_count)s di %(result_count)s)"
#: views.py:37 #: views.py:37
msgid "results" msgid "results"
@@ -100,9 +98,7 @@ msgstr "Aiuto"
msgid "" msgid ""
"Enter the desired search keywords separated by space. Only the top " "Enter the desired search keywords separated by space. Only the top "
"%(search_results_limit)s results will be available." "%(search_results_limit)s results will be available."
msgstr "" msgstr "Inserisci le parole da cercare separate da spazzi. Solo i primi %(search_results_limit)s saranno disponibili."
"Inserisci le parole da cercare separate da spazzi. Solo i primi "
"%(search_results_limit)s saranno disponibili."
#: templates/search_results.html:3 #: templates/search_results.html:3
msgid "Search results" msgid "Search results"

View File

@@ -4,14 +4,15 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
# Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012. # Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-21 00:25+0000\n" "PO-Revision-Date: 2012-03-21 13:23+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -53,7 +54,7 @@ msgstr "cartelle"
#: __init__.py:27 #: __init__.py:27
msgid "ACLs" msgid "ACLs"
msgstr "" msgstr "ACL"
#: forms.py:38 #: forms.py:38
msgid "Folder" msgid "Folder"

View File

@@ -4,19 +4,19 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:19+0000\n" "PO-Revision-Date: 2012-03-21 13:30+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:10 models.py:71 #: __init__.py:10 models.py:71
@@ -57,7 +57,7 @@ msgstr "Versioni"
#: permissions.py:8 #: permissions.py:8
msgid "Access the history of an object" msgid "Access the history of an object"
msgstr "" msgstr "Accedi alla storia di un oggetto"
#: views.py:27 #: views.py:27
msgid "history events" msgid "history events"

View File

@@ -4,19 +4,19 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:19+0000\n" "PO-Revision-Date: 2012-03-21 13:18+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:17 #: __init__.py:17
@@ -53,7 +53,7 @@ msgstr "crea condizioni"
#: __init__.py:31 #: __init__.py:31
msgid "ACLs" msgid "ACLs"
msgstr "" msgstr "ACL"
#: forms.py:50 #: forms.py:50
msgid "Pages" msgid "Pages"
@@ -148,10 +148,7 @@ msgid ""
"This expression will be evaluated against the current selected document. " "This expression will be evaluated against the current selected document. "
"The document metadata is available as variables `metadata` and document " "The document metadata is available as variables `metadata` and document "
"properties under the variable `document`." "properties under the variable `document`."
msgstr "" msgstr "Questa espressione sarà valutata per il documento corrente selezionato. I metadati del documento sono disponibile come variabili `metadati` e le proprietà dei documenti sotto la variabile `documento`."
"Questa espressione sarà valutata per il documento corrente selezionato. I "
"metadati del documento sono disponibile come variabili `metadati` e le "
"proprietà dei documenti sotto la variabile `documento`."
#: models.py:14 models.py:33 views.py:136 views.py:232 #: models.py:14 models.py:33 views.py:136 views.py:232
msgid "enabled" msgid "enabled"
@@ -173,9 +170,7 @@ msgstr "dati del documento estero"
msgid "" msgid ""
"This represents the metadata of all other documents. Available objects: " "This represents the metadata of all other documents. Available objects: "
"`document.<attribute>` and `metadata.<metadata_type_name>`." "`document.<attribute>` and `metadata.<metadata_type_name>`."
msgstr "" msgstr "Questo rappresenta i metadati di tutti gli altri documenti. Oggetti disponibili: `document.<attribute>` e `metadata.<metadata_type_name>`."
"Questo rappresenta i metadati di tutti gli altri documenti. Oggetti "
"disponibili: `document.<attribute>` e `metadata.<metadata_type_name>`."
#: models.py:31 #: models.py:31
msgid "expression" msgid "expression"
@@ -315,16 +310,12 @@ msgstr "Condizioni per il link intelligente: \"%s\" cancellato con successo."
#, python-format #, python-format
msgid "" msgid ""
"Error deleting smart link condition: %(smart_link_condition)s; %(error)s." "Error deleting smart link condition: %(smart_link_condition)s; %(error)s."
msgstr "" msgstr "Errore nella cancellazione del link intelligente: %(smart_link_condition)s; %(error)s."
"Errore nella cancellazione del link intelligente: %(smart_link_condition)s; "
"%(error)s."
#: views.py:333 #: views.py:333
#, python-format #, python-format
msgid "Are you sure you wish to delete smart link condition: \"%s\"?" msgid "Are you sure you wish to delete smart link condition: \"%s\"?"
msgstr "" msgstr "Sei sicuro di voler cancellare le condizioni per il link intelligente : \"%s\"?"
"Sei sicuro di voler cancellare le condizioni per il link intelligente : \"%s"
"\"?"
#: conf/settings.py:11 #: conf/settings.py:11
msgid "Show smart link that don't return any documents." msgid "Show smart link that don't return any documents."
@@ -341,10 +332,4 @@ msgid ""
"source, the results of these queries are a list of documents that relate in " "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 " "some manner to the document being displayed and allow users the ability to "
"jump to and from linked documents very easily." "jump to and from linked documents very easily."
msgstr "" msgstr "Collegamenti intelligenti sono un insieme di istruzioni condizionali che vengono utilizzati per interrogare il database utilizzando il documento corrente l'utente sta accedendo come origine dati, i risultati di queste query sono un elenco di documenti che riguardano in qualche modo al documento e consentire la visualizzazione agli utenti la possibilità di saltare da e per i documenti collegati molto facilmente."
"Collegamenti intelligenti sono un insieme di istruzioni condizionali che "
"vengono utilizzati per interrogare il database utilizzando il documento "
"corrente l'utente sta accedendo come origine dati, i risultati di queste "
"query sono un elenco di documenti che riguardano in qualche modo al "
"documento e consentire la visualizzazione agli utenti la possibilità di "
"saltare da e per i documenti collegati molto facilmente."

View File

@@ -4,14 +4,15 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-12 19:24+0000\n" "PO-Revision-Date: 2012-03-21 13:22+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@@ -139,9 +140,7 @@ msgstr "lookup"
msgid "" msgid ""
"Enter a string to be evaluated. Example: [user.get_full_name() for user in " "Enter a string to be evaluated. Example: [user.get_full_name() for user in "
"User.objects.all()].%s" "User.objects.all()].%s"
msgstr "" msgstr "Inserisci una stringa per la valutazione. Esempio: [user.get_full_name() per l'utente User.objects.all()].%s"
"Inserisci una stringa per la valutazione. Esempio: [user.get_full_name() "
"per l'utente User.objects.all()].%s"
#: models.py:33 models.py:58 views.py:353 views.py:398 #: models.py:33 models.py:58 views.py:353 views.py:398
msgid "metadata type" msgid "metadata type"
@@ -259,8 +258,7 @@ msgstr "Errore nella cancellazione degli indici di documento;%s"
#: views.py:99 #: views.py:99
#, python-format #, python-format
msgid "Error editing metadata for document %(document)s; %(error)s." msgid "Error editing metadata for document %(document)s; %(error)s."
msgstr "" msgstr "Errore nella modifica dei metadata per il documento %(document)s; %(error)s."
"Errore nella modifica dei metadata per il documento %(document)s; %(error)s."
#: views.py:102 #: views.py:102
#, python-format #, python-format
@@ -291,16 +289,13 @@ msgstr "Modifica metadata per i documenti: %s"
msgid "" msgid ""
"Metadata type: %(metadata_type)s successfully added to document " "Metadata type: %(metadata_type)s successfully added to document "
"%(document)s." "%(document)s."
msgstr "" msgstr "Tipo metadata: %(metadata_type)s aggiunto con successo al documento %(document)s."
"Tipo metadata: %(metadata_type)s aggiunto con successo al documento "
"%(document)s."
#: views.py:164 #: views.py:164
#, python-format #, python-format
msgid "" msgid ""
"Metadata type: %(metadata_type)s already present in document %(document)s." "Metadata type: %(metadata_type)s already present in document %(document)s."
msgstr "" msgstr "Tipo Metadata: %(metadata_type)s già presente per il documento %(document)s."
"Tipo Metadata: %(metadata_type)s già presente per il documento %(document)s."
#: views.py:188 #: views.py:188
#, python-format #, python-format
@@ -317,17 +312,13 @@ msgstr "Aggiungi tipo metadata ai documents: %s"
msgid "" msgid ""
"Successfully remove metadata type: %(metadata_type)s from document: " "Successfully remove metadata type: %(metadata_type)s from document: "
"%(document)s." "%(document)s."
msgstr "" msgstr "Rimuovere con successo tipo di metadati: %(metadata_type)s per il documento: %(document)s."
"Rimuovere con successo tipo di metadati: %(metadata_type)s per il "
"documento: %(document)s."
#: views.py:262 #: views.py:262
#, python-format #, python-format
msgid "" msgid ""
"Error removing metadata type: %(metadata_type)s from document: %(document)s." "Error removing metadata type: %(metadata_type)s from document: %(document)s."
msgstr "" msgstr "Errore durante la rimozione dei metadati di tipo: %(metadata_type)s per il documento: %(document)s."
"Errore durante la rimozione dei metadati di tipo: %(metadata_type)s per il "
"documento: %(document)s."
#: views.py:281 #: views.py:281
#, python-format #, python-format
@@ -424,7 +415,7 @@ msgstr "Sei sicuro di voler eliminare il set di metadati: %s?"
#: views.py:538 views.py:556 #: views.py:538 views.py:556
msgid "Metadata types" msgid "Metadata types"
msgstr "" msgstr "Tipi di Metadati"
#: views.py:594 #: views.py:594
#, python-format #, python-format
@@ -445,11 +436,7 @@ msgid ""
"A metadata set is a group of one or more metadata types. Metadata sets are " "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 " "useful when creating new documents; selecing a metadata set automatically "
"attaches it's member metadata types to said document." "attaches it's member metadata types to said document."
msgstr "" msgstr "Un insieme di metadati è un gruppo di uno o più tipi di metadati. Set di metadati sono utili durante la creazione di nuovi documenti e, selezionando un set di metadati allega automaticamente è membro tipi di metadati per documentare detto."
"Un insieme di metadati è un gruppo di uno o più tipi di metadati. Set di "
"metadati sono utili durante la creazione di nuovi documenti e, selezionando "
"un set di metadati allega automaticamente è membro tipi di metadati per "
"documentare detto."
#: templates/metadata_type_help.html:3 #: templates/metadata_type_help.html:3
msgid "What are metadata types?" msgid "What are metadata types?"
@@ -466,16 +453,4 @@ msgid ""
" will have initially, and the lookup value turns an instance of a metadata " " 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" "of this type into a choice list which options are the result of the lookup's"
" code execution." " code execution."
msgstr "" msgstr "Un tipo di metadati definisce le caratteristiche di un valore di qualche tipo che può essere collegato a un documento. Esempi di tipi di metadati: il nome del client, una data o un progetto a cui appartengono diversi documenti. Il nome di un tipo di metadati è l'identificatore interno con il quale possono essere pubblicati da altri moduli come il modulo di indicizzazione, il titolo è il valore che viene mostrato agli utenti, il valore predefinito è il valore di un'istanza di questo tipo di metadati avrà inizialmente, e il valore di ricerca si trasforma un'istanza di metadati di questo tipo in un elenco di opzioni di scelta che sono il risultato della esecuzione di codice la ricerca di."
"Un tipo di metadati definisce le caratteristiche di un valore di qualche "
"tipo che può essere collegato a un documento. Esempi di tipi di metadati: il"
" nome del client, una data o un progetto a cui appartengono diversi "
"documenti. Il nome di un tipo di metadati è l'identificatore interno con il "
"quale possono essere pubblicati da altri moduli come il modulo di "
"indicizzazione, il titolo è il valore che viene mostrato agli utenti, il "
"valore predefinito è il valore di un'istanza di questo tipo di metadati avrà"
" inizialmente, e il valore di ricerca si trasforma un'istanza di metadati di"
" questo tipo in un elenco di opzioni di scelta che sono il risultato della "
"esecuzione di codice la ricerca di."

View File

@@ -94,8 +94,8 @@ def get_mimetype(file_description, filepath, mimetype_only=False):
library via python-magic or fallback to use python's mimetypes library via python-magic or fallback to use python's mimetypes
library library
""" """
file_mimetype = u'' file_mimetype = None
file_mime_encoding = u'' file_mime_encoding = None
if USE_PYTHON_MAGIC: if USE_PYTHON_MAGIC:
mime = magic.Magic(mime=True) mime = magic.Magic(mime=True)
file_mimetype = mime.from_buffer(file_description.read()) file_mimetype = mime.from_buffer(file_description.read())

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 18:00+0000\n" "PO-Revision-Date: 2011-12-09 18:00+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: forms.py:14 #: forms.py:14

View File

@@ -3,11 +3,14 @@ from __future__ import absolute_import
import copy import copy
import re import re
import logging import logging
#import urlparse
#import urllib
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template import (TemplateSyntaxError, Library, from django.template import (TemplateSyntaxError, Library,
Node, Variable, VariableDoesNotExist) Node, Variable, VariableDoesNotExist)
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils.encoding import smart_str, force_unicode, smart_unicode
from ..api import (link_binding, multi_object_navigation, from ..api import (link_binding, multi_object_navigation,
sidebar_templates, get_context_navigation_links) sidebar_templates, get_context_navigation_links)
@@ -30,6 +33,184 @@ def get_top_menu_links(parser, token):
return TopMenuNavigationNode() return TopMenuNavigationNode()
'''
def resolve_arguments(context, src_args):
args = []
kwargs = {}
if type(src_args) == type([]):
for i in src_args:
val = resolve_template_variable(context, i)
if val:
args.append(val)
elif type(src_args) == type({}):
for key, value in src_args.items():
val = resolve_template_variable(context, value)
if val:
kwargs[key] = val
else:
val = resolve_template_variable(context, src_args)
if val:
args.append(val)
return args, kwargs
def resolve_links(context, links, current_view, current_path, parsed_query_string=None):
"""
Express a list of links from definition to final values
"""
context_links = []
for link in links:
# Check to see if link has conditional display
if 'condition' in link:
condition_result = link['condition'](context)
else:
condition_result = True
if condition_result:
new_link = copy.copy(link)
try:
args, kwargs = resolve_arguments(context, link.get('args', {}))
except VariableDoesNotExist:
args = []
kwargs = {}
if 'view' in link:
if not link.get('dont_mark_active', False):
new_link['active'] = link['view'] == current_view
try:
if kwargs:
new_link['url'] = reverse(link['view'], kwargs=kwargs)
else:
new_link['url'] = reverse(link['view'], args=args)
if link.get('keep_query', False):
print 'parsed_query_string', parsed_query_string
new_link['url'] = urlquote(new_link['url'], parsed_query_string)
except NoReverseMatch, err:
new_link['url'] = '#'
new_link['error'] = err
elif 'url' in link:
if not link.get('dont_mark_active', False):
new_link['active'] = link['url'] == current_path
if kwargs:
new_link['url'] = link['url'] % kwargs
else:
new_link['url'] = link['url'] % args
if link.get('keep_query', False):
new_link['url'] = urlquote(new_link['url'], parsed_query_string)
else:
new_link['active'] = False
if 'conditional_highlight' in link:
new_link['active'] = link['conditional_highlight'](context)
if 'conditional_disable' in link:
new_link['disabled'] = link['conditional_disable'](context)
else:
new_link['disabled'] = False
if current_view in link.get('children_views', []):
new_link['active'] = True
for child_url_regex in link.get('children_url_regex', []):
if re.compile(child_url_regex).match(current_path.lstrip('/')):
new_link['active'] = True
for children_view_regex in link.get('children_view_regex', []):
if re.compile(children_view_regex).match(current_view):
new_link['active'] = True
for cls in link.get('children_classes', []):
obj, object_name = get_navigation_object(context)
if type(obj) == cls or obj == cls:
new_link['active'] = True
context_links.append(new_link)
return context_links
def get_navigation_object(context):
try:
object_name = Variable('navigation_object_name').resolve(context)
except VariableDoesNotExist:
object_name = 'object'
try:
obj = Variable(object_name).resolve(context)
except VariableDoesNotExist:
obj = None
return obj, object_name
def _get_object_navigation_links(context, menu_name=None, links_dict=object_navigation):
request = Variable('request').resolve(context)
current_path = request.META['PATH_INFO']
current_view = resolve_to_name(current_path)
context_links = []
# Don't fudge with the original global dictionary
links_dict = links_dict.copy()
# Preserve unicode data in URL query
previous_path = smart_unicode(urllib.unquote_plus(smart_str(request.get_full_path()) or smart_str(request.META.get('HTTP_REFERER', u'/'))))
query_string = urlparse.urlparse(previous_path).query
parsed_query_string = urlparse.parse_qs(query_string)
try:
"""
Override the navigation links dictionary with the provided
link list
"""
navigation_object_links = Variable('overrided_object_links').resolve(context)
if navigation_object_links:
return [link for link in resolve_links(context, navigation_object_links, current_view, current_path, parsed_query_string)]
except VariableDoesNotExist:
pass
try:
"""
Check for and inject a temporary navigation dictionary
"""
temp_navigation_links = Variable('temporary_navigation_links').resolve(context)
if temp_navigation_links:
links_dict.update(temp_navigation_links)
except VariableDoesNotExist:
pass
try:
links = links_dict[menu_name][current_view]['links']
for link in resolve_links(context, links, current_view, current_path, parsed_query_string):
context_links.append(link)
except KeyError:
pass
obj, object_name = get_navigation_object(context)
try:
links = links_dict[menu_name][type(obj)]['links']
for link in resolve_links(context, links, current_view, current_path, parsed_query_string):
context_links.append(link)
except KeyError:
pass
return context_links
def resolve_template_variable(context, name):
try:
return unescape_string_literal(name)
except ValueError:
#return Variable(name).resolve(context)
#TODO: Research if should return always as a str
return str(Variable(name).resolve(context))
except TypeError:
return name
'''
class GetNavigationLinks(Node): class GetNavigationLinks(Node):
def __init__(self, menu_name=None, links_dict=link_binding, var_name='object_navigation_links'): def __init__(self, menu_name=None, links_dict=link_binding, var_name='object_navigation_links'):
self.menu_name = menu_name self.menu_name = menu_name

View File

@@ -50,7 +50,6 @@ setup_queue_transformation_edit = Link(text=_(u'edit'),view='setup_queue_transfo
setup_queue_transformation_delete = Link(text=_(u'delete'),view='setup_queue_transformation_delete',args='transformation.pk',sprite='shape_square_delete') setup_queue_transformation_delete = Link(text=_(u'delete'),view='setup_queue_transformation_delete',args='transformation.pk',sprite='shape_square_delete')
bind_links([Document], [submit_document]) bind_links([Document], [submit_document])
bind_links([DocumentQueue], [document_queue_disable, document_queue_enable, setup_queue_transformation_list]) bind_links([DocumentQueue], [document_queue_disable, document_queue_enable, setup_queue_transformation_list])
bind_links([QueueTransformation], [setup_queue_transformation_edit, setup_queue_transformation_delete]) bind_links([QueueTransformation], [setup_queue_transformation_edit, setup_queue_transformation_delete])

View File

@@ -2,6 +2,7 @@
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
<<<<<<< HEAD
from smart_settings.api import Setting, SettingNamespace from smart_settings.api import Setting, SettingNamespace
namespace = SettingNamespace('ocr', _(u'OCR'), module='ocr.conf.settings') namespace = SettingNamespace('ocr', _(u'OCR'), module='ocr.conf.settings')
@@ -61,3 +62,12 @@ Setting(
description=_(u'File path to unpaper program.'), description=_(u'File path to unpaper program.'),
exists=True exists=True
) )
Setting(
namespace=namespace,
name='PDFTOTEXT_PATH',
global_name='OCR_PDFTOTEXT_PATH',
default=u'/usr/bin/pdftotext',
description=_(u'File path to poppler\'s pdftotext program used to extract text from PDF files.'),
exists=True
)

View File

@@ -4,19 +4,19 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:19+0000\n" "PO-Revision-Date: 2012-03-21 13:29+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:32 __init__.py:33 #: __init__.py:32 __init__.py:33
@@ -47,9 +47,7 @@ msgstr "ripulisci il contenuto delle pagine"
msgid "" msgid ""
"Runs a language filter to remove common OCR mistakes from document pages " "Runs a language filter to remove common OCR mistakes from document pages "
"content." "content."
msgstr "" msgstr "Esegue un filtro per rimuovere i comuni errori di OCR dal contenuto del documento pagine."
"Esegue un filtro per rimuovere i comuni errori di OCR dal contenuto del "
"documento pagine."
#: __init__.py:44 #: __init__.py:44
msgid "queue document list" msgid "queue document list"
@@ -187,19 +185,19 @@ msgstr "code dei documenti in trasformazione"
#: permissions.py:8 #: permissions.py:8
msgid "Submit documents for OCR" msgid "Submit documents for OCR"
msgstr "" msgstr "Inviare documenti all OCR"
#: permissions.py:9 #: permissions.py:9
msgid "Delete documents from OCR queue" msgid "Delete documents from OCR queue"
msgstr "" msgstr "Cancella documenti dalla coda OCR"
#: permissions.py:10 #: permissions.py:10
msgid "Can enable/disable the OCR queue" msgid "Can enable/disable the OCR queue"
msgstr "" msgstr "Puoi abilitare/disabilitare la coda OCR"
#: permissions.py:11 #: permissions.py:11
msgid "Can execute the OCR clean up on all document pages" msgid "Can execute the OCR clean up on all document pages"
msgstr "" msgstr "Posso effettuare la pulizia dell OCR di tutte le pagine dei documenti"
#: permissions.py:12 #: permissions.py:12
msgid "Can edit an OCR queue properties" msgid "Can edit an OCR queue properties"
@@ -269,8 +267,7 @@ msgstr "Sei sicuro di voler cancellare queste code documento: %s?"
#: views.py:148 #: views.py:148
#, python-format #, python-format
msgid "Document: %(document)s was added to the OCR queue: %(queue)s." msgid "Document: %(document)s was added to the OCR queue: %(queue)s."
msgstr "" msgstr "Il documento: %(document)s è stato aggiunto alla coda %(queue)s per OCR."
"Il documento: %(document)s è stato aggiunto alla coda %(queue)s per OCR."
#: views.py:151 #: views.py:151
#, python-format #, python-format
@@ -381,9 +378,7 @@ msgstr "Errore nella cancellazione della coda di trasformazione; %(error)s"
#, python-format #, python-format
msgid "" msgid ""
"Are you sure you wish to delete queue transformation \"%(transformation)s\"" "Are you sure you wish to delete queue transformation \"%(transformation)s\""
msgstr "" msgstr "Sei sicuro di voler cancellare la coda di trasformazione \"%(transformation)s\""
"Sei sicuro di voler cancellare la coda di trasformazione \"%(transformation)s"
"\""
#: views.py:412 #: views.py:412
msgid "Queue transformation created successfully" msgid "Queue transformation created successfully"
@@ -403,15 +398,11 @@ msgstr "Crea una nuova coda di trasformazione:%s"
msgid "" msgid ""
"Amount of seconds to delay OCR of documents to allow for the node's storage " "Amount of seconds to delay OCR of documents to allow for the node's storage "
"replication overhead." "replication overhead."
msgstr "" msgstr "Quantità di secondi di ritardo OCR di documenti per consentire lo stoccaggio nel nodo di replica."
"Quantità di secondi di ritardo OCR di documenti per consentire lo stoccaggio "
"nel nodo di replica."
#: conf/settings.py:14 #: conf/settings.py:14
msgid "Maximum amount of concurrent document OCRs a node can perform." msgid "Maximum amount of concurrent document OCRs a node can perform."
msgstr "" msgstr "Importo massimo di documenti concorrenti per OCR che un nodo è in grado di eseguire."
"Importo massimo di documenti concorrenti per OCR che un nodo è in grado di "
"eseguire."
#: conf/settings.py:15 #: conf/settings.py:15
msgid "Automatically queue newly created documents for OCR." msgid "Automatically queue newly created documents for OCR."

View File

@@ -17,7 +17,8 @@ from sources.managers import SourceTransformationManager
from .literals import (DOCUMENTQUEUE_STATE_STOPPED, from .literals import (DOCUMENTQUEUE_STATE_STOPPED,
DOCUMENTQUEUE_STATE_CHOICES, QUEUEDOCUMENT_STATE_PENDING, DOCUMENTQUEUE_STATE_CHOICES, QUEUEDOCUMENT_STATE_PENDING,
QUEUEDOCUMENT_STATE_CHOICES, QUEUEDOCUMENT_STATE_PROCESSING) QUEUEDOCUMENT_STATE_CHOICES, QUEUEDOCUMENT_STATE_PROCESSING,
DOCUMENTQUEUE_STATE_ACTIVE)
from .managers import DocumentQueueManager from .managers import DocumentQueueManager
from .exceptions import ReQueueError from .exceptions import ReQueueError
@@ -27,7 +28,7 @@ class DocumentQueue(models.Model):
label = models.CharField(max_length=64, verbose_name=_(u'label')) label = models.CharField(max_length=64, verbose_name=_(u'label'))
state = models.CharField(max_length=4, state = models.CharField(max_length=4,
choices=DOCUMENTQUEUE_STATE_CHOICES, choices=DOCUMENTQUEUE_STATE_CHOICES,
default=DOCUMENTQUEUE_STATE_STOPPED, default=DOCUMENTQUEUE_STATE_ACTIVE,
verbose_name=_(u'state')) verbose_name=_(u'state'))
objects = DocumentQueueManager() objects = DocumentQueueManager()

View File

@@ -1,5 +1,8 @@
import os
import slate import slate
import logging import logging
import tempfile
import subprocess
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@@ -7,23 +10,70 @@ from converter import office_converter
from converter.office_converter import OfficeConverter from converter.office_converter import OfficeConverter
from converter.exceptions import OfficeConversionError from converter.exceptions import OfficeConversionError
from documents.utils import document_save_to_temp_dir from documents.utils import document_save_to_temp_dir
from common.utils import copyfile
from common.conf.settings import TEMPORARY_DIRECTORY
from ocr.parsers.exceptions import ParserError, ParserUnknownFile from ocr.parsers.exceptions import ParserError, ParserUnknownFile
from ocr.conf.settings import PDFTOTEXT_PATH
mimetype_registry = {} mimetype_registry = {}
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def register_parser(function, mimetype=None, mimetypes=None): def register_parser(mimetypes, parsers):
if mimetypes:
for mimetype in mimetypes: for mimetype in mimetypes:
mimetype_registry[mimetype] = {'function': function} for parser in parsers:
try:
parser_instance = parser()
except ParserError:
# If parser fails initialization is not added to the list for this mimetype
pass
else: else:
mimetype_registry[mimetype] = {'function': function} mimetype_registry.setdefault(mimetype, []).append(parser_instance)
def pdf_parser(document_page, descriptor=None): def parse_document_page(document_page, descriptor=None, mimetype=None):
logger.debug('executing')
logger.debug('document_page: %s' % document_page)
logger.debug('mimetype: %s' % document_page.document.file_mimetype)
if not mimetype:
mimetype = document_page.document.file_mimetype
try:
for parser in mimetype_registry[mimetype]:
try:
parser.parse(document_page, descriptor)
except ParserError:
# If parser raises error, try next parser in the list
pass
else:
# If parser was successfull there is no need to try
# others in the list for this mimetype
return
raise ParserError('Parser list exhausted')
except KeyError:
raise ParserUnknownFile
class Parser(object):
"""
Parser base class
"""
def parse(self, document_page, descriptor=None):
raise NotImplementedError("Your %s class has not defined a parse() method, which is required." % self.__class__.__name__)
class SlateParser(Parser):
"""
Parser for PDF files using the slate library for Python
"""
def parse(self, document_page, descriptor=None):
logger.debug('Starting SlateParser')
if not descriptor: if not descriptor:
descriptor = document_page.document_version.open() descriptor = document_page.document_version.open()
@@ -38,7 +88,11 @@ def pdf_parser(document_page, descriptor=None):
document_page.save() document_page.save()
def office_parser(document_page): class OfficeParser(Parser):
"""
Parser for office document formats
"""
def parse(self, document_page, descriptor=None):
logger.debug('executing') logger.debug('executing')
try: try:
office_converter = OfficeConverter() office_converter = OfficeConverter()
@@ -50,25 +104,66 @@ def office_parser(document_page):
input_filepath = office_converter.output_filepath input_filepath = office_converter.output_filepath
logger.debug('office_converter.output_filepath: %s', input_filepath) logger.debug('office_converter.output_filepath: %s', input_filepath)
pdf_parser(document_page, descriptor=open(input_filepath)) # Now that the office document has been converted to PDF
# call the coresponding PDF parser in this new file
parse_document_page(document_page, descriptor=open(input_filepath), mimetype=u'application/pdf')
else: else:
raise ParserError raise ParserError
except OfficeConversionError, msg: except OfficeConversionError, msg:
print msg logger.error(msg)
raise ParserError raise ParserError
def parse_document_page(document_page): class PopplerParser(Parser):
logger.debug('executing') """
logger.debug('document_page: %s' % document_page) PDF parser using the pdftotext execute from the poppler package
logger.debug('mimetype: %s' % document_page.document.file_mimetype) """
def __init__(self):
self.pdftotext_path = PDFTOTEXT_PATH if PDFTOTEXT_PATH else u'/usr/bin/pdftotext'
if not os.path.exists(self.pdftotext_path):
raise ParserError('cannot find pdftotext executable')
logger.debug('self.pdftotext_path: %s' % self.pdftotext_path)
try: def parse(self, document_page, descriptor=None):
mimetype_registry[document_page.document.file_mimetype]['function'](document_page) logger.debug('parsing PDF with PopplerParser')
except KeyError: pagenum = str(document_page.page_number)
raise ParserUnknownFile
if descriptor:
destination_descriptor, temp_filepath = tempfile.mkstemp(dir=TEMPORARY_DIRECTORY)
copyfile(descriptor, temp_filepath)
document_file = temp_filepath
else:
document_file = document_save_to_temp_dir(document_page.document, document_page.document.checksum)
logger.debug('document_file: %s', document_file)
logger.debug('parsing PDF page %s' % pagenum)
command = []
command.append(self.pdftotext_path)
command.append('-f')
command.append(pagenum)
command.append('-l')
command.append(pagenum)
command.append(document_file)
command.append('-')
proc = subprocess.Popen(command, close_fds=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
return_code = proc.wait()
if return_code != 0:
logger.error(proc.stderr.readline())
raise ParserError
output = proc.stdout.read()
if output == '\x0c':
logger.debug('Parser didn\'t any output')
raise ParserError('No output')
document_page.content = output
document_page.page_label = _(u'Text extracted from PDF')
document_page.save()
register_parser(mimetype=u'application/pdf', function=pdf_parser) register_parser(mimetypes=[u'application/pdf'], parsers=[PopplerParser, SlateParser])
register_parser(mimetypes=office_converter.CONVERTER_OFFICE_FILE_MIMETYPES, function=office_parser) register_parser(mimetypes=office_converter.CONVERTER_OFFICE_FILE_MIMETYPES, parsers=[OfficeParser])

View File

@@ -66,8 +66,7 @@ def task_process_document_queues():
oldest_queued_document = oldest_queued_document_qs.order_by('datetime_submitted')[0] oldest_queued_document = oldest_queued_document_qs.order_by('datetime_submitted')[0]
process_job(task_process_queue_document, oldest_queued_document.pk) process_job(task_process_queue_document, oldest_queued_document.pk)
except Exception, e: except Exception, e:
pass logger.error('unhandled exception: %s' % e)
#print 'DocumentQueueWatcher exception: %s' % e
finally: finally:
# Don't process anymore from this queryset, might be stale # Don't process anymore from this queryset, might be stale
break break

View File

@@ -4,19 +4,19 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-02 18:18+0000\n" "PO-Revision-Date: 2012-03-21 13:31+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:17 models.py:209 views.py:40 #: __init__.py:17 models.py:209 views.py:40
@@ -151,9 +151,7 @@ msgstr "%(requester)s, ha già il permesso \"%(permission)s\" concesso."
#, python-format #, python-format
msgid "" msgid ""
"Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?" "Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?"
msgstr "" msgstr "Sei sicuro che tu voglia concedere questo permesso %(permissions_label)s %(title_suffix)s?"
"Sei sicuro che tu voglia concedere questo permesso %(permissions_label)s "
"%(title_suffix)s?"
#: views.py:222 #: views.py:222
#, python-format #, python-format
@@ -169,21 +167,19 @@ msgstr "%(requester)s, non ha i permessi \"%(permission)s\" consentiti."
#, python-format #, python-format
msgid "" msgid ""
"Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?" "Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?"
msgstr "" msgstr "Sei sicuro di voler revocare questo permesso %(permissions_label)s %(title_suffix)s?"
"Sei sicuro di voler revocare questo permesso %(permissions_label)s "
"%(title_suffix)s?"
#: views.py:271 views.py:295 #: views.py:271 views.py:295
msgid "Users" msgid "Users"
msgstr "" msgstr "Utenti"
#: views.py:274 views.py:298 #: views.py:274 views.py:298
msgid "Groups" msgid "Groups"
msgstr "" msgstr "Gruppi"
#: views.py:277 views.py:301 #: views.py:277 views.py:301
msgid "Special" msgid "Special"
msgstr "" msgstr "Speciale"
#: views.py:330 #: views.py:330
#, python-format #, python-format
@@ -207,6 +203,4 @@ msgstr "Concessione"
msgid "" msgid ""
"A list of existing roles that are automatically assigned to newly created " "A list of existing roles that are automatically assigned to newly created "
"users" "users"
msgstr "" msgstr "Un elenco di ruoli esistenti che vengono automaticamente assegnati agli utenti appena creati"
"Un elenco di ruoli esistenti che vengono automaticamente assegnati agli "
"utenti appena creati"

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 18:08+0000\n" "PO-Revision-Date: 2011-12-09 18:08+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:6 #: __init__.py:6

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 18:01+0000\n" "PO-Revision-Date: 2011-12-09 18:01+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:7 views.py:15 #: __init__.py:7 views.py:15

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 17:38+0000\n" "PO-Revision-Date: 2011-12-09 17:38+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: __init__.py:9 views.py:28 #: __init__.py:9 views.py:28

View File

@@ -4,14 +4,15 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-12 19:23+0000\n" "PO-Revision-Date: 2012-03-21 14:07+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@@ -64,7 +65,7 @@ msgstr "Sorgente del documento"
#: __init__.py:38 #: __init__.py:38
msgid "upload new version" msgid "upload new version"
msgstr "" msgstr "Carica nuova versione"
#: __init__.py:68 widgets.py:39 #: __init__.py:68 widgets.py:39
msgid "thumbnail" msgid "thumbnail"
@@ -84,7 +85,7 @@ msgstr "Mostra file"
#: forms.py:50 #: forms.py:50
msgid "File" msgid "File"
msgstr "" msgstr "File"
#: literals.py:8 literals.py:13 #: literals.py:8 literals.py:13
msgid "Always" msgid "Always"
@@ -196,9 +197,7 @@ msgstr "anteprima larghezza"
#: models.py:159 #: models.py:159
msgid "Width value to be passed to the converter backend." msgid "Width value to be passed to the converter backend."
msgstr "" msgstr "valore della larghezza da passare per le operazioni di conversione in backend"
"valore della larghezza da passare per le operazioni di conversione in "
"backend"
#: models.py:160 #: models.py:160
msgid "preview height" msgid "preview height"
@@ -206,8 +205,7 @@ msgstr "anteprima altezza"
#: models.py:160 #: models.py:160
msgid "Height value to be passed to the converter backend." msgid "Height value to be passed to the converter backend."
msgstr "" msgstr "valore dell'altezza da passare per le operazioni di conversione in backend"
"valore dell'altezza da passare per le operazioni di conversione in backend"
#: models.py:161 models.py:198 models.py:211 #: models.py:161 models.py:198 models.py:211
msgid "uncompress" msgid "uncompress"
@@ -237,9 +235,7 @@ msgstr "intervallo"
msgid "" msgid ""
"Inverval in seconds where the watch folder path is checked for new " "Inverval in seconds where the watch folder path is checked for new "
"documents." "documents."
msgstr "" msgstr "Invervallo di pochi secondi in cui viene controllato il percorso cartella di controllo per i nuovi documenti."
"Invervallo di pochi secondi in cui viene controllato il percorso cartella di"
" controllo per i nuovi documenti."
#: models.py:237 #: models.py:237
msgid "watch folder" msgid "watch folder"
@@ -276,7 +272,7 @@ msgstr "trasformazioni dei documenti sorgente"
#: models.py:290 models.py:291 #: models.py:290 models.py:291
msgid "out of process" msgid "out of process"
msgstr "" msgstr "fuori del processo"
#: permissions.py:7 #: permissions.py:7
msgid "Sources setup" msgid "Sources setup"
@@ -328,41 +324,38 @@ msgstr "Sorgenti caricamento"
#: views.py:105 #: views.py:105
msgid "" msgid ""
"No interactive document sources have been defined or none have been enabled." "No interactive document sources have been defined or none have been enabled."
msgstr "" msgstr "Nessuna fonte interattiva dei documenti sono state definite o non ne sono state attivate."
"Nessuna fonte interattiva dei documenti sono state definite o non ne sono "
"state attivate."
#: views.py:106 #: views.py:106
#, python-format #, python-format
msgid "Click %(setup_link)s to add or enable some document sources." msgid "Click %(setup_link)s to add or enable some document sources."
msgstr "" msgstr "Click %(setup_link)s per aggiungere o abilitare una sorgente documenti."
"Click %(setup_link)s per aggiungere o abilitare una sorgente documenti."
#: views.py:163 #: views.py:163
msgid "New document version uploaded successfully." msgid "New document version uploaded successfully."
msgstr "" msgstr "Nuova versione del documento caricata con successo."
#: views.py:167 #: views.py:167
msgid "File uploaded successfully." msgid "File uploaded successfully."
msgstr "" msgstr "File caricato con successo."
#: views.py:170 #: views.py:170
msgid "File uncompressed successfully and uploaded as individual files." msgid "File uncompressed successfully and uploaded as individual files."
msgstr "" msgstr "File non compresso e caricato con successo come singolo file."
#: views.py:173 #: views.py:173
msgid "File was not a compressed file, uploaded as it was." msgid "File was not a compressed file, uploaded as it was."
msgstr "" msgstr "Il file non era un file compresso,è stato caricato così com'era."
#: views.py:179 views.py:258 #: views.py:179 views.py:258
#, python-format #, python-format
msgid "Unhandled exception: %s" msgid "Unhandled exception: %s"
msgstr "" msgstr "Eccezione non gestita: %s"
#: views.py:188 #: views.py:188
#, python-format #, python-format
msgid "upload a new version from source: %s" msgid "upload a new version from source: %s"
msgstr "" msgstr "caricata una nuova versione da: %s"
#: views.py:190 #: views.py:190
#, python-format #, python-format
@@ -372,7 +365,7 @@ msgstr "carica un documento in locale dalla sorgente: %s"
#: views.py:236 #: views.py:236
#, python-format #, python-format
msgid "Document version from staging file: %s, uploaded successfully." msgid "Document version from staging file: %s, uploaded successfully."
msgstr "" msgstr "Versione documento da gestione temporanea file: %s,caricata con successo"
#: views.py:239 #: views.py:239
#, python-format #, python-format
@@ -384,12 +377,12 @@ msgstr "File in allestimento:%s, caricato con successo."
msgid "" msgid ""
"Staging file: %s, uncompressed successfully and uploaded as individual " "Staging file: %s, uncompressed successfully and uploaded as individual "
"files." "files."
msgstr "" msgstr "file temporaneo: %s, non compresso e caricato come file singolo"
#: views.py:245 #: views.py:245
#, python-format #, python-format
msgid "Staging file: %s, was not compressed, uploaded as a single file." msgid "Staging file: %s, was not compressed, uploaded as a single file."
msgstr "" msgstr "file temporaneo: %s, non è stato compresso, caricato come file singolo."
#: views.py:250 #: views.py:250
#, python-format #, python-format
@@ -399,7 +392,7 @@ msgstr "File in allestimento:%s, cancellato con successo."
#: views.py:273 #: views.py:273
#, python-format #, python-format
msgid "upload a new version from staging source: %s" msgid "upload a new version from staging source: %s"
msgstr "" msgstr "caricata una nuova versione da file temporaneo: %s"
#: views.py:275 #: views.py:275
#, python-format #, python-format
@@ -412,11 +405,11 @@ msgstr "path dei file in allestimento"
#: views.py:320 #: views.py:320
msgid "Current document type" msgid "Current document type"
msgstr "" msgstr "Tipo di documento corrente"
#: views.py:321 #: views.py:321
msgid "None" msgid "None"
msgstr "" msgstr "Nessuno"
#: views.py:328 #: views.py:328
msgid "Current metadata" msgid "Current metadata"
@@ -510,16 +503,13 @@ msgstr "Sorgente per la trasformazione cancellata con successo."
#: views.py:646 #: views.py:646
#, python-format #, python-format
msgid "Error deleting source transformation; %(error)s" msgid "Error deleting source transformation; %(error)s"
msgstr "" msgstr "Erroro nella cancellazione della sorgente per la trasformazione; %(error)s"
"Erroro nella cancellazione della sorgente per la trasformazione; %(error)s"
#: views.py:659 #: views.py:659
#, python-format #, python-format
msgid "" msgid ""
"Are you sure you wish to delete source transformation \"%(transformation)s\"" "Are you sure you wish to delete source transformation \"%(transformation)s\""
msgstr "" msgstr "Sei sicuro di voler cancellare la sorgente di trasformazione \"%(transformation)s\""
"Sei sicuro di voler cancellare la sorgente di trasformazione "
"\"%(transformation)s\""
#: views.py:689 #: views.py:689
msgid "Source transformation created successfully" msgid "Source transformation created successfully"
@@ -534,5 +524,3 @@ msgstr "Errore nella creazione della sorgente di trasformazione; %s"
#, python-format #, python-format
msgid "Create new transformation for source: %s" msgid "Create new transformation for source: %s"
msgstr "Crea una nuova sorgente per la trasformazione:%s" msgstr "Crea una nuova sorgente per la trasformazione:%s"

View File

@@ -4,15 +4,16 @@
# #
# Translators: # Translators:
# <pierpaolo.baldan@gmail.com>, 2011. # <pierpaolo.baldan@gmail.com>, 2011.
# Pierpaolo Baldan <pierpaolo.baldan@gmail.com>, 2012.
# Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2011. # Roberto Rosario <roberto.rosario.gonzalez@gmail.com>, 2011.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2012-02-12 19:23+0000\n" "PO-Revision-Date: 2012-03-21 13:46+0000\n"
"Last-Translator: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/it/)\n" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@@ -53,11 +54,11 @@ msgstr "documenti etichettati"
#: __init__.py:30 #: __init__.py:30
msgid "ACLs" msgid "ACLs"
msgstr "" msgstr "ACLs"
#: __init__.py:34 #: __init__.py:34
msgid "preview" msgid "preview"
msgstr "" msgstr "anteprima"
#: __init__.py:38 #: __init__.py:38
msgid "tagged items" msgid "tagged items"
@@ -137,19 +138,19 @@ msgstr "Crea un nuova etichetta"
#: permissions.py:10 #: permissions.py:10
msgid "Delete tags" msgid "Delete tags"
msgstr "" msgstr "Eliminare i tag"
#: permissions.py:11 #: permissions.py:11
msgid "Edit tags" msgid "Edit tags"
msgstr "" msgstr "Modificare i tag"
#: permissions.py:12 #: permissions.py:12
msgid "View tags" msgid "View tags"
msgstr "" msgstr "Visualizzare i tag"
#: permissions.py:13 #: permissions.py:13
msgid "Attach tags to documents" msgid "Attach tags to documents"
msgstr "" msgstr "Applicare i tag ai documenti"
#: permissions.py:14 #: permissions.py:14
msgid "Remove tags from documents" msgid "Remove tags from documents"
@@ -247,5 +248,3 @@ msgstr "Sei sicuro di voler rimuovere le etichette: %s ?"
#: templatetags/tags_tags.py:17 #: templatetags/tags_tags.py:17
msgid "Add tag to document" msgid "Add tag to document"
msgstr "Aggiungi l'etichetta al documento" msgstr "Aggiungi l'etichetta al documento"

View File

@@ -7,16 +7,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Mayan EDMS\n" "Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: http://github.com/rosarior/mayan/issues\n"
"POT-Creation-Date: 2012-02-12 15:20-0400\n" "POT-Creation-Date: 2012-02-12 15:20-0400\n"
"PO-Revision-Date: 2011-12-09 18:07+0000\n" "PO-Revision-Date: 2011-12-09 18:07+0000\n"
"Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n" "Last-Translator: Pierpaolo Baldan <pierpaolo.baldan@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/team/" "Language-Team: Italian (http://www.transifex.net/projects/p/mayan-edms/language/it/)\n"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: conf/settings.py:10 #: conf/settings.py:10
@@ -24,10 +23,7 @@ msgid ""
"CSS theme to apply, options are: amro, bec, bec-green, blue, default, djime-" "CSS theme to apply, options are: amro, bec, bec-green, blue, default, djime-"
"cerulean, drastic-dark, kathleene, olive, orange, red, reidb-greenish and " "cerulean, drastic-dark, kathleene, olive, orange, red, reidb-greenish and "
"warehouse." "warehouse."
msgstr "" msgstr "Tema CSS da applicare, le opzioni sono: ABN AMRO, bec, bec-verde, blu, di default, djime-ceruleo, drastica-scuro, kathleene, oliva, arancio, rosso, reidb-verdastro e magazzino."
"Tema CSS da applicare, le opzioni sono: ABN AMRO, bec, bec-verde, blu, di "
"default, djime-ceruleo, drastica-scuro, kathleene, oliva, arancio, rosso, "
"reidb-verdastro e magazzino."
#: conf/settings.py:12 #: conf/settings.py:12
msgid "Display extra information in the login screen." msgid "Display extra information in the login screen."
@@ -66,9 +62,7 @@ msgstr "Reindirizzamento al tuo punto di ingresso al sito in 5 secondi."
msgid "" msgid ""
"Or click <a href=\"%(LOGIN_REDIRECT_URL)s\">here</a> if redirection doesn't " "Or click <a href=\"%(LOGIN_REDIRECT_URL)s\">here</a> if redirection doesn't "
"work." "work."
msgstr "" msgstr "Oppure click <a href=\"%(LOGIN_REDIRECT_URL)s\">qui</a> if per essere rimandato al tuo sito nel caso non funzioni."
"Oppure click <a href=\"%(LOGIN_REDIRECT_URL)s\">qui</a> if per essere "
"rimandato al tuo sito nel caso non funzioni."
#: templates/pagination/pagination.html:6 #: templates/pagination/pagination.html:6
#: templates/pagination/pagination.html:8 #: templates/pagination/pagination.html:8

BIN
contrib/fabfile.tar.gz Normal file

Binary file not shown.

View File

@@ -1,7 +0,0 @@
mysqldump mayan documents_metadatatype -u root -p | replace 'documents_metadatatype' 'metadata_metadatatype' > new_types.mysql
cat new_types.mysql | mysql -u root -p mayan
mysqldump mayan documents_documentmetadata -u root -p | replace 'documents_documentmetadata' 'metadata_documentmetadata' > new_metadata.mysql
cat new_metadata.mysql | mysql -u root -p mayan

View File

@@ -52,10 +52,10 @@ copyright = u'2011, Roberto Rosario'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.12' version = '0.12.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.12' release = '0.12.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@@ -15,7 +15,7 @@ Bug fixes
--------- ---------
* Aziz M. Bookwala (https://github.com/azizmb) * Aziz M. Bookwala (https://github.com/azizmb)
* IHLeanne (https://github.com/IHLeanne) * IHLeanne (https://github.com/IHLeanne)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Sergey Glita (s.v.glita@gmail.com)
* Meurig Freeman (https://github.com/meurig) * Meurig Freeman (https://github.com/meurig)
* David Herring (https://github.com/abadger1406) * David Herring (https://github.com/abadger1406)
@@ -27,24 +27,27 @@ Bug reports
* Joost Cassee (joost@cassee.net, https://github.com/jcassee) * Joost Cassee (joost@cassee.net, https://github.com/jcassee)
* Brian Huxley * Brian Huxley
* dAnjou (https://github.com/dAnjou) * dAnjou (https://github.com/dAnjou)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Sergey Glita (s.v.glita@gmail.com)
* IHLeanne (https://github.com/IHLeanne) * IHLeanne (https://github.com/IHLeanne)
* valterwill (https://github.com/valterwill) * valterwill (https://github.com/valterwill)
* David Herring (https://github.com/abadger1406) * David Herring (https://github.com/abadger1406)
* Alexandru Kiss (usurel@gmail.com)
Patches Patches
------- -------
* Meurig Freeman (https://github.com/meurig) * Meurig Freeman (https://github.com/meurig)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Sergey Glita (s.v.glita@gmail.com)
* Brian E (brian@realize.org)
Suggestions Suggestions
----------- -----------
* Cezar Jenkins (https://twitter.com/#!/emperorcezar) * Cezar Jenkins (https://twitter.com/#!/emperorcezar)
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Sergey Glita (s.v.glita@gmail.com)
* Barry Rowlingson (http://geospaced.blogspot.com) * Barry Rowlingson (http://geospaced.blogspot.com)
* Gour (https://github.com/gour) * Gour (https://github.com/gour)
* Alexandru Kiss (usurel@gmail.com)
Translations Translations
@@ -56,7 +59,7 @@ Translations
* Russian * Russian
- Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) - Sergey Glita (s.v.glita@gmail.com)
* Italian * Italian
@@ -69,9 +72,10 @@ Translations
Remote access for debugging Remote access for debugging
--------------------------- ---------------------------
* Сергей Глита [Sergey Glita] (s.v.glita@gmail.com) * Sergey Glita (s.v.glita@gmail.com)
* David Herring (https://github.com/abadger1406) * David Herring (https://github.com/abadger1406)
* Michael Terretta (terretta@gmail.com) * Michael Terretta (terretta@gmail.com)
* Alexandru Kiss (usurel@gmail.com)
Monetary donations Monetary donations

View File

@@ -23,6 +23,7 @@ On the Web
* Website: http://www.mayan-edms.com * Website: http://www.mayan-edms.com
* Source: http://github.com/rosarior/mayan * Source: http://github.com/rosarior/mayan
* Video: http://bit.ly/Mayan-Intro * Video: http://bit.ly/Mayan-Intro
* Mailing list: http://groups.google.com/group/mayan-edms/
Looking for specific information? Try the :doc:`detailed table of contents <contents>` otherwise below are the different part of the documentation. Looking for specific information? Try the :doc:`detailed table of contents <contents>` otherwise below are the different part of the documentation.

View File

@@ -2,14 +2,90 @@
Installation Installation
============ ============
Local or managed server Automatic install using included fabfile
----------------------- ----------------------------------------
A Fabric_ file is included to help users not very familiar with Ubuntu_,
Python_ and Django_ install **Mayan EDMS**, or for system administrators
looking to automate the install whether in a local or remote system.
To bootstrap **Mayan EDMS** via the fabfile without having to clone the
entire repository, run the following command, replacing the part that
reads: <Your MySQL root password> with your current MySQL root password
or the MySQL root password you plan to assign to it, during the MySQL
installation when executing the fabfile.
* Debian or Ubuntu::
$ cd /tmp && sudo apt-get install -y fabric wget tar gzip && wget https://raw.github.com/rosarior/mayan/contrib/fabfile.tar.gz -O - | tar -xvzf - && echo "database_manager_admin_password=<Your MySQL root password>" > ~/.fabricrc && fab -H localhost install
* Fedora::
$ cd /tmp && sudo yum install -y fabric wget tar gzip && wget https://raw.github.com/rosarior/mayan/contrib/fabfile.tar.gz -O - | tar -xvzf - && echo "database_manager_admin_password=<Your MySQL root password>" > ~/.fabricrc && fab -H localhost install
The ``fabfile`` also supports deploying to more than one server whether
the they same configuration or not, via a ``server_config.json`` file.
The fabfile also supports YAML server configuration
files but requires installing ``pyyaml`` via ``pip``, ``python-yaml``
via ``apt`` (Debian_, Ubuntu_) or ``PyYAML`` via ``yum`` (Fedora_)
A sample ``server_config.yaml`` would be as follows::
debian_server:
host: 192.168.1.1
database_manager_admin_password: my_debian_mysql_pa$$word
drop_database: True
os: debian
ubuntu_server:
host: 192.168.1.2
database_manager_admin_password: my_ubuntu_mysql_pa$$word
drop_database: True
os: ubuntu
database_username: mayan_release_12
database_name: mayan_release_12
all_servers: [debian_server, ubuntu_server]
To install **Mayan EDMS** to these servers the ``fabfile`` should be called in the following manner::
$ fab servers:debian_server install
or::
$ fab servers:ubuntu_server,debian_server install
or::
$ fab servers:all_servers install
Configuration options for the ``fabfile``:
* ``host`` Hostname or address of the host to which to install **Mayan EDMS**. Required setting.
* ``os`` Operating system of the target host. Options: ubuntu, debian, fedora. default: ubuntu
* ``install_path`` Installation path. Default: /usr/share
* ``virtualenv_name`` Name of the directory that will house the virtualenv under the ``install_path``. Default: mayan
* ``repository_name`` Name of the directory where the repository will be clone under the ``virtualenv_name`` directory. Default: mayan
* ``database_manager`` Database manager to use. Options: mysql. Default: mysql
* ``database_username`` Username that will be created and used to access the database. Default: mayan
* ``database_password`` Password of the database user account. Default: random autogenerated password
* ``database_host`` Address of the database manager host. Default: 127.0.0.1
* ``drop_database`` Weather or not to drop the database when uninstalling **Mayan EDMS** via the fabfile. Default: False
* ``database_manager_admin_password`` Administrator password of the database manager, only used to create the **Mayan EDMS** database and user. Required setting.
* ``database_name`` Name of the **Mayan EDMS** database. Default: mayan
* ``webserver`` Web server that will be install and configure to server **Mayan EDMS**. Options: apache. Default: apache
Only the options: ``host``, ``os`` and ``database_manager_admin_password`` should be required for most installations.
Local or managed Ubuntu or Debian server
----------------------------------------
**Mayan EDMS** should be deployed_ like any other Django_ project and preferably using virtualenv_. **Mayan EDMS** should be deployed_ like any other Django_ project and preferably using virtualenv_.
If using a Debian_ or Ubuntu_ based Linux distribution getting the executable requirements is as easy as:: If using a Debian_ or Ubuntu_ based Linux distribution getting the executable requirements is as easy as::
$ apt-get install tesseract-ocr unpaper python-virtualenv ghostscript -y $ sudo apt-get install python-dev gcc tesseract-ocr unpaper python-virtualenv ghostscript libjpeg-dev libpng-dev poppler-utils -y
To initialize a ``virtualenv`` to deploy the project do:: To initialize a ``virtualenv`` to deploy the project do::
@@ -34,19 +110,35 @@ To install the python dependencies ``easy_install`` can be used, however for eas
Create the database that will hold the data. Install any corresponding python database drivers. Update the settings.py file with you database settings. Create the database that will hold the data. Install any corresponding python database drivers. Update the settings.py file with you database settings.
If using the ``MySQL`` database manager, use the following commands:: If using the ``MySQL`` database manager, use the following commands::
$ apt-get install python-dev libmysqlclient-dev gcc -y $ sudo apt-get install libmysqlclient-dev -y
$ pip install MySQL-python $ pip install MySQL-python
If using PostgreSQL, enter the following:: If using ``PostgreSQL``, enter the following::
$ apt-get install python-dev libpq-dev gcc-y $ sudo apt-get install libpq-dev -y
$ pip install pip install psycopg2 $ pip install psycopg2
Populate the database with the project's schema doing:: Populate the database with the project's schema doing::
$ ./manage.py syncdb --migrate $ ./manage.py syncdb --migrate
Collect the static files of the project into the ``static`` folder for serving via a webserver:: To test your installation, create a file called settings_local.py with the following content::
DEBUG=True
DEVELOPMENT=True
Execute Djangos development server using the ``runserver`` command to launch a local instance of Mayan EDMS::
$ ./manager.py runserver
Point your browser to http://127:0.0.1:8000, if everything was installed
correctly you should see the login screen. After making sure everything
is running correctly, stop the runserver command and delete the settings_local.py.
Deploy **Mayan EDMS** using the webserver of your preference. If your are
using Apache_, a sample site file is included under the contrib directory.
Before finally deploying to your favorite webserver don't forget to collect the
static files of the project into the ``static`` folder for serving via a webserver::
$ ./manage.py collectstatic $ ./manage.py collectstatic
@@ -59,6 +151,85 @@ Execute Django's runserver command to launch a local instance of **Mayan EDMS**
After making sure everything is running correctly, stop the runserver command, delete the settings_local.py and deploy **Mayan EDMS** using the webserver of your preference. If your are using Apache_, a sample site file is included under the contrib directory. After making sure everything is running correctly, stop the runserver command, delete the settings_local.py and deploy **Mayan EDMS** using the webserver of your preference. If your are using Apache_, a sample site file is included under the contrib directory.
Local or managed Fedora server
------------------------------
**Mayan EDMS** should be deployed_ like any other Django_ project and preferably using virtualenv_.
If using a Fedora_ based Linux distribution getting the executable requirements is as easy as::
$ sudo yum install -y git gcc tesseract unpaper python-virtualenv ghostscript libjpeg-turbo-devel libpng-devel poppler-util python-devel
To initialize a ``virtualenv`` to deploy the project do::
$ virtualenv --no-site-packages mayan
Download_ and decompress the latest version of **Mayan EDMS**::
$ cd mayan
$ tar -xvzf mayan.tar.gz
Or clone the latest development version straight from github::
$ cd mayan
$ git clone git://github.com/rosarior/mayan.git
To install the python dependencies ``easy_install`` can be used, however for easier retrieval a production dependencies file is included, to use it execute::
$ cd mayan
$ source ../bin/activate
$ pip install -r requirements/production.txt
Create the database that will hold the data. Install any corresponding python database drivers. Update the settings.py file with you database settings.
If using the ``MySQL`` database manager, use the following commands::
$ sudo yum install -y mysql-devel
$ pip install MySQL-python
If using ``PostgreSQL``, enter the following::
$ sudo yum install -y postgresql-devel
$ pip install psycopg2
Populate the database with the project's schema doing::
$ ./manage.py syncdb --migrate
To test your installation, create a file called settings_local.py with the following content::
DEBUG=True
DEVELOPMENT=True
Execute Djangos development server using the ``runserver`` command to launch a local instance of Mayan EDMS::
$ ./manager.py runserver
Point your browser to http://127:0.0.1:8000, if everything was installed
correctly you should see the login screen. After making sure everything
is running correctly, stop the runserver command and delete the settings_local.py.
Deploy **Mayan EDMS** using the webserver of your preference. If your are
using Apache_, a sample site file is included under the contrib directory.
Before finally deploying to your favorite webserver don't forget to collect the
static files of the project into the ``static`` folder for serving via a webserver::
$ ./manage.py collectstatic
Cloud install
-------------
SaaS provied Appsembler_ has started providing a "1-click install" cloud
offering of **Mayan EDMS**. Go to their website and click on apps to start
your trial period of **Mayan EDMS** on the cloud.
DjangoZoom
----------
For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screencast:
"Deploying Mayan EDMS on DjangoZoom.net" available on Youtube_
Webfaction Webfaction
---------- ----------
@@ -168,11 +339,6 @@ To install **Mayan EDMS** on Webfaction_, follow these steps:
apache2/bin/restart apache2/bin/restart
DjangoZoom
----------
For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screencast:
"Deploying Mayan EDMS on DjangoZoom.net" available on Youtube_
.. _`vendor lock-in`: https://secure.wikimedia.org/wikipedia/en/wiki/Vendor_lock-in .. _`vendor lock-in`: https://secure.wikimedia.org/wikipedia/en/wiki/Vendor_lock-in
@@ -193,3 +359,6 @@ For instructions on how to deploy **Mayan EDMS** on DjangoZoom, watch the screen
.. _deployed: https://docs.djangoproject.com/en/1.3/howto/deployment/ .. _deployed: https://docs.djangoproject.com/en/1.3/howto/deployment/
.. _virtualenv: http://www.virtualenv.org/en/latest/index.html .. _virtualenv: http://www.virtualenv.org/en/latest/index.html
.. _`Reducing mod_wsgi Memory Consumption`: http://docs.webfaction.com/software/mod-wsgi.html#mod-wsgi-reducing-memory-consumption .. _`Reducing mod_wsgi Memory Consumption`: http://docs.webfaction.com/software/mod-wsgi.html#mod-wsgi-reducing-memory-consumption
.. _Fedora: http://fedoraproject.org/
.. _Fabric: http://docs.fabfile.org/
.. _Appsembler: http://appsembler.com/

View File

@@ -39,7 +39,7 @@ Version 0.10
* Document image serving response now specifies a MIME type for increased * Document image serving response now specifies a MIME type for increased
browser compatibility. browser compatibility.
* Small change in the scheduler that increases stability. * Small change in the scheduler that increases stability.
* Russian translation updates (Сергей Глита [Sergey Glita]) * Russian translation updates Sergey Glita
* Improved and generalized the OCR queue locking mechanism, this should * Improved and generalized the OCR queue locking mechanism, this should
eliminate any posibility of race conditions between Mayan EDMS OCR nodes. eliminate any posibility of race conditions between Mayan EDMS OCR nodes.
* Added support for signals to the OCR queue, this results in instant OCR * Added support for signals to the OCR queue, this results in instant OCR

116
docs/releases/0.12.1.rst Normal file
View File

@@ -0,0 +1,116 @@
================================
Mayan EDMS v0.12.1 release notes
================================
*May 2012*
This is the first maintenance release of the 0.12 series.
Overview
========
While bug fixes and minor feature were the focus for this release, some
bigger changes were included because of their importance. The parsing of
documents saw a complete rewrite being now class based and allows for more
than one parser per mimetype with sequencial fallback. This provides the
best text extraction on deployments where users have control over the
installation and basic extraction when deploying on the cloud or other
environments where users don't have the ability to install OS level
binaries.
What's new in Mayan EDMS v0.12.1
================================
Fabric file (fabfile)
~~~~~~~~~~~~~~~~~~~~~
A Fabric file is included to help users not very familiar with Ubuntu,
Python and Django install **Mayan EDMS**, or for system administrators
looking to automate the install whether in local or remote systems.
At the moment the fabfile will install **Mayan EDMS** in the same configurations
listed in this documentation, that is: (Ubuntu/Debian/Fedora) + virtualenv + Apache + MySQL.
Feel free to submit your configuration settings and files for different databases,
webserver or Linux distribution. More configurations will be added to
the fabfile as more are tested.
Documentation update
~~~~~~~~~~~~~~~~~~~~
The installation instructions were updated to include the installation of
the libpng-dev and libjpeg-dev libraries as well as the installation of
the poppler-utils package. An additional step to help users test their
new installation of **Mayan EDMS** was also added.
Translations
~~~~~~~~~~~~
The Italian translation has been synchronized with the source files at
Transifex and finished to %100 completion.
Usability improvements
~~~~~~~~~~~~~~~~~~~~~~
The index instance view now feature the same multi document action
buttons (Submit to OCR, delete, download, etc) as the mail and recent
document views.
Better office document conversion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A new method of converting office documents has been implemented, this
new method doesn't require the use of the command line utility ``UNOCONV``.
If this new method proves to work better than previous solutions the use
of ``UNOCONV`` may be deprecated in the future. The conversion method
adds just one new configuration option: :setting:`CONVERTER_LIBREOFFICE_PATH`
which defaults to '/usr/bin/libreoffice'.
Better PDF text parsing
~~~~~~~~~~~~~~~~~~~~~~~
Brian E. submitted a patch to use the Poppler package pdftotext utility to
extract text from PDF files. This is now the default method Mayan EDMS
will execute to try to extract text from a PDF and failing that will
fallback to the previous method. This change add a new configuration
option: :setting:`OCR_PDFTOTEXT_PATH` to specify the location of the ``pdftotext``
executable, it defaults to '/usr/bin/pdftotext'. Be sure to install the
``poppler-utils`` os package to take advantage of this new parser.
Changed defaults
~~~~~~~~~~~~~~~~
The OCR queue is now active by default when first created during the
``syncdb`` phase and the :setting:`OCR_AUTOMATIC_OCR` option now defaults
to ``True``. These two changes are made to reduce the steps required for
new users to start enjoying the benefits of automatic text extraction from
uploaded documents without having to read the documentation and have a more
functional default install.
Upgrading from a previous version
=================================
Start off by adding the new requirements::
$ pip install -r requirements/production.txt
Migrate existing database schema with::
$ ./manage.py migrate documents
Install the ``poppler-utils`` package:
* Ubuntu, Debian::
$ apt-get install -y poppler-utils
* Fedora::
$ yum install -y poppler-utils
The upgrade procedure is now complete.
Backward incompatible changes
=============================
* None
Bugs fixed
==========
* Issue #25 "Office document conversion error"
Stuff removed
=============
* None

View File

@@ -1,7 +1,7 @@
Version 0.9.1 Version 0.9.1
------------- -------------
* Added handling percent encoded unicode query strings in search URL, * Added handling percent encoded unicode query strings in search URL,
thanks to (Сергей Глита [Sergei Glita]) for reporting. thanks to Sergei Glita for reporting.
* Added a FAQ explaing how to fix MySQL collation related error when * Added a FAQ explaing how to fix MySQL collation related error when
doing searches also thanks to (Сергей Глита [Sergei Glita]) for doing searches also thanks to Sergei Glita for
reporting this one. reporting this one.

View File

@@ -16,11 +16,11 @@ Version 0.9
* Changed to Semantic Versioning (http://semver.org/), with * Changed to Semantic Versioning (http://semver.org/), with
recommendations 7, 8 and 9 causing the most effect in the versioning number. recommendations 7, 8 and 9 causing the most effect in the versioning number.
* Added Russian locale post OCR cleanup backend (Сергей Глита [Sergei Glita]) * Added Russian locale post OCR cleanup backend Sergei Glita
* Reduced severity of the messages displayed when no OCR cleanup backend * Reduced severity of the messages displayed when no OCR cleanup backend
is found for a language is found for a language
* Complete Portuguese translation (Emerson Soares and Renata Oliveira) * Complete Portuguese translation (Emerson Soares and Renata Oliveira)
* Complete Russian translation (Сергей Глита [Sergei Glita]) * Complete Russian translation Sergei Glita)
* Added animate.css to use CSS to animate flash messages with better * Added animate.css to use CSS to animate flash messages with better
fallback on non JS browsers fallback on non JS browsers
* The admin and sentry links are no longer hard-coded (Meurig Freeman) * The admin and sentry links are no longer hard-coded (Meurig Freeman)

View File

@@ -9,7 +9,7 @@ changes made in that version.
For those upgrading to a new version of **Mayan EDMS**, you will need to check For those upgrading to a new version of **Mayan EDMS**, you will need to check
all the backwards-incompatible changes and deprecated features for all the backwards-incompatible changes and deprecated features for
each 'final' release from the one after your current **Mayan EDMS** version, each 'final' release from the one after your current **Mayan EDMS** version,
up to and including the new version. up to and including the latest version.
Latest version (0.13) Latest version (0.13)
--------------------- ---------------------
@@ -17,6 +17,7 @@ Latest version (0.13)
:maxdepth: 1 :maxdepth: 1
0.13 0.13
0.12.1
0.12 0.12
Historic changelogs Historic changelogs

View File

@@ -200,7 +200,7 @@ fine tune it's functionality as explained in the `GraphicsMagick documentation`_
Default: ``/usr/bin/unoconv`` Default: ``/usr/bin/unoconv``
Path to the unoconv program used to call LibreOffice for office document convertion. Path to the unoconv program used to call LibreOffice for office document conversion.
.. setting:: CONVERTER_UNOCONV_USE_PIPE .. setting:: CONVERTER_UNOCONV_USE_PIPE
@@ -213,6 +213,17 @@ Default: ``True``
Use alternate method of connection to LibreOffice using a pipe, it is slower but less prone to segmentation faults. Use alternate method of connection to LibreOffice using a pipe, it is slower but less prone to segmentation faults.
.. setting:: CONVERTER_LIBREOFFICE_PATH
**CONVERTER_LIBREOFFICE_PATH**
Default: ``/usr/bin/libreoffice``
Path to the libreoffice binary used to call LibreOffice for office document conversion.
Linking Linking
======= =======
@@ -341,7 +352,7 @@ Maximum amount of concurrent document OCRs a node can perform.
**OCR_AUTOMATIC_OCR** **OCR_AUTOMATIC_OCR**
Default: ``False`` Default: ``True``
Automatically queue newly created documents or newly uploaded versions Automatically queue newly created documents or newly uploaded versions
of existing documents for OCR. of existing documents for OCR.
@@ -364,6 +375,16 @@ File path to the ``unpaper`` executable, used to clean up images before
doing OCR. doing OCR.
.. setting:: OCR_PDFTOTEXT_PATH
**OCR_PDFTOTEXT_PATH**
Default: ``/usr/bin/pdftotext``
File path to ``poppler's`` ``pdftotext`` program used to extract text
from PDF files.
Metadata Metadata
======== ========

61
fabfile/__init__.py Normal file
View File

@@ -0,0 +1,61 @@
import sys
from fabric.api import task, env
from fabric.colors import white
import databases as database
import platforms as platform
import webservers as webserver
import django
from conf import print_supported_configs
from server_config import servers
print(white('\n\n ######## ', bold=True))
print(white(' ######## ', bold=True))
print(white(' ### ### ', bold=True))
print(white(' ##### ##### ', bold=True))
print(white(' ############## ', bold=True))
print(white(' ####### ####### ', bold=True))
print(white(' ################## ', bold=True))
print(white(' ######### ######### ', bold=True))
print(white(' ###################### ', bold=True))
print(white(' ########### ########### ', bold=True))
print(white(' ########################## ', bold=True))
print(white('############# #############', bold=True))
print(white('\nMayan EDMS Fabric installation file\n\n', bold=True))
print_supported_configs()
@task
def install():
"""
Perform a complete install of Mayan EDMS on a host
"""
platform.install_dependencies()
platform.install_mayan()
platform.install_database_manager()
database.create_database()
django.database_config()
django.syncdb()
django.collectstatic()
platform.fix_permissions()
platform.install_webserver()
webserver.install_site()
webserver.restart()
platform.post_install()
@task
def uninstall():
"""
Perform a complete removal of Mayan EDMS from a host
"""
platform.delete_mayan()
webserver.remove_site()
webserver.restart()
if env.drop_database:
database.drop_database()
database.drop_username()

60
fabfile/conf.py Normal file
View File

@@ -0,0 +1,60 @@
import os
import string
import random
from fabric.api import env
from fabric.colors import green
from literals import (DEFAULT_INSTALL_PATH, DEFAULT_VIRTUALENV_NAME,
DEFAULT_REPOSITORY_NAME, DEFAULT_OS, OS_CHOICES,
DEFAULT_DATABASE_MANAGER, DB_CHOICES, DEFAULT_DATABASE_NAME,
DEFAULT_WEBSERVER, WEB_CHOICES, DEFAULT_DATABASE_USERNAME,
DJANGO_DB_DRIVERS, DEFAULT_DATABASE_HOST, DEFAULT_PASSWORD_LENGTH)
from server_config import reduce_env
def password_generator():
# http://snipplr.com/view/63223/python-password-generator/
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for x in range(DEFAULT_PASSWORD_LENGTH))
@reduce_env
def setup_environment():
env['os'] = getattr(env, 'os', DEFAULT_OS)
env['os_name'] = OS_CHOICES[env.os]
env['install_path'] = getattr(env, 'install_path', DEFAULT_INSTALL_PATH[env.os])
env['virtualenv_name'] = getattr(env, 'virtualenv_name', DEFAULT_VIRTUALENV_NAME[env.os])
env['repository_name'] = getattr(env, 'repository_name', DEFAULT_REPOSITORY_NAME[env.os])
env['virtualenv_path'] = os.path.join(env.install_path, env.virtualenv_name)
env['repository_path'] = os.path.join(env.virtualenv_path, env.repository_name)
env['database_manager'] = getattr(env, 'database_manager', DEFAULT_DATABASE_MANAGER)
env['database_manager_name'] = DB_CHOICES[env.database_manager]
env['database_username'] = getattr(env, 'database_username', DEFAULT_DATABASE_USERNAME)
env['database_password'] = getattr(env, 'database_password', password_generator())
env['database_host'] = getattr(env, 'database_host', DEFAULT_DATABASE_HOST)
env['drop_database'] = getattr(env, 'drop_database', False)
if not getattr(env, 'database_manager_admin_password', None):
print('Must set the database_manager_admin_password entry in the fabric settings file (~/.fabricrc by default)')
exit(1)
env['database_name'] = getattr(env, 'database_name', DEFAULT_DATABASE_NAME)
env['webserver'] = getattr(env, 'webserver', DEFAULT_WEBSERVER)
env['webserver_name'] = WEB_CHOICES[env.webserver]
env['django_database_driver'] = DJANGO_DB_DRIVERS[env.database_manager]
def print_supported_configs():
print('Supported operating systems (os=): %s, default=\'%s\'' % (dict(OS_CHOICES).keys(), green(DEFAULT_OS)))
print('Supported database managers (database_manager=): %s, default=\'%s\'' % (dict(DB_CHOICES).keys(), green(DEFAULT_DATABASE_MANAGER)))
print('Supported webservers (webserver=): %s, default=\'%s\'' % (dict(WEB_CHOICES).keys(), green(DEFAULT_WEBSERVER)))
print('\n')

View File

@@ -0,0 +1,42 @@
from fabric.api import env, task
from fabric.colors import green
from ..conf import setup_environment
from ..literals import DB_MYSQL
import mysql
@task
def create_database():
"""
Create the Mayan EDMS database
"""
setup_environment()
print(green('Creating Mayan EDMS database', bold=True))
if env.database_manager == DB_MYSQL:
mysql.create_database()
@task
def drop_database():
"""
Drop Mayan EDMS's database
"""
setup_environment()
print(green('Droping Mayan EDMS database', bold=True))
if env.database_manager == DB_MYSQL:
mysql.drop_database()
@task
def drop_username():
"""
Drop Mayan EDMS's username
"""
setup_environment()
print(green('Droping Mayan EDMS username', bold=True))
if env.database_manager == DB_MYSQL:
mysql.drop_username()

View File

@@ -0,0 +1,30 @@
from fabric.api import run, env, task, settings
from fabric.colors import green
def create_database():
"""
Create the MySQL Mayan EDMS database
"""
run('echo "CREATE DATABASE %(database_name)s;" | mysql -u root --password=%(database_manager_admin_password)s' % env)
run('echo "CREATE USER \'%(database_username)s\'@\'%(database_host)s\' IDENTIFIED BY \'%(database_password)s\';" | mysql -u root --password=%(database_manager_admin_password)s' % env)
run('echo "GRANT ALL PRIVILEGES ON %(database_name)s.* TO \'%(database_username)s\'@\'%(database_host)s\' WITH GRANT OPTION;" | mysql -u root --password=%(database_manager_admin_password)s' % env)
print(green('Password used for Mayan EDMS database account: %s' % env.database_password, bold=True))
def drop_database():
"""
Drop MySQL's Mayan EDMS's database
"""
with settings(warn_only=True):
run('echo "DROP DATABASE %(database_name)s;" | mysql -u root --password=%(database_manager_admin_password)s' % env)
def drop_username():
"""
Drop MySQL's Mayan EDMS's username
"""
with settings(warn_only=True):
run('echo "DROP USER \'%(database_username)s\'@\'%(database_host)s\';" | mysql -u root --password=%(database_manager_admin_password)s' % env)

View File

@@ -0,0 +1,34 @@
import os
from fabric.api import env, task, cd, sudo
from fabric.contrib.files import upload_template
from ..conf import setup_environment
@task
def syncdb():
"""
Perform Django's syncdb command
"""
setup_environment()
with cd(env.virtualenv_path):
sudo('source bin/activate; %(repository_name)s/manage.py syncdb --noinput; %(repository_name)s/manage.py migrate' % (env))
@task
def database_config():
"""
Create a settings_local.py file tailored to the database manager selected
"""
setup_environment()
upload_template(filename=os.path.join('fabfile', 'templates', 'settings_local.py'), destination=env.repository_path, context=env, use_sudo=True)
@task
def collectstatic():
"""
Perform Django's collectstatic command
"""
setup_environment()
with cd(env.virtualenv_path):
sudo('source bin/activate; %(repository_name)s/manage.py collectstatic --noinput' % (env))

70
fabfile/literals.py Normal file
View File

@@ -0,0 +1,70 @@
OS_UBUNTU = 'ubuntu'
OS_REDHAT = 'redhat'
OS_CENTOS = 'centos'
OS_FEDORA = 'fedora'
OS_WINDOWS = 'windows'
OS_FREEBSD = 'freebds'
OS_DEBIAN = 'debian'
OS_CHOICES = {
OS_UBUNTU: 'Ubuntu',
OS_FEDORA: 'Fedora',
OS_DEBIAN: 'Debian',
#OS_REDHAT: 'RedHat',
#OS_CENTOS: 'CentOS',
#OS_WINDOWS: 'MS Windows',
#OS_FREEBSD: 'FreeBSD',
}
DEFAULT_INSTALL_PATH = {
OS_UBUNTU: '/usr/share',
OS_FEDORA: '/usr/share',
OS_DEBIAN: '/usr/share',
}
DEFAULT_VIRTUALENV_NAME = {
OS_UBUNTU: 'mayan',
OS_FEDORA: 'mayan',
OS_DEBIAN: 'mayan',
}
DEFAULT_REPOSITORY_NAME = {
OS_UBUNTU: 'mayan',
OS_FEDORA: 'mayan',
OS_DEBIAN: 'mayan',
}
DB_MYSQL = 'mysql'
DB_PGSQL = 'pgsql'
DB_SQLITE = 'sqlite'
DB_ORACLE = 'oracle'
DB_CHOICES = {
DB_MYSQL: 'MySQL',
#DB_PGSQL: 'PostgreSQL',
#DB_SQLITE: 'SQLite',
#DB_ORACLE: 'ORACLE'
}
DJANGO_DB_DRIVERS = {
DB_MYSQL: 'mysql',
DB_PGSQL: 'postgresql_psycopg2',
DB_SQLITE: 'sqlite3',
DB_ORACLE: 'oracle',
}
WEB_APACHE = 'apache'
WEB_NGINX = 'nginx'
WEB_CHOICES = {
WEB_APACHE: 'Apache',
#WEB_NGINX: 'Nginx',
}
DEFAULT_OS = OS_UBUNTU
DEFAULT_DATABASE_MANAGER = DB_MYSQL
DEFAULT_DATABASE_NAME = 'mayan'
DEFAULT_WEBSERVER = WEB_APACHE
DEFAULT_DATABASE_USERNAME = 'mayan'
DEFAULT_DATABASE_HOST = '127.0.0.1'
DEFAULT_PASSWORD_LENGTH = 10

View File

@@ -0,0 +1,100 @@
from fabric.api import run, sudo, cd, env, task
from fabric.colors import green
from ..literals import OS_UBUNTU, OS_FEDORA, OS_DEBIAN
from ..conf import setup_environment
import linux, ubuntu, fedora, debian
@task
def install_dependencies():
"""
Install OS dependencies
"""
setup_environment()
print(green('Installing dependencies for %s' % env.os_name, bold=True))
if env.os in [OS_UBUNTU, OS_DEBIAN]:
debian.install_dependencies()
elif env.os == OS_FEDORA:
fedora.install_dependencies()
@task
def install_mayan():
"""
Install Mayan EDMS
"""
setup_environment()
print(green('Installing Mayan EDMS from git repository', bold=True))
if env.os in [OS_UBUNTU, OS_FEDORA, OS_DEBIAN]:
linux.install_mayan()
@task
def install_database_manager():
"""
Install the selected database manager
"""
setup_environment()
print(green('Installing database manager: %s' % env.database_manager_name, bold=True))
if env.os in [OS_UBUNTU, OS_DEBIAN]:
debian.install_database_manager()
elif env.os == OS_FEDORA:
fedora.install_database_manager()
@task
def fix_permissions():
"""
Fix installation files' permissions
"""
setup_environment()
print(green('Fixing installation files\' permissions', bold=True))
if env.os in [OS_UBUNTU, OS_DEBIAN]:
debian.fix_permissions()
elif env.os == OS_FEDORA:
fedora.fix_permissions()
@task
def install_webserver():
"""
Installing the OS packages for the webserver
"""
setup_environment()
print(green('Installing webserver: %s' % env.webserver_name, bold=True))
if env.os in [OS_UBUNTU, OS_DEBIAN]:
debian.install_webserver()
elif env.os == OS_FEDORA:
fedora.install_webserver()
@task
def delete_mayan():
"""
Delete Mayan EDMS from the OS
"""
setup_environment()
print(green('Deleting Mayan EDMS files', bold=True))
if env.os in [OS_UBUNTU, OS_FEDORA, OS_DEBIAN]:
linux.delete_mayan()
@task
def post_install():
"""
Perform post install operations
"""
setup_environment()
if env.os == OS_UBUNTU:
ubuntu.post_install()
elif env.os == OS_FEDORA:
fedora.post_install()
elif env.os == OS_DEBIAN:
debian.post_install()

View File

@@ -0,0 +1,50 @@
from fabric.api import run, sudo, cd, env, task, settings
from ..literals import DB_MYSQL, WEB_APACHE
def install_dependencies():
"""
Install Debian dependencies
"""
sudo('apt-get install -y git-core gcc tesseract-ocr unpaper python-virtualenv ghostscript libjpeg-dev libpng-dev poppler-utils python-dev')
def install_database_manager():
"""
Install the database manager on an Ubuntu system
"""
if env.database_manager == DB_MYSQL:
sudo('apt-get install -y mysql-server libmysqlclient-dev')
with cd(env.virtualenv_path):
sudo('source bin/activate; pip install MySQL-python')
def install_webserver():
"""
Installing the Debian packages for the webserver
"""
if env.webserver == WEB_APACHE:
sudo('apt-get install -y apache2 libapache2-mod-wsgi')
with settings(warn_only=True):
# Get rid of Apache's default site
sudo('a2dissite default')
def fix_permissions():
"""
Fix installation files' permissions on a Debian system
"""
sudo('chmod 770 %s -R' % env.virtualenv_path)
sudo('chgrp www-data %s -R' % env.virtualenv_path)
def post_install():
"""
Post install operations on a Debian system
"""
pass

View File

@@ -0,0 +1,62 @@
import os
from fabric.api import run, sudo, cd, env, task, settings
from fabric.operations import put, reboot
from ..literals import DB_MYSQL, WEB_APACHE
def install_dependencies():
"""
Install Fedora dependencies
"""
sudo('yum install -y git gcc tesseract unpaper python-virtualenv ghostscript libjpeg-turbo-devel libpng-devel poppler-utils')
def install_database_manager():
"""
Install the database manager on a Fedora system
"""
if env.database_manager == DB_MYSQL:
sudo('yum install -y mysql-server mysql-devel')
sudo('systemctl enable mysqld.service')
sudo('systemctl start mysqld.service')
sudo('mysql_secure_installation')
with cd(env.virtualenv_path):
sudo('source bin/activate; pip install MySQL-python')
def install_webserver():
"""
Installing the Fedora packages for the webserver
"""
if env.webserver == WEB_APACHE:
sudo('yum install -y httpd mod_wsgi')
sudo('systemctl enable httpd.service')
sudo('systemctl start httpd.service')
with settings(warn_only=True):
# Get rid of Apache's default site
sudo('rm /etc/httpd/conf.d/welcome.conf')
# Disable SELinux as it blocks mod_wsgi's file access
# TODO: implement a proper solution is implemented
put(local_path=os.path.join('fabfile', 'templates', 'selinux.config'), remote_path='/etc/selinux/config', use_sudo=True)
def fix_permissions():
"""
Fix installation files' permissions on a Fedora system
"""
sudo('chmod 770 %s -R' % env.virtualenv_path)
sudo('chgrp apache %s -R' % env.virtualenv_path)
def post_install():
"""
Post install operations on a Fedora system
"""
reboot()

View File

@@ -0,0 +1,20 @@
from fabric.api import run, sudo, cd, env, task, settings
def delete_mayan():
"""
Delete Mayan EDMS files from an Ubuntu system
"""
sudo('rm %(virtualenv_path)s -Rf' % env)
def install_mayan():
"""
Install Mayan EDMS on an Ubuntu system
"""
with cd(env.install_path):
sudo('virtualenv --no-site-packages %(virtualenv_name)s' % env)
with cd(env.virtualenv_path):
sudo('git clone git://github.com/rosarior/mayan.git %(repository_name)s' % env)
sudo('source bin/activate; pip install -r %(repository_name)s/requirements/production.txt' % env)

View File

@@ -0,0 +1,5 @@
def post_install():
"""
Post install operations on an Ubuntu system
"""
pass

141
fabfile/server_config.py Normal file
View File

@@ -0,0 +1,141 @@
"""Fabric server config management fabfile.
If you need additional configuration, setup ~/.fabricrc file:
user = your_remote_server_username
To get specific command help type:
fab -d command_name
"""
# From http://fueledbylemons.com/blog/2011/04/09/server-configs-and-fabric/
import os
from fabric.api import env, task
from fabric.utils import puts
from fabric import colors
import fabric.network
import fabric.state
YAML_AVAILABLE = True
try:
import yaml
except ImportError:
YAML_AVAILABLE = False
JSON_AVAILABLE = True
try:
import simplejson as json
except ImportError:
try:
import json
except ImportError:
JSON_AVAILABLE = False
################################
# ENVIRONMENTS #
################################
def _load_config(**kwargs):
"""Find and parse server config file.
If `config` keyword argument wasn't set look for default
'server_config.yaml' or 'server_config.json' file.
"""
config, ext = os.path.splitext(kwargs.get('config',
'server_config.yaml' if os.path.exists('server_config.yaml') else 'server_config.json'))
if not os.path.exists(config + ext):
print colors.red('Error. "%s" file not found.' % (config + ext))
return {}
if YAML_AVAILABLE and ext == '.yaml':
loader = yaml
elif JSON_AVAILABLE and ext =='.json':
loader = json
else:
print colors.red('Parser package not available')
return {}
# Open file and deserialize settings.
with open(config + ext) as config_file:
return loader.load(config_file)
@task
def servers(*args, **kwargs):
"""Set destination servers or server groups by comma delimited list of names"""
# Load config
servers = _load_config(**kwargs)
# If no arguments were recieved, print a message with a list of available configs.
if not args:
print 'No server name given. Available configs:'
for key in servers:
print colors.green('\t%s' % key)
# Create `group` - a dictionary, containing copies of configs for selected servers. Server hosts
# are used as dictionary keys, which allows us to connect current command destination host with
# the correct config. This is important, because somewhere along the way fabric messes up the
# hosts order, so simple list index incrementation won't suffice.
env.group = {}
# For each given server name
for name in args:
# Recursive function call to retrieve all server records. If `name` is a group(e.g. `all`)
# - get it's members, iterate through them and create `group`
# record. Else, get fields from `name` server record.
# If requested server is not in the settings dictionary output error message and list all
# available servers.
_build_group(name, servers)
# Copy server hosts from `env.group` keys - this gives us a complete list of unique hosts to
# operate on. No host is added twice, so we can safely add overlaping groups. Each added host is
# guaranteed to have a config record in `env.group`.
env.hosts = env.group.keys()
def _build_group(name, servers):
"""Recursively walk through servers dictionary and search for all server records."""
# We're going to reference server a lot, so we'd better store it.
server = servers.get(name, None)
# If `name` exists in servers dictionary we
if server:
# check whether it's a group by looking for `members`
if isinstance(server, list):
if fabric.state.output['debug']:
puts("%s is a group, getting members" % name)
for item in server:
# and call this function for each of them.
_build_group(item, servers)
# When, finally, we dig through to the standalone server records, we retrieve
# configs and store them in `env.group`
else:
if fabric.state.output['debug']:
puts("%s is a server, filling up env.group" % name)
env.group[server['host']] = server
else:
print colors.red('Error. "%s" config not found. Run `fab servers` to list all available configs' % name)
def reduce_env(task):
"""
Copies server config settings from `env.group` dictionary to env variable.
This way, tasks have easier access to server-specific variables:
`env.owner` instead of `env.group[env.host]['owner']`
"""
def task_with_setup(*args, **kwargs):
# If `s:server` was run before the current command - then we should copy values to
# `env`. Otherwise, hosts were passed through command line with `fab -H host1,host2
# command` and we skip.
if env.get("group", None):
for key,val in env.group[env.host].items():
setattr(env, key, val)
if fabric.state.output['debug']:
puts("[env] %s : %s" % (key, val))
task(*args, **kwargs)
# Don't keep host connections open, disconnect from each host after each task.
# Function will be available in fabric 1.0 release.
# fabric.network.disconnect_all()
return task_with_setup

View File

@@ -0,0 +1,20 @@
<VirtualHost *:80>
# Uncomment if libapache2-mod-xsendfile is installed
# XSendFile On
# XSendFileAllowAbove On
WSGIScriptAlias / %(repository_path)s/wsgi/dispatch.wsgi
<Directory %(repository_path)s>
Order deny,allow
Allow from all
</Directory>
#ErrorLog /var/log/apache2/mayan_error.log
LogLevel warn
#CustomLog /var/log/apache2/mayan_access.log combined
Alias /mayan-static "%(repository_path)s/static/"
<Location "/static">
SetHandler None
</Location>
</VirtualHost>

View File

@@ -0,0 +1,10 @@
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
SELINUXTYPE=targeted

View File

@@ -0,0 +1,55 @@
from fabric.api import run, sudo, cd, env, task
from fabric.colors import green
from ..conf import setup_environment
from ..literals import WEB_APACHE
import apache
@task
def install_site():
"""
Install Mayan EDMS site in the webserver configuration files
"""
setup_environment()
print(green('Adding Mayan EDMS\'s site files to: %s' % env.webserver_name, bold=True))
if env.webserver == WEB_APACHE:
apache.install_site()
@task
def remove_site():
"""
Install Mayan EDMS's site file from the webserver's configuration
"""
setup_environment()
print(green('Removing Mayan EDMS\'s site file from %s configuration' % env.webserver_name, bold=True))
if env.webserver == WEB_APACHE:
apache.remove_site()
@task
def restart():
"""
Restart the webserver
"""
setup_environment()
print(green('Restarting the web server: %s' % env.webserver_name, bold=True))
if env.webserver == WEB_APACHE:
apache.restart()
@task
def reload():
"""
Reload webserver configuration files
"""
setup_environment()
print(green('Reloading the web server configuration files', bold=True))
if env.webserver == WEB_APACHE:
apache.reload()

View File

@@ -0,0 +1,50 @@
import os
from fabric.api import run, sudo, cd, env, task, settings
from fabric.contrib.files import upload_template
from ..literals import OS_UBUNTU, OS_FEDORA, OS_DEBIAN
def install_site():
"""
Install Mayan EDMS's site file in Apache configuration
"""
# TODO: configurable site name
if env.os in [OS_UBUNTU, OS_DEBIAN]:
upload_template(filename=os.path.join('fabfile', 'templates', 'apache_site'), destination='/etc/apache2/sites-available/mayan', context=env, use_sudo=True)
sudo('a2ensite mayan')
elif env.os == OS_FEDORA:
upload_template(filename=os.path.join('fabfile', 'templates', 'apache_site'), destination='/etc/httpd/conf.d/mayan.conf', context=env, use_sudo=True)
def remove_site():
"""
Install Mayan EDMS's site file from Apache's configuration
"""
if env.os in [OS_UBUNTU, OS_DEBIAN]:
with settings(warn_only=True):
sudo('a2dissite mayan')
elif env.os == OS_FEDORA:
with settings(warn_only=True):
sudo('rm /etc/httpd/conf.d/mayan.conf')
def restart():
"""
Restart Apache
"""
if env.os in [OS_UBUNTU, OS_DEBIAN]:
sudo('/etc/init.d/apache2 restart')
elif env.os == OS_FEDORA:
sudo('systemctl restart httpd.service')
def reload():
"""
Reload Apache configuration files
"""
if env.os in [OS_UBUNTU, OS_DEBIAN]:
sudo('/etc/init.d/apache2 reload')
elif env.os == OS_FEDORA:
sudo('systemctl reload httpd.service')

3
misc/make_fabfile_tar.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
find 'fabfile' -depth -name '*.pyc' -exec rm {} \;
tar -czvf contrib/fabfile.tar.gz fabfile

View File

@@ -1,11 +1,11 @@
import os import os
import sys import sys
import site import site
import platform
sys.stdout = sys.stderr sys.stdout = sys.stderr
#TODO fix properly ve_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'lib/python%s/site-packages' % platform.python_version()[:3]))
ve_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'lib/python2.7/site-packages')) # Change python 2.6 to the python version you are using
# Add the virtual Python environment site-packages directory to the path # Add the virtual Python environment site-packages directory to the path
site.addsitedir(ve_path) site.addsitedir(ve_path)