Merge branch 'development'

This commit is contained in:
Roberto Rosario
2015-12-04 05:32:13 -04:00
3184 changed files with 172263 additions and 181363 deletions

View File

@@ -4,4 +4,7 @@ source=
omit=
mayan/bin/mayan-edms.py
mayan/wsgi.py
mayan/settings/*
tests.py
mayan/apps/*/tests/*
*migrations*

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
*
!docker

6
.gitignore vendored
View File

@@ -7,7 +7,7 @@ settings_local.py
/celerybeat-schedule
document_storage/
/misc/mayan.geany
image_cache/
mayan/media/document_cache/
build/
_build/
gpg_home/
@@ -22,3 +22,7 @@ static_collected/
*egg-info*
mayan/settings/local.py
.vagrant
.tox/
coverage.xml
.coverage.tox*
htmlcov/

35
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,35 @@
image: python:2.7
services:
- mysql
- postgres
before_script:
- apt-get update -qq
- apt-get install -qq python-dev gcc tesseract-ocr tesseract-ocr-deu unpaper ghostscript libjpeg-dev libpng-dev libtiff-dev poppler-utils libreoffice
variables:
POSTGRES_DB: "mayan_edms"
POSTGRES_PASSWORD: "postgres"
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_DATABASE: "mayan_edms"
test:mysql:
script:
- pip install -r requirements/testing.txt
- pip install -q mysql-python
- apt-get install -qq mysql-client
- mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD" -e "ALTER DATABASE $MYSQL_DATABASE CHARACTER SET utf8 COLLATE utf8_unicode_ci;"
- coverage run manage.py runtests --settings=mayan.settings.testing.gitlab-ci.db_mysql --nomigrations
- bash <(curl https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -t $CODECOV_TOKEN
tags:
- mysql
test:postgres:
script:
- pip install -r requirements/testing.txt
- pip install -q psycopg2
- coverage run manage.py runtests --settings=mayan.settings.testing.gitlab-ci.db_postgres --nomigrations
- bash <(curl https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -t $CODECOV_TOKEN
tags:
- postgres
test:sqlite:
script:
- pip install -r requirements/testing.txt
- coverage run manage.py runtests --settings=mayan.settings.testing.gitlab-ci --nomigrations
- bash <(curl https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -t $CODECOV_TOKEN

21
.magnum.yml Normal file
View File

@@ -0,0 +1,21 @@
language: python
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq python-dev gcc tesseract-ocr tesseract-ocr-deu unpaper ghostscript libjpeg-dev libpng-dev poppler-utils
install:
- pip install -r requirements/testing.txt
- pip install -q mysql-python
- pip install -q psycopg2
before_script:
- mysql -u root -e 'create database mayan_edms;'
- psql -c 'create database mayan_edms;' -U postgres
script:
- export TEST_APPS="acls authentication django_gpg document_indexing document_signatures documents dynamic_search folders lock_manager ocr permissions sources tags"
- coverage run manage.py test $TEST_APPS --settings=mayan.settings.testing.base
- coverage run manage.py test $TEST_APPS --settings=mayan.settings.magnum.db_mysql
- coverage run manage.py test $TEST_APPS --settings=mayan.settings.magnum.db_postgres
after_script:
- coveralls
services:
- mysql
- postgresql

View File

@@ -1,17 +1,14 @@
language: python
python:
- 2.6
- 2.7
env:
global:
- TEST_APPS="document_indexing documents dynamic_search lock_manager document_signatures folders ocr sources tags"
matrix:
- DB=mysql
- DB=postgres
- DB=sqlite
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq python-dev gcc tesseract-ocr unpaper ghostscript libjpeg-dev libpng-dev poppler-utils
- sudo apt-get install -qq python-dev gcc tesseract-ocr tesseract-ocr-deu unpaper ghostscript libjpeg-dev libpng-dev poppler-utils libreoffice
install:
- "pip install -r requirements/testing.txt"
- if [[ $DB == mysql ]]; then pip install -q mysql-python; fi
@@ -20,9 +17,9 @@ before_script:
- mysql -e 'create database mayan_edms;'
- psql -c 'create database mayan_edms;' -U postgres
script:
- if [[ $DB == mysql ]]; then coverage run manage.py test $TEST_APPS --settings=mayan.settings.travis.db_mysql; fi
- if [[ $DB == postgres ]]; then coverage run manage.py test $TEST_APPS --settings=mayan.settings.travis.db_postgres; fi
- if [[ $DB == sqlite ]]; then coverage run manage.py test $TEST_APPS --settings=mayan.settings.travis.base; fi
- if [[ $DB == mysql ]]; then coverage run manage.py runtests --settings=mayan.settings.testing.travis.db_mysql --nomigrations; fi
- if [[ $DB == postgres ]]; then coverage run manage.py runtests --settings=mayan.settings.testing.travis.db_postgres --nomigrations; fi
- if [[ $DB == sqlite ]]; then coverage run manage.py runtests --settings=mayan.settings.testing.base --nomigrations; fi
after_success:
- coveralls
branches:

View File

@@ -1,178 +1,188 @@
[main]
host = https://www.transifex.com
[mayan-edms.apps-acls]
[mayan-edms.acls-2-0]
file_filter = mayan/apps/acls/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/acls/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-checkouts]
[mayan-edms.appearance-2-0]
file_filter = mayan/apps/appearance/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/appearance/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.authentication-2-0]
file_filter = mayan/apps/authentication/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/authentication/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.checkouts-2-0]
file_filter = mayan/apps/checkouts/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/checkouts/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-common]
[mayan-edms.common-2-0]
file_filter = mayan/apps/common/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/common/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-converter]
[mayan-edms.converter-2-0]
file_filter = mayan/apps/converter/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/converter/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-django_gpg]
[mayan-edms.django_gpg-2-0]
file_filter = mayan/apps/django_gpg/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/django_gpg/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-documents]
[mayan-edms.documents-2-0]
file_filter = mayan/apps/documents/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/documents/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-document_comments]
[mayan-edms.document_comments-2-0]
file_filter = mayan/apps/document_comments/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/document_comments/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-document_indexing]
[mayan-edms.document_indexing-2-0]
file_filter = mayan/apps/document_indexing/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/document_indexing/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-document_signatures]
[mayan-edms.document_signatures-2-0]
file_filter = mayan/apps/document_signatures/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/document_signatures/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-document_states]
[mayan-edms.document_states-2-0]
file_filter = mayan/apps/document_states/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/document_states/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-dynamic_search]
[mayan-edms.dynamic_search-2-0]
file_filter = mayan/apps/dynamic_search/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/dynamic_search/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-events]
[mayan-edms.events-2-0]
file_filter = mayan/apps/events/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/events/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-folders]
[mayan-edms.folders-2-0]
file_filter = mayan/apps/folders/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/folders/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-installation]
[mayan-edms.installation-2-0]
file_filter = mayan/apps/installation/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/installation/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-linking]
[mayan-edms.linking-2-0]
file_filter = mayan/apps/linking/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/linking/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-mailer]
[mayan-edms.lock_manager-2-0]
file_filter = mayan/apps/lock_manager/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/lock_manager/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.mailer-2-0]
file_filter = mayan/apps/mailer/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/mailer/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-main]
file_filter = mayan/apps/main/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/main/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-metadata]
[mayan-edms.metadata-2-0]
file_filter = mayan/apps/metadata/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/metadata/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-navigation]
[mayan-edms.mirroring-2-0]
file_filter = mayan/apps/mirroring/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/mirroring/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.navigation-2-0]
file_filter = mayan/apps/navigation/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/navigation/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-ocr]
[mayan-edms.ocr-2-0]
file_filter = mayan/apps/ocr/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/ocr/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-permissions]
[mayan-edms.permissions-2-0]
file_filter = mayan/apps/permissions/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/permissions/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-project_setup]
file_filter = mayan/apps/project_setup/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/project_setup/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-project_tools]
file_filter = mayan/apps/project_tools/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/project_tools/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-rest_api]
[mayan-edms.rest_api-2-0]
file_filter = mayan/apps/rest_api/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/rest_api/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-smart_settings]
[mayan-edms.smart_settings-2-0]
file_filter = mayan/apps/smart_settings/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/smart_settings/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-statistics]
file_filter = mayan/apps/statistics/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/statistics/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-sources]
[mayan-edms.sources-2-0]
file_filter = mayan/apps/sources/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/sources/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-tags]
[mayan-edms.statistics-2-0]
file_filter = mayan/apps/statistics/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/statistics/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.storage-2-0]
file_filter = mayan/apps/storage/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/storage/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.tags-2-0]
file_filter = mayan/apps/tags/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/tags/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.apps-user_management]
[mayan-edms.user_management-2-0]
file_filter = mayan/apps/user_management/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/user_management/locale/en/LC_MESSAGES/django.po
type = PO

40
Dockerfile Normal file
View File

@@ -0,0 +1,40 @@
FROM ubuntu:15.04
MAINTAINER Roberto Rosario "roberto.rosario@mayan-edms.com"
# Install base Ubuntu libraries
RUN apt-get update && apt-get install -y netcat-openbsd python-dev python-pip gpgv nginx libpq-dev git-core libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv tesseract-ocr unpaper poppler-utils && apt-get clean && rm -rf /var/lib/apt/lists/* && rm -f /var/cache/apt/archives/*.deb
ENV MAYAN_INSTALL_DIR=/usr/local/lib/python2.7/dist-packages/mayan
# Install Mayan EDMS, latest production release
RUN pip install mayan-edms==2.0.0
# Install Python clients for PostgreSQL, REDIS, and uWSGI
RUN pip install psycopg2 redis uwsgi
# Create Mayan EDMS basic settings/local.py file
RUN mayan-edms.py createsettings
# Install Mayan EDMS static media files
RUN mayan-edms.py collectstatic --noinput
ADD docker /docker
# Setup Mayan EDMS settings file overrides
RUN cat /docker/conf/mayan/settings.py >> $MAYAN_INSTALL_DIR/settings/local.py
# Setup NGINX
RUN rm /etc/nginx/sites-enabled/default
RUN ln -s /docker/conf/nginx/mayan-edms /etc/nginx/sites-enabled/mayan-edms
# Setup UWSGI
RUN mkdir /var/log/uwsgi
# Persistent Mayan EDMS files
VOLUME $MAYAN_INSTALL_DIR/media
ENTRYPOINT ["/docker/entrypoint.sh"]
EXPOSE 80
CMD ["/docker/bin/run.sh"]

View File

@@ -1,3 +1,58 @@
2.0 (2015-10-xx)
================
- New source homepage: https://gitlab.com/mayan-edms/mayan-edms
- Update to Django 1.7
- New Bootstrap Frontend UI
- Easier theming and rebranding
- Improved page navigation interface
- Menu reorganization
- Removal of famfam icon set
- Improved document preview generation
- Document submission for OCR changed to POST
- New YAML based settings system
- Removal of auto admin creation as separate app
- Removal of dependencies
- ACL system refactor
- Object access control inheritance
- Removal of anonymous user support
- Metadata validators refactor
- Trash can support
- Retention policies
- Support for sharing indexes as FUSE filesystems
- Clickable preview images titles
- Removal of eval
- Smarter OCR, per page parsing or OCR fallback
- Improve failure tolerance (not all Operational Errors are critical now)
- RGB tags
- Default document type and default document source
- Link unbinding
- Statistics refactor
- Apps merge
- New signals
- Test improvements
- Indexes recalculation after document creation too
- Upgrade command
- OCR data moved to ocr app from documents app
- New internal document creation workflow return a document stub
- Auto console debug logging during development and info during production
- New class based and menu based navigation system
- New class based transformations
- Usage of Font Awesome icons set
- Management command to remove obsolete permissions: `purgepermissions`
- Normalization of 'title' and 'name' fields to 'label'
- Improved API, now at version 1
- Invert page title/project name order in browser title
- Django's class based views pagination
- Reduction of text strings
- Removal of the CombinedSource class
- Removal of default class ACLs
- Removal of the ImageMagick and GraphicsMagick converter backends
- Remove support for applying roles to new users automatically
- Removal of the DOCUMENT_RESTRICTIONS_OVERRIDE permission
- Removed the page_label field
1.1.1 (2015-05-21)
==================
@@ -41,9 +96,6 @@
- More technical documentation
For a full changelog and release notes go to: http://mayan.readthedocs.org/en/latest/releases/1.1.html
1.0 (2014-08-27)
================
@@ -63,5 +115,3 @@ For a full changelog and release notes go to: http://mayan.readthedocs.org/en/la
- License change, Mayan EDMS in now licensed under the Apache 2.0 License
- PyPI package, Mayan EDMS in now available on PyPI: https://pypi.python.org/pypi/mayan-edms/
- New REST API
For a full changelog and release notes go to: http://mayan.readthedocs.org/en/latest/releases/1.0.html

View File

@@ -1,3 +1,3 @@
include README.rst LICENSE HISTORY.rst
recursive-include mayan README *.txt *.html *.css *.ico *.png *.jpg *.js *.po *.mo *.ttf
global-exclude mayan/settings/local.py mayan/settings/travis/* settings_local.* mayan.sqlite* db.sqlite* mayan/media gpg_home document_storage image_cache
recursive-include mayan *.txt *.html *.css *.ico *.png *.jpg *.js *.po *.mo *.ttf *.woff *.woff2 LICENSE
global-exclude mayan/settings/local.py mayan/settings/travis/* mayan/media/*

View File

@@ -1,15 +1,7 @@
|Build Status| |Coverage Status| |PyPI badge| |Installs badge| |License badge| |Wheel badge|
|Build Status| |Coverage badge| |PyPI badge| |Installs badge| |License badge|
|Logo|
Notice: This project is being migrated to GitLab: https://gitlab.com/mayan-edms/mayan-edms. This repository will be removed once all tickets are closed.
.. image:: https://badges.gitter.im/Join%20Chat.svg
:alt: Join the chat at https://gitter.im/mayan-edms/mayan-edms
:target: https://gitter.im/mayan-edms/mayan-edms?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
Description
-----------
@@ -59,7 +51,7 @@ Contribute
- Fork `the repository`_ on GitHub to start making your changes to the **development** branch (or branch off of it).
- Write a test which shows that the bug was fixed or that the feature works as expected.
- Add yourself to the `contributors file`_.
- Send a pull request
- Send a merge request.
.. _Website: http://www.mayan-edms.com
@@ -69,20 +61,19 @@ Contribute
.. _Mailing list (via Google Groups): http://groups.google.com/group/mayan-edms
.. _Apache 2.0 License: https://www.apache.org/licenses/LICENSE-2.0.txt
.. _`the repository`: http://github.com/mayan-edms/mayan-edms
.. _`contributors file`: https://github.com/mayan-edms/mayan-edms/blob/master/docs/topics/contributors.rst
.. _`contributors file`: https://github.com/mayan-edms/mayan-edms/blob/development/docs/topics/contributors.rst
.. |Build Status| image:: http://img.shields.io/travis/mayan-edms/mayan-edms/master.svg?style=flat
:target: https://travis-ci.org/mayan-edms/mayan-edms
.. |Coverage Status| image:: http://img.shields.io/coveralls/mayan-edms/mayan-edms/master.svg?style=flat
:target: https://coveralls.io/r/mayan-edms/mayan-edms?branch=master
.. |Logo| image:: https://github.com/mayan-edms/mayan-edms/raw/master/docs/_static/mayan_logo.png
.. |Animation| image:: https://github.com/mayan-edms/mayan-edms/raw/master/docs/_static/overview.gif
.. |Build Status| image:: https://gitlab.com/ci/projects/6169/status.png?ref=development
:target: https://gitlab.com/ci/projects/6169?ref=development
.. |Logo| image:: https://github.com/mayan-edms/mayan-edms/raw/development/docs/_static/mayan_logo.png
.. |Animation| image:: https://github.com/mayan-edms/mayan-edms/raw/development/docs/_static/overview.gif
.. |Installs badge| image:: http://img.shields.io/pypi/dm/mayan-edms.svg?style=flat
:target: https://crate.io/packages/mayan-edms/
.. |PyPI badge| image:: http://img.shields.io/pypi/v/mayan-edms.svg?style=flat
:target: http://badge.fury.io/py/mayan-edms
.. |Wheel badge| image:: http://img.shields.io/badge/wheel-yes-green.svg?style=flat
.. |License badge| image:: http://img.shields.io/badge/license-Apache%202.0-green.svg?style=flat
.. |Analytics| image:: https://ga-beacon.appspot.com/UA-52965619-2/mayan-edms/readme?pixel
.. |Coverage badge| image:: https://codecov.io/gitlab/mayan-edms/mayan-edms/coverage.svg?branch=development
:target: https://codecov.io/gitlab/mayan-edms/mayan-edms?branch=development
|Analytics|

View File

@@ -1,19 +0,0 @@
<VirtualHost *:80>
# Uncomment if libapache2-mod-xsendfile is installed
# XSendFile On
# XSendFileAllowAbove On
ServerName mayan.yoursite.com
ServerAdmin admin@yoursite.com
DocumentRoot /var/www/mayan-edms
WSGIScriptAlias / /var/www/mayan-edms/mayan/mayan-edms.wsgi
<Directory /var/www/mayan-edms>
Order allow,deny
Allow from all
</Directory>
Alias /static /var/www/mayan-edms/media/static
<Location "/static">
SetHandler None
</Location>
</VirtualHost>

View File

@@ -1,14 +0,0 @@
# sample wsgi file for usage with apache webserver
# mayan installation in a virtualenv /opt/mayan/venv
# apache deployment in /var/www/mayan-edms
import os
import sys
import site
# set up python path to virtual environment
site.addsitedir(/opt/mayan/venv/lib/python2.7/site-packages)
sys.path.append(/var/www/mayan-edms)
os.environ[PYTHON_EGG_CACHE]=/var/www/django/cache
#django WSGI specifics
From django.core.handlers.wsgi import WSGIHandler
os.environ[DJANGO_SETTING_MODULE] = mayan.settings.production
application = WSGIHandler()

View File

@@ -1,31 +0,0 @@
# invoke gunicorn using
# 'gunicorn -c <this_file> <project_module>.wsgi:application
import os
import multiprocessing
from django.conf import settings
bind = settings.GUNICORN_BIND
workers = multiprocessing.cpu_count() * 2 + 1
preload_app = True
chdir = settings.BASE_DIR
user = settings.PROCESS_USER
group = user
log_dir = os.path.join(
os.path.dirname(settings.BASE_DIR), 'gunicorn_logs', settings.PROCESS_NAME)
if not os.path.isdir(log_dir):
os.makedirs(log_dir)
import pwd
import grp
os.chown(log_dir,
pwd.getpwnam(user).pw_uid,
grp.getgrnam(group).gr_gid)
accesslog = os.path.join(log_dir, 'access.log')
errorlog = os.path.join(log_dir, 'error.log')
proc_name = settings.PROCESS_NAME

View File

@@ -1,3 +1,3 @@
#!/bin/sh
DJANGO_SETTINGS_MODULE='mayan.settings.celery_redis' celery -A mayan worker -l DEBUG -Q checkouts,mailing,uploads,converter,ocr,tools,indexing,metadata -Ofair -B
DJANGO_SETTINGS_MODULE='mayan.settings.celery_redis' celery -A mayan worker -l DEBUG -Ofair -B

22
contrib/nginx/mayan Normal file
View File

@@ -0,0 +1,22 @@
server {
listen 80;
server_name localhost;
location / {
include uwsgi_params;
uwsgi_pass unix:/usr/share/mayan-edms/uwsgi.sock;
client_max_body_size 30M; # Increse if your plan to upload bigger documents
proxy_read_timeout 30s; # Increase if your document uploads take more than 30 seconds
}
location /static {
alias /usr/share/mayan-edms/mayan/media/static;
expires 1h;
}
location /favicon.ico {
alias /usr/share/mayan-edms/mayan/media/static/appearance/images/favicon.ico;
expires 1h;
}
}

View File

@@ -1,19 +0,0 @@
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name mayan;
access_log /var/log/nginx/access_mayan.log;
error_log /var/log/nginx/error_mayan.log;
location / {
uwsgi_pass unix:///run/uwsgi/app/mayan/socket;
include uwsgi_params;
uwsgi_param UWSGI_SCHEME $scheme;
uwsgi_param SERVER_SOFTWARE nginx/$nginx_version;
}
location /static/ {
root /srv/mayan/projects/mayan/mayan-edms/mayan/media/;
}
}

View File

@@ -1,46 +0,0 @@
upstream app_server {
server unix:/var/tmp/filesystem.sock fail_timeout=0;
}
server {
listen 80;
access_log off;
error_log /var/log/nginx/mayan-edms_error.log;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/css application/x-javascript text/xml
application/xml application/xml+rss text/javascript;
# Some version of IE 6 don't handle compression well on some mime-types, so just disable for them
gzip_disable "MSIE [1-6].(?!.*SV1)";
# Set a vary header so downstream proxies don't send cached gzipped content to IE6
gzip_vary on;
location / {
client_max_body_size 2M;
proxy_read_timeout 600s;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server;
break;
}
}
location /static {
expires 1h;
alias /usr/share/mayan-edms/lib/python2.7/site-packages/mayan/media/static;
}
location /favicon.ico {
alias /usr/share/mayan-edms/lib/python2.7/site-packages/mayan/media/static/core/images/favicon.ico;
}
}

View File

@@ -1,34 +0,0 @@
server {
listen 80;
server_name mayan.crossculturalconsult.com www.mayan.crossculturalconsult.com;
access_log /var/log/nginx/mayan.crossculturalconsult.com.access.log;
error_log /var/log/nginx/mayan.crossculturalconsult.com.error.log;
root /home/mayan/production/;
location /static/ {
alias /home/mayan/production/static_collected/;
}
location /media/ {
alias /home/mayan/production/media/;
}
location = /favicon.ico {
alias /home/mayan/production/media/favicon.ico;
}
location = /robots.txt {
alias /home/mayan/production/media/robots.txt;
}
location / {
proxy_pass http://127.0.0.1:8731;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
}
allow all;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,16 +1,26 @@
#!/usr/bin/env python
import sys
import os
import optparse
import sh
APP_LIST = ('acls', 'checkouts', 'common', 'converter', 'django_gpg', 'documents',
'document_comments', 'document_indexing', 'document_signatures', 'document_states', 'dynamic_search',
'events', 'folders', 'installation', 'linking', 'mailer', 'main', 'metadata', 'navigation',
'ocr', 'permissions', 'project_setup', 'project_tools', 'rest_api',
'smart_settings', 'sources', 'statistics', 'tags', 'user_management')
LANGUAGE_LIST = ('ar', 'bg', 'bs_BA', 'da', 'de_CH', 'de_DE', 'en', 'es', 'fa', 'fr', 'hu', 'hr_HR', 'id', 'it', 'lv', 'nb', 'nl_NL', 'pl', 'pt', 'pt_BR', 'ro_RO', 'ru', 'sl_SI', 'sq', 'tr_TR', 'vi_VN', 'zh_CN', 'zh_TW')
APP_LIST = (
'acls', 'appearance', 'authentication', 'checkouts', 'common',
'converter', 'django_gpg', 'document_comments', 'document_indexing',
'document_signatures', 'document_states', 'documents', 'dynamic_search',
'events', 'folders', 'installation', 'linking', 'lock_manager', 'mailer',
'metadata', 'mirroring', 'navigation', 'ocr', 'permissions', 'rest_api',
'smart_settings', 'sources', 'statistics', 'storage', 'tags',
'user_management'
)
LANGUAGE_LIST = (
'ar', 'bg', 'bs_BA', 'da', 'de_DE', 'en', 'es', 'fa', 'fr', 'hu', 'id',
'it', 'nl_NL', 'pl', 'pt', 'pt_BR', 'ro_RO', 'ru', 'sl_SI', 'vi_VN',
'zh_CN',
)
# Inactive translations
# 'de_CH', 'hr_HR', 'lv', 'nb', 'sq', 'tr_TR', 'zh_TW'
makemessages = sh.Command('django-admin.py')
makemessages = makemessages.bake('makemessages')
@@ -22,7 +32,9 @@ transifex_client = sh.Command('tx')
pull_translations = transifex_client.bake('pull')
push_translations = transifex_client.bake('push')
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'mayan'))
BASE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', 'mayan')
)
def process(command, app_list, language_list):
@@ -55,12 +67,30 @@ def process(command, app_list, language_list):
if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option('-m', '--make', help='create message sources file', dest='make', default=False, action='store_true')
parser.add_option('-c', '--compile', help='compile message files', dest='compile', default=False, action='store_true')
parser.add_option('-p', '--pull', help='pull translation files', dest='pull', default=False, action='store_true')
parser.add_option('-u', '--push', help='push translation files', dest='push', default=False, action='store_true')
parser.add_option('-a', '--app', help='specify which app to process', dest='app', action='store', metavar='appname')
parser.add_option('-l', '--lang', help='specify which language to process', dest='lang', action='store', metavar='language')
parser.add_option(
'-m', '--make', help='create message sources file', dest='make',
default=False, action='store_true'
)
parser.add_option(
'-c', '--compile', help='compile message files', dest='compile',
default=False, action='store_true'
)
parser.add_option(
'-p', '--pull', help='pull translation files', dest='pull',
default=False, action='store_true'
)
parser.add_option(
'-u', '--push', help='push translation files', dest='push',
default=False, action='store_true'
)
parser.add_option(
'-a', '--app', help='specify which app to process', dest='app',
action='store', metavar='appname'
)
parser.add_option(
'-l', '--lang', help='specify which language to process', dest='lang',
action='store', metavar='language'
)
(opts, args) = parser.parse_args()
if not opts.make and not opts.compile:

View File

@@ -1,5 +0,0 @@
[program:openoffice]
command = /usr/lib/libreoffice/program/soffice.bin "-accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" -headless -nodefault -nofirststartwizard -nolockcheck -nologo -norestore
stdout_logfile= /var/log/libreoffice-headless.log
redirect_stderr = true
autostart = true

View File

@@ -0,0 +1,26 @@
[program:mayan-worker]
command = /usr/share/mayan-edms/bin/python /usr/share/mayan-edms/bin/mayan-edms.py celery --settings=mayan.settings.production worker -Ofair -l ERROR
directory = /usr/share/mayan-edms
user = www-data
stdout_logfile = /var/log/mayan/worker-stdout.log
stderr_logfile = /var/log/mayan/worker-stderr.log
autostart = true
autorestart = true
startsecs = 10
stopwaitsecs = 10
killasgroup = true
priority = 998
[program:mayan-beat]
command = /usr/share/mayan-edms/bin/python /usr/share/mayan-edms/bin/mayan-edms.py celery --settings=mayan.settings.production beat -l ERROR
directory = /usr/share/mayan-edms
user = www-data
numprocs = 1
stdout_logfile = /var/log/mayan/beat-stdout.log
stderr_logfile = /var/log/mayan/beat-stderr.log
autostart = true
autorestart = true
startsecs = 10
stopwaitsecs = 1
killasgroup = true
priority = 998

View File

@@ -1,7 +0,0 @@
[program:mayan-edms]
command = /usr/share/mayan-edms/contrib/scripts/gunicorn_start.sh
user = www-data
autostart = true
autorestart = true
redirect_stderr = true

View File

@@ -0,0 +1,6 @@
[program:mayan-uwsgi]
command = /usr/share/mayan-edms/bin/uwsgi --ini /usr/share/mayan-edms/uwsgi.ini
user = root
autostart = true
autorestart = true
redirect_stderr = true

View File

@@ -1,10 +0,0 @@
#!/bin/bash
# Run the gunicorn service
# Make sure we're in the right virtual env and location
source /home/mayan/.virtualenvs/production/bin/activate
source /home/mayan/.virtualenvs/production/bin/postactivate
cd /home/mayan/production
exec gunicorn -c /home/mayan/production/deploy/gunicorn.conf.py mayan.wsgi:application

View File

@@ -1,10 +0,0 @@
start on started rc
stop on stopped rc
respawn
respawn limit 3 5
setuid mayan
setgid mayan
exec /home/mayan/production/deploy/production/service_demon.sh

View File

@@ -1,14 +0,0 @@
# Sample file for uswgi with mayan installed in a virtualenv mayan
# with project directory mayan e.g. for use with nginx connecting via
# local unix socket
[uwsgi]
#socket = 127.0.0.1:3031
plugin = python
chdir = /srv/mayan/projects/mayan/mayan-edms
virtualenv = /srv/mayan/.virtualenvs/mayan
env = DJANGO_SETTINGS_MODULE=mayan.settings.production
module = django.core.handlers.wsgi:WSGIHandler()
processes = 4
threads = 2
stats = :9191
buffer-size=32768

21
docker-compose.yml Normal file
View File

@@ -0,0 +1,21 @@
postgres:
env_file:
- ./environment
image: postgres
volumes:
- /var/lib/postgresql/data
redis:
image: redis
mayan-edms:
env_file:
- ./environment
image: mayanedms/monolithic
links:
- postgres
- redis
ports:
- "80:80"
volumes:
- /usr/local/lib/python2.7/dist-packages/mayan/media

10
docker/bin/run.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Launch NGINX daemon
nginx
# Launch the workers
mayan-edms.py celery worker --settings=mayan.settings.production -Ofair -l ERROR -B &
# Launch uWSGI in foreground
/usr/local/bin/uwsgi --ini /docker/conf/uwsgi/uwsgi.ini

View File

@@ -0,0 +1,15 @@
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ.get('POSTGRES_DB'),
'USER': os.environ.get('POSTGRES_USER'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
'HOST': os.environ.get('POSTGRES_PORT_5432_TCP_ADDR'),
'PORT': os.environ.get('POSTGRES_PORT_5432_TCP_PORT'),
}
}
BROKER_URL = 'redis://{}:{}/0'.format(os.environ.get('REDIS_PORT_6379_TCP_ADDR'), os.environ.get('REDIS_PORT_6379_TCP_PORT'))
CELERY_RESULT_BACKEND = 'redis://{}:{}/0'.format(os.environ.get('REDIS_PORT_6379_TCP_ADDR'), os.environ.get('REDIS_PORT_6379_TCP_PORT'))

View File

@@ -0,0 +1,22 @@
server {
listen 80;
server_name localhost;
location / {
include uwsgi_params;
uwsgi_pass unix:/run/mayan.sock;
client_max_body_size 30M; # Increse if your plan to upload bigger documents
proxy_read_timeout 30s; # Increase if your document uploads take more than 30 seconds
}
location /static {
alias /usr/local/lib/python2.7/dist-packages/mayan/media/static;
expires 1h;
}
location /favicon.ico {
alias /usr/local/lib/python2.7/dist-packages/mayan/media/static/appearance/images/favicon.ico;
expires 1h;
}
}

View File

@@ -0,0 +1,14 @@
[uwsgi]
chdir = $(MAYAN_INSTALL_DIR)
chmod-socket = 664
chown-socket = www-data:www-data
env = DJANGO_SETTINGS_MODULE=mayan.settings.production
gid = root
logto = /var/log/uwsgi/%n.log
pythonpath = /usr/local/lib/python2.7/dist-packages
master = True
max-requests = 5000
socket = /run/mayan.sock
uid = root
vacuum = True
wsgi-file = $(MAYAN_INSTALL_DIR)/wsgi.py

17
docker/entrypoint.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
set -e
if [[ -z $POSTGRES_PORT_5432_TCP_ADDR ]]; then
echo "** ERROR: You need to link the Postgres container."
exit 1
fi
until nc -z $POSTGRES_PORT_5432_TCP_ADDR $POSTGRES_PORT_5432_TCP_PORT; do
echo "$(date) - waiting for Postgres..."
sleep 1
done
# Migrate database, create initial admin user
mayan-edms.py initialsetup
exec "$@"

View File

@@ -128,3 +128,6 @@ doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
livehtml:
sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html

BIN
docs/_static/api.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
docs/_static/document_view.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
docs/_static/main.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 628 KiB

BIN
docs/_static/page_view.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
docs/_static/setup.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/_static/statistics.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/_static/tools.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -1,3 +1,5 @@
<script type="text/javascript" src="https://gumroad.com/js/gumroad.js"></script>
<a href="https://gumroad.com/l/UNApl" class="gumroad-button">Buy Mayan EDMS</a>
<h3>Donate</h3>
<p>
Help support further improvements and development by donating on: <a href="https://www.patreon.com/siloraptor">Patreon</a>

View File

@@ -33,7 +33,12 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext"))
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
#extensions = ["djangodocs", "sphinx.ext.intersphinx"]
extensions = ['djangodocs']
extensions = ['djangodocs', 'sphinxcontrib.blockdiag']
blockdiag_antialias = True
blockdiag_html_image_format = "SVG"
blockdiag_latex_image_format = "PDF"
blockdiag_tex_image_format = "PDF"
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -229,20 +234,19 @@ man_pages = [
import alabaster
html_theme_path = [alabaster.get_path()]
extensions = ['alabaster']
extensions.append('alabaster')
html_theme = 'alabaster'
html_sidebars = {
'**': [
'about.html', 'navigation.html', 'searchbox.html', 'donate.html',
'about.html', 'donate.html', 'navigation.html', 'searchbox.html',
]
}
html_theme_options = {
'description': 'Free Open Source Electronic Document Management System',
'github_user': 'mayan-edms',
'github_repo': 'mayan-edms',
'travis_button': True,
'description': mayan.__description__,
'github_button': False,
'travis_button': False,
'gratipay_user': 'rosarior',
'github_banner': True,
'github_banner': False,
}
html_logo = '_static/logo_pyramid_only.png'

View File

@@ -10,31 +10,36 @@ and installing it from PyPI with the following commands:
.. code-block:: bash
$ sudo apt-get install libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv tesseract-ocr unpaper poppler-utils -y
$ virtualenv venv
$ source venv/bin/activate
$ pip install mayan-edms
$ mayan-edms.py initialsetup
$ mayan-edms.py runserver
sudo apt-get install libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv tesseract-ocr unpaper poppler-utils -y
virtualenv venv
source venv/bin/activate
pip install mayan-edms
mayan-edms.py initialsetup
mayan-edms.py runserver
Point your browser to 127.0.0.1:8000 and use the automatically created admin
account.
.. image:: /_static/overview.gif
:alt: Overview
.. toctree::
:hidden:
Features <topics/features>
Installation <topics/installation>
Getting started <topics/getting_started>
Deploying <topics/deploying>
Release notes and upgrading <releases/index>
Concepts <topics/index>
Development <topics/development>
App creation <topics/app_creation>
Translations <topics/translations>
Contributors <topics/contributors>
Screenshots <topics/screenshots>
Licensing <topics/license>
FAQ <topics/faq>
Contact <topics/contact>
.. _Django: http://www.djangoproject.com/
.. _Free Open Source: http://en.wikipedia.org/wiki/Open_source
.. _Electronic Document Management System: https://en.wikipedia.org/wiki/Document_management_system

View File

@@ -13,7 +13,7 @@ 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
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.
@@ -24,7 +24,7 @@ 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,
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
@@ -36,10 +36,10 @@ 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 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
@@ -50,30 +50,30 @@ 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`
adds just one new configuration option: `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
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``
option: `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
The OCR queue is now active by default when first created during the
``syncdb`` phase and the `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
@@ -95,7 +95,7 @@ Install the ``poppler-utils`` package:
* Ubuntu, Debian::
$ apt-get install -y poppler-utils
* Fedora::
$ yum install -y poppler-utils
@@ -112,5 +112,5 @@ Bugs fixed
* Issue #25 "Office document conversion error"
Stuff removed
=============
=============
* None

View File

@@ -27,10 +27,10 @@ Smarter auto admin creation
**Mayan EDMS** creates a administrator user during the
database creation phase to reduce the amount of steps required for a
functional install. The creation of this account is controlled by the configuration
option :setting:`COMMON_AUTO_CREATE_ADMIN`, the username of the account is
specified with the configuration option :setting:`COMMON_AUTO_ADMIN_USERNAME`
and the password of this account by the option :setting:`COMMON_AUTO_ADMIN_PASSWORD`.
Previously the :setting:`COMMON_AUTO_ADMIN_PASSWORD` defaulted to 'admin' which
option `COMMON_AUTO_CREATE_ADMIN`, the username of the account is
specified with the configuration option `COMMON_AUTO_ADMIN_USERNAME`
and the password of this account by the option `COMMON_AUTO_ADMIN_PASSWORD`.
Previously the `COMMON_AUTO_ADMIN_PASSWORD` defaulted to 'admin' which
created an administrator account of username 'admin' with a password of
'admin'. The new default is to randomize an initial password and show this password
at the login screen until the administrator password is changed.

View File

@@ -60,7 +60,7 @@ ACL support
Anonymous user support
~~~~~~~~~~~~~~~~~~~~~~
Anonymous user support is a two tier function, first is the addition of
the :setting:`COMMON_ALLOW_ANONYMOUS_ACCESS` configuration option that
the `COMMON_ALLOW_ANONYMOUS_ACCESS` configuration option that
allows non authenticated user to browse all the pages of a **Mayan EDMS** installation.
The second part of this support is the ability to assign permissions
or individual access to objects to anonymous users.
@@ -88,7 +88,7 @@ the download of several documents in a single compressed file.
Customizable GPG home directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Addition of the :setting:`SIGNATURES_GPG_HOME` configuration option to let
Addition of the `SIGNATURES_GPG_HOME` configuration option to let
administrators set **Mayan EDMS**'s GPG instance home directory, used to
store keyrings and other GPG configuration files.
@@ -116,7 +116,7 @@ These populated trees can also be mirrored on the physical filesystem and shared
using Samba or another filesharing server giving users a structured view
of the documents contained within **Mayan EDMS** from the ``Indexes`` tab
or from a mirrored index shared via the network. A new configuration option
has been added, :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`, which maps
has been added, `DOCUMENT_INDEXING_FILESYSTEM_SERVING`, which maps
the index internal name with the physical directory where such index will be
mirrored on disk.
@@ -226,6 +226,6 @@ Stuff removed
* Configuration options removed:
* OCR_CACHE_URI
* DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH - Use the newest :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`
* DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE - Use the newest :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`
* DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH - Use the newest `DOCUMENT_INDEXING_FILESYSTEM_SERVING`
* DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE - Use the newest `DOCUMENT_INDEXING_FILESYSTEM_SERVING`

508
docs/releases/2.0.rst Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -17,8 +17,15 @@ Final releases
Below are release notes through **Mayan EDMS** |version| and its minor releases. Newer
versions of the documentation contain the release notes for any later releases.
2.0 series
----------
.. toctree::
:maxdepth: 1
2.0
1.0 series
-----------
----------
.. toctree::
:maxdepth: 1

73
docs/topics/acls.rst Normal file
View File

@@ -0,0 +1,73 @@
====================
Access control lists
====================
Besides the permissions system explained in :doc:`permissions`, **Mayan EDMS**
provides per object permission granting. This feature is used to grant a
permission to a role, but this permission can only be executed for a limited
number of objects (documents, folders, tags) instead of being effective
system-wide.
.. blockdiag::
blockdiag {
document [ label = 'Document' ];
role [ label = 'Role' ];
permission [ label = 'Permission' ];
role -> document <- permission;
}
Example:
.. blockdiag::
blockdiag {
document [ label = '2015 Payroll report.txt', width=200 ];
role [ label = 'Accountants' ];
permission [ label = 'View document' ];
role -> document <- permission;
}
In this scenario only users in groups belonging to the ``Accountants`` role
would be able to view the ``2015 Payroll report.txt`` document.
Inherited access control
========================
It is also possible to grant a permission to a role for a specific document type (:doc:`document_types`).
Under this scheme all users in groups belonging to that role will inherit that
permission for all documents of that type.
.. blockdiag::
blockdiag {
document_type [ label = 'Document type' ];
role [ label = 'Role' ];
permission [ label = 'Permission' ];
role -> document_type <- permission;
}
Example:
.. blockdiag::
blockdiag {
document_type [ label = 'Payroll reports', width=200 ];
role [ label = 'Accountants' ];
permission [ label = 'View document' ];
role -> document_type <- permission;
}
The role ``Accountants`` is given the permission ``document view`` for the
document type ``Payroll reports``. Now all users in groups belonging to the
``Accountants`` role can view all documents of the type ``Payroll reports``
without needing to have that permissions granted for each particular
``Payroll reports`` type document.
If access control for the ``Payroll reports`` documents needs to be updated it
only needs to be done for the document type and not for each document of the type
``Payroll reports``.

View File

@@ -0,0 +1,143 @@
============
App creation
============
**Mayan EDMS** apps are essentially Django app with some extra code to register
navigation, permissions and other relationships.
App modules
===========
- __init__.py
Should be empty if possible. No initialization code should be here, use the
ready() method of the MayanAppConfig class in the apps.py module.
- admin.py
Standard Django app module to define how models are to be presented in the
admin interface.
- api_views.py
REST API views go here. **Mayan EDMS** uses Django REST Framework API view
classes.
- apps.py
Contains the MayanAppConfig subclass as required by Django 1.7 and up. This
is a place to define the app name and translatable verbose name as well as
code to be execute when the modules of the app are ready.
- classes.py
Hold python classes to be used internally or externally. Any class defined by
the app that is not a model.
- events.py
Define event class instances that are later committed to a log by custom
code.
- exceptions.py
Custom exceptions defined by the app.
- fields.py
Place any custom form field classed you define here.
- forms.py
Standard Django app module that hold custom form classes.
- handlers.py
Contains the signal handlers, functions that will process a given signal
emitted from this or other apps. Connect the handler functions to the
corresponding signal in the ready() method of the MayanAppConfig subclass in
apps.py
- links.py
Defines the links to be used by the app. Import only from the navigation app
and the local permissions.py file.
- literals.py
Stores magic numbers, module choices (if static), settings defaults, and
constants. Should contain all capital case variables. Must not import from
any other module.
- managers.py
Standard Django app module that hold custom model managers. These act as
model class method to performs actions in a series of model instances or
utilitarian actions on external models instances.
- models.py
Standard Django app module that defines ORM persistent data schema.
- permissions.py
Defines the permissions to be used to validate user access by links and views.
Imports only from the permissions app. Link or view conditions such as
testing for is_staff or is_super_user flag are defined in this same module.
- runtime.py
Use this module when you need the same instance of a class for the entire app.
This module acts as a shared memory space for the other modules of the app or
other apps.
- serializers.py
Hold Django REST Framework serializers used by the api_views.py module.
- settings.py
Define the configuration settings instances that the app will use.
- signals.py
Any custom defined signal goes here.
- statistics.py
Provides functions that will compute any sort of statistical information on
the apps data.
- tasks.py
Code to be execute in the background or as an out-of-process action.
- tests/ directory
Hold test modules. There should be one test_*.py module for each aspect being
tested, examples: test_api.py, test_views.py, test_parsers.py, test_permissions.py
Any shared constant data used by the tests should be added to tests/literals.py
- utils.py
Holds utilitarian code that doesn't fit on any other app module or that is
used by several modules in the app. Anything used internally by the app that
is not a class or a literal (should be as little as possible)
- widgets.py
HTML widgets go here. This should be the only place with presentation
directives in the app (aside the templates).
Views
=====
The module common.generics provides custom generic class based views to be used.
The basic views used to create, edit, view and delete objects in **Mayan EDMS**
are: SingleObjectCreateView, SingleObjectDetailView, SingleObjectEditView,
and SingleObjectListView
These views handle aspects relating to view permissions, object permissions,
post action redirection and template context generation.

14
docs/topics/checkouts.rst Normal file
View File

@@ -0,0 +1,14 @@
=========
Checkouts
=========
Checkouts are a way to block certain accesses or actions of a document for a
period of time.
An user can choose to checkout a document to work on an update and block new
versions of that document to be uploaded by other users. Document are checked
out for a certain amount of time and if not manually checked in by the original
user, will be checked in automatically by the system.
To be able to check in documents that were checked out by other users, the
permission 'Forcefully check in documents' is required.

View File

@@ -12,11 +12,12 @@ Mailing list
------------
Search for information in the `archives of the mayan-edms mailing list`_, or
`post a question`_. If you prefer news servers, use the gateway provided by Gmane_.
`post a question`_. If you prefer news servers, use the gateway provided by
Gmane_.
**Mayan EDMS** community developers do their best to reply to basic questions.
Be sure to check the list archives as it may already containt the answers to your
questions.
Be sure to check the list archives as it may already containt the answers to
your questions.
Twitter
-------
@@ -34,5 +35,5 @@ Report bugs with **Mayan EDMS** or search existing ones using Github's `ticket t
.. _archives of the mayan-edms mailing list: http://groups.google.com/group/mayan-edms/
.. _post a question: http://groups.google.com/group/mayan-edms
.. _ticket tracker: https://github.com/mayan-edms/mayan-edms/issues
.. _ticket tracker: https://gitlab.com/mayan-edms/mayan-edms/issues
.. _Gmane: http://news.gmane.org/gmane.comp.python.django.mayan-edms

View File

@@ -8,7 +8,8 @@ Contributors
How to contribute?
------------------
You can help further the development of **Mayan EDMS** by testing, reporting bugs, submitting documentation or code patches.
You can help further the development of **Mayan EDMS** by testing, reporting
bugs, submitting documentation or code patches.
Lead developer
--------------
@@ -20,8 +21,10 @@ Contributors (in alphabetical order)
* Bertrand Bordage (https://github.com/BertrandBordage)
* Brian E (brian@realize.org)
* David Herring (https://github.com/abadger1406)
* Emlyn Clay (https://github.com/EmlynC)
* Jens Kadenbach (https://github.com/audax)
* Kolmar Kafran
* Helga Carrero
* IHLeanne (https://github.com/IHLeanne)
* Iliya Georgiev (ikgeorgiev@gmail.com)
* Lars Kruse (devel@sumpfralle.de)

191
docs/topics/deploying.rst Normal file
View File

@@ -0,0 +1,191 @@
=========
Deploying
=========
OS "bare metal"
===============
Like other Django based projects **Mayan EDMS** can be deployed in a wide variety
of ways. The method provided below is only a bare minimum example.
These instructions are independent of the instructions mentioned in the
:doc:`installation` chapter but assume you have already made a test install to
test the compatibility of your operating system. These instruction are for
Ubuntu 15.04.
Switch to superuser::
sudo -i
Install all system dependencies::
apt-get install nginx supervisor redis-server postgresql \
libpq-dev libjpeg-dev libmagic1 libpng-dev libreoffice \
libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv \
tesseract-ocr unpaper poppler-utils -y
Change the directory to where the project will be deployed::
cd /usr/share
Create the Python virtual environment for the installation::
virtualenv mayan-edms
Activate virtual env::
source mayan-edms/bin/activate
Install Mayan EDMS::
pip install mayan-edms
Install the Python client for PostgreSQL, Redis, and uWSGI::
pip install psycopg2 redis uwsgi
Create the database for installation::
sudo -u postgres createuser -P mayan (provide password)
sudo -u postgres createdb -O mayan mayan
Create the directories for the logs::
mkdir /var/log/mayan
Change the current directory to be the one of the installation::
cd mayan-edms
Make a convenience symlink::
ln -s lib/python2.7/site-packages/mayan .
Create an initial settings file::
mayan-edms.py createsettings
Update the ``mayan/settings/local.py`` file::
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'mayan',
'USER': 'mayan',
'PASSWORD': '<password used when creating postgreSQL user>',
'HOST': 'localhost',
'PORT': '5432',
}
}
BROKER_URL = 'redis://127.0.0.1:6379/0'
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0'
Migrate the database or initialize the project::
mayan-edms.py initialsetup
Disable the default NGINX site::
rm /etc/nginx/sites-enabled/default
Create the NGINX site file for Mayan EDMS, ``/etc/nginx/site-available/mayan``::
server {
listen 80;
server_name localhost;
location / {
include uwsgi_params;
uwsgi_pass unix:/usr/share/mayan-edms/uwsgi.sock;
client_max_body_size 30M; # Increse if your plan to upload bigger documents
proxy_read_timeout 30s; # Increase if your document uploads take more than 30 seconds
}
location /static {
alias /usr/share/mayan-edms/mayan/media/static;
expires 1h;
}
location /favicon.ico {
alias /usr/share/mayan-edms/mayan/media/static/appearance/images/favicon.ico;
expires 1h;
}
}
Enable the NGINX site for Mayan EDMS::
ln -s /etc/nginx/sites-available/mayan /etc/nginx/sites-enabled/
Create the supervisor file for the uWSGI process, ``/etc/supervisor/conf.d/mayan-uwsgi.conf``::
[program:mayan-uwsgi]
command = /usr/share/mayan-edms/bin/uwsgi --ini /usr/share/mayan-edms/uwsgi.ini
user = root
autostart = true
autorestart = true
redirect_stderr = true
Create the supervisor file for the Celery worker, ``/etc/supervisor/conf.d/mayan-celery.conf``::
[program:mayan-worker]
command = /usr/share/mayan-edms/bin/python /usr/share/mayan-edms/bin/mayan-edms.py celery --settings=mayan.settings.production worker -Ofair -l ERROR
directory = /usr/share/mayan-edms
user = www-data
stdout_logfile = /var/log/mayan/worker-stdout.log
stderr_logfile = /var/log/mayan/worker-stderr.log
autostart = true
autorestart = true
startsecs = 10
stopwaitsecs = 10
killasgroup = true
priority = 998
[program:mayan-beat]
command = /usr/share/mayan-edms/bin/python /usr/share/mayan-edms/bin/mayan-edms.py celery --settings=mayan.settings.production beat -l ERROR
directory = /usr/share/mayan-edms
user = www-data
numprocs = 1
stdout_logfile = /var/log/mayan/beat-stdout.log
stderr_logfile = /var/log/mayan/beat-stderr.log
autostart = true
autorestart = true
startsecs = 10
stopwaitsecs = 1
killasgroup = true
priority = 998
Collect the static files::
mayan-edms.py collectstatic --noinput
Make the installation directory readable and writable by the webserver user::
chown www-data:www-data /usr/share/mayan-edms -R
Restart the services::
/etc/init.d/nginx restart
/etc/init.d/supervisor restart
Docker
======
Deploy the Mayan EDMS Docker image::
docker run --name postgres -e POSTGRES_DB=mayan -e POSTGRES_USER=mayan -e POSTGRES_PASSWORD=mysecretpassword -v /var/lib/postgresql/data -d postgres
docker run --name redis -d redis
docker run --name mayan-edms -p 80:80 --link postgres:postgres --link redis:redis -e POSTGRES_DB=mayan -e POSTGRES_USER=mayan -e POSTGRES_PASSWORD=mysecretpassword -v /usr/local/lib/python2.7/dist-packages/mayan/media -d mayanedms/monolithic
After the **Mayan EDMS** container finishes initializing (about 5 minutes), it will
be available by browsing to http://127.0.0.1
Docker Compose
==============
Launch the entire stack using::
docker-compose -f docker-compose.yaml up -d
After the **Mayan EDMS** container finishes initializing (about 5 minutes), it will
be available by browsing to http://127.0.0.1

View File

@@ -6,31 +6,41 @@ Development
**Mayan EDMS** is under active development, and contributions are welcome.
If you have a feature request, suggestion or bug report, please open a new
issue on the `GitHub issue tracker`_. To submit patches, please send a pull
request on GitHub_. Make sure to add yourself to the :ref:`contributors` file.
issue on the `GitLab issue tracker`_. To submit patches, please send a pull
request on GitLab_. Make sure to add yourself to the :ref:`contributors` file.
.. _GitHub: https://github.com/mayan-edms/mayan-edms/
.. _`GitHub issue tracker`: https://github.com/mayan-edms/mayan-edms/issues
.. _GitLab: https://gitlab.com/mayan-edms/mayan-edms/
.. _`GitLab issue tracker`: https://gitlab.com/mayan-edms/mayan-edms/issues
Project philosophies
--------------------
How to think about **Mayan EDMS** when doing changes or adding new features, why things are the way they are in **Mayan EDMS**.
How to think about **Mayan EDMS** when doing changes or adding new features,
why things are the way they are in **Mayan EDMS**.
- Functionality must be as market/sector independent as possible, code for the 95% of use cases.
- Each user must be able to configure and customize it to their needs after install.
- Abstract as much as possible, each app must be an expert in just one thing, for other things they should use the API/classes/functions of other apps.
- Assume as little as possible about anything outside the project (hardware, OS, storage).
- Provide Python based abstraction so that a default install runs with a single step.
- Functionality must be as market/sector independent as possible, code for the
95% of use cases.
- Each user must be able to configure and customize it to their needs after
install.
- Abstract as much as possible, each app must be an expert in just one thing,
for other things they should use the API/classes/functions of other apps.
- Assume as little as possible about anything outside the project
(hardware, OS, storage).
- Provide Python based abstraction so that a default install runs with a single
step.
- No hard dependencies on binaries unless there is no other choice.
- Provide “drivers” or switchable backends to allow users to fine tune the installation.
- Call to binaries only when there is no other choice or the Python choices are not viable/mature/efficient.
- Each app is as independent and self contained as possible. Exceptions, the basic requirements: navigation, permissions, common, main.
- If an app is meant to be used by more than one other app it should be as generic as possible in regard to the project and another app will bridge the functionality.
- Provide “drivers” or switchable backends to allow users to fine tune the
installation.
- Call to binaries only when there is no other choice or the Python choices are
not viable/mature/efficient.
- Each app is as independent and self contained as possible. Exceptions, the
basic requirements: navigation, permissions, common, main.
- If an app is meant to be used by more than one other app it should be as
generic as possible in regard to the project and another app will bridge the functionality.
- Example: the acls app is app agnostic, document_acls connects the acls app with the documents app.
- Example: since indexing (document_indexing) only applies to documents, the app is specialized and dependant on the documents app.
- Example: since indexing (document_indexing) only applies to documents, the
app is specialized and depends on the documents app.
Coding conventions
@@ -93,7 +103,9 @@ Example:
)
from .models import Index, IndexInstanceNode, DocumentRenameCount
All local app module imports are in relative form, local app module name is to be referenced as little as possible, unless required by a specific feature, trick, restriction, ie: Runtime modification of the module's attributes.
All local app module imports are in relative form, local app module name is to
be referenced as little as possible, unless required by a specific feature,
trick, restriction, ie: Runtime modification of the module's attributes.
Incorrect:
@@ -113,12 +125,18 @@ Correct:
Dependencies
~~~~~~~~~~~~
**Mayan EDMS** apps follow a hierarchical model of dependency. Apps import from their parents or siblings, never from their children. Think plugins. A parent app must never assume anything about a possible existing child app. The documents app and the Document model are the basic entities they must never import anything else. The common and main apps are the base apps.
**Mayan EDMS** apps follow a hierarchical model of dependency. Apps import from
their parents or siblings, never from their children. Think plugins. A parent
app must never assume anything about a possible existing child app. The
documents app and the Document model are the basic entities they must never
import anything else. The common and main apps are the base apps.
Variables
~~~~~~~~~
Naming of variables should follow a Major to Minor convention, usually including the purpose of the variable as the first piece of the name, using underscores as spaces. camelCase is not used in **Mayan EDMS**.
Naming of variables should follow a Major to Minor convention, usually
including the purpose of the variable as the first piece of the name, using
underscores as spaces. camelCase is not used in **Mayan EDMS**.
Examples:
@@ -153,125 +171,46 @@ Classes:
Strings
~~~~~~~
Quotation character used in **Mayan EDMS** for strings is the single quote. Double quote is used for multiline comments or HTML markup.
Quotation character used in **Mayan EDMS** for strings is the single quote.
Double quote is used for multiple line comments or HTML markup.
Migrations
~~~~~~~~~~
Migrations should do only one thing (eg: either create a table, move data to a
new table or remove an old table) to aid retrying on failure.
General
~~~~~~~
Code should appear in their modules in alphabetic order or in their order of importance if it makes more sense for the specific application.
This makes visual scanning easier on modules with a large number of imports, views or classes.
Class methods that return a value should be prepended with a ``get_`` to differentiate from an objects properties.
When a variable refers to a file it should be named as follows:
Code should appear in their modules in alphabetic order or in their order of
importance if it makes more sense for the specific application. This makes
visual scanning easier on modules with a large number of imports, views or
classes. Class methods that return a value should be pretended with a
``get_`` to differentiate from an objects properties. When a variable refers
to a file it should be named as follows:
- filename: The files name and extension only.
- filepath: The entire path to the file including the filename.
- path: A path to a directory.
Flash messages should end with a period as applicable for the language.
Only exception is when the tail of the message contains an exceptions message as passed directly from the exception object.
App anatomy
~~~~~~~~~~~
- __init__.py
- Generic initialization code (should be empty if possible)
- api.py
- File to hold functions that are meant to be used by external apps.
- Interfaces meant to be used by other apps that are not models or classes.
- classes.py
- Hold python classes to be used internally or externally.
- Any class defined by the app that is not a model.
- diagnostics.py
- Define functions that will return the state of the data of an app.
- Does not fixes the problems only finds them.
- events.py
- Define history type events
- exceptions.py
- Exceptions defined by the app
- icons.py
- Defines the icons to be used by the links and views of the app.
- Imports from the icons app only.
- links.py
- Defines the links to be used by the app.
- Import only from the navigation app and the local icons.py file.
- literals.py
- Stores magic numbers, module choices (if static), settings defaults, and constants.
- Should contain all capital case variables.
- Must not import from any other module.
- maintenance.py
- Hold functions that the user may run periodically to fix errors in the apps data.
- permissions.py
- Defines the permissions to be used by links and views to validate access.
- Imports only from permissions app.
- Link or view conditions such as testing for staff or super admin status are defined in the same file.
- statistics.py
- Provides functions that will computer any sort of statistical information on the apps data.
- tasks.py
- Code to be execute as in the background or a as an process-of-process action.
- utils.py
- Hold utilitarian code that doesn't fit on any other app file or that is used by several files in the app.
- Anything used internally by the app that is not a class or a literal (should be as little as possible)
Views behavior
~~~~~~~~~~~~~~
- Delete views:
- Redirect to object list view if one object is deleted.
- Redirect to previous view if many are deleted.
- Previous view equals:
- previous variable in POST or
- previous variable in GET or
- request.META.HTTP_REFERER or
- object list view or
- 'home' view
- fallback to /
- if previous equal same view then previous should equal object list view or /
Only exception is when the tail of the message contains an exceptions message
as passed directly from the exception object.
Source Control
--------------
**Mayan EDMS** source is controlled with Git_.
The project is publicly accessible, hosted and can be cloned from **GitHub** using::
The project is publicly accessible, hosted and can be cloned from **GitLab** using::
$ git clone git://github.com/mayan-edms/mayan-edms.git
git clone https://gitlab.com/mayan-edms/mayan-edms.git
Git branch structure
--------------------
**Mayan EDMS** follows the model layout by Vincent Driessen in his `Successful Git Branching Model`_ blog post. Git-flow_ is a great tool for managing the repository in this way.
**Mayan EDMS** follows a simplified model layout based on Vincent Driessen's
`Successful Git Branching Model`_ blog post.
``develop``
The "next release" branch, likely unstable.
@@ -283,46 +222,46 @@ Git branch structure
Released versions.
Each release is tagged and available for download on the Downloads_ section of the **Mayan EDMS** repository on GitHub_.
Each release is tagged separately.
When submitting patches, please place your code in its own ``feature/`` branch prior to opening a pull request on GitHub_.
When submitting patches, please place your code in its own ``feature/`` branch
prior to opening a Merge Request on GitLab_.
.. _Git: http://git-scm.org
.. _`Successful Git Branching Model`: http://nvie.com/posts/a-successful-git-branching-model/
.. _git-flow: https://github.com/nvie/gitflow
.. _Downloads: https://github.com/mayan-edms/mayan-edms/archives/master
Steps to deploy a development version
-------------------------------------
.. code-block:: bash
$ git clone https://github.com/mayan-edms/mayan-edms.git
$ cd mayan-edms
$ git checkout development
$ virtualenv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
$ ./manage.py initialsetup
$ ./manage.py runserver
git clone https://gitlab.com/mayan-edms/mayan-edms.git
cd mayan-edms
git checkout development
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
./manage.py initialsetup
./manage.py runserver
Setting up a development version using Vagrant
----------------------------------------------
Make sure you have Vagrant and a provider properly installed as per https://docs.vagrantup.com/v2/installation/index.html
Make sure you have Vagrant and a provider properly installed as per
https://docs.vagrantup.com/v2/installation/index.html
Start and provision a machine using:
.. code-block:: bash
$ vagrant up
vagrant up
To launch a standalone development server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
$ vagrant ssh
vagrant ssh
vagrant@vagrant-ubuntu-trusty-32:~$ cd ~/mayan-edms/
vagrant@vagrant-ubuntu-trusty-32:~$ source venv/bin/activate
vagrant@vagrant-ubuntu-trusty-32:~$ ./manage.py runserver 0.0.0.0:8000
@@ -332,7 +271,7 @@ To launch a development server with a celery worker and Redis as broker
.. code-block:: bash
$ vagrant ssh
vagrant ssh
vagrant@vagrant-ubuntu-trusty-32:~$ cd ~/mayan-edms/
vagrant@vagrant-ubuntu-trusty-32:~$ source venv/bin/activate
vagrant@vagrant-ubuntu-trusty-32:~$ ./manage.py runserver 0.0.0.0:8000 --settings=mayan.settings.celery_redis
@@ -341,7 +280,7 @@ Then on a separate console launch a celery worker from the same provisioned Vagr
.. code-block:: bash
$ vagrant ssh
vagrant ssh
vagrant@vagrant-ubuntu-trusty-32:~$ cd ~/mayan-edms/
vagrant@vagrant-ubuntu-trusty-32:~$ source venv/bin/activate
vagrant@vagrant-ubuntu-trusty-32:~$ DJANGO_SETTINGS_MODULE='mayan.settings.celery_redis' celery -A mayan worker -l DEBUG -Q checkouts,mailing,uploads,converter,ocr,tools,indexing,metadata -Ofair -B
@@ -349,22 +288,22 @@ Then on a separate console launch a celery worker from the same provisioned Vagr
Contributing changes
--------------------
Once your have created and committed some new code or feature, submit a Pull Request.
Be sure to merge with mayan-edms/development before doing a pull request so that patches
apply as cleanly as possible. If there are no conflicts, Pull Requests can be merged
directly from Github otherwise a manual command line merge has to be done and
your patches might take longer to get merged.
For more information on how to create Pull Request read: https://help.github.com/articles/using-pull-requests
or the quick version: https://help.github.com/articles/creating-a-pull-request
Once your have created and committed some new code or feature, submit a Pull
Request. Be sure to merge with the development branch before doing a Pull
Request so that patches apply as cleanly as possible. If there are no conflicts,
Merge Requests can be merged directly from the website UI otherwise a manual
command line merge has to be done and your patches might take longer to get
merged.
Debugging
---------
**Mayan EDMS** makes extensive use of Django's new `logging capabilities`_.
To enable debug logging for the ``documents`` app for example add the following
lines to your ``settings_local.py`` file::
By default debug logging for all apps is turned on. If you wish to customize
how logging is managed turn off automatic logging by setting
`COMMON_AUTO_LOGGING` to ``False`` and add the following lines to your
``settings/local.py`` file::
LOGGING = {
'version': 1,
@@ -418,76 +357,69 @@ Likewise, to see the debug output of the ``tags`` app, just add the following in
Documentation
-------------
**Mayan EDMS**'s documentation is written in `reStructured Text`_ format.
The documentation is written in `reStructured Text`_ format, processed with
Sphinx_, and resides in the ``docs`` directory. In order to build it, you will
first need to install the documentation editing dependencies with::
The documentation lives in the ``docs`` directory. In order to build it, you will first need to install Sphinx_. ::
pip install -r requirements/documentation.txt
$ pip install sphinx
Then, to build an HTML version of the documentation, run the following command
from the **docs** directory::
make livehtml
Then, to build an HTML version of the documentation, simply run the following from the **docs** directory::
The generated documentation can be viewed by browsing to http://127.0.0.1:8000
or by browsing to the ``docs/_build/html`` directory.
$ make html
Your ``docs/_build/html`` directory will then contain an HTML version of the documentation, ready for publication on most web servers.
You can also generate the documentation in formats other than HTML.
You can also generate the documentation in formats other than HTML. Consult the
Sphinx_ documentation for more details.
.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html
.. _Sphinx: http://sphinx.pocoo.org
Translations
------------
Translations are handled online via the **Transifex** website: https://www.transifex.com/projects/p/mayan-edms/.
To create a translation team for a new language or contribute to an already
existing language translation, create a **Transifex** account and contact
the team coordinator of the respective language in which you are interested.
Installable package
-------------------
Source file package
~~~~~~~~~~~~~~~~~~~
This is the sequence of step I use to produce an installable package:
This is the sequence of step used to produce an installable package:
1. Make sure there are no lingering packages from previous attempts::
$ rm dist -R
rm dist -R
2. Generate the packaged version (will produce dist/mayan-edms-1.1.1.tar.gz)::
2. Generate the packaged version (will produce dist/mayan-edms-x.y.z.tar.gz)::
$ python setup.py sdist
python setup.py sdist
3. Do a test install::
$ cd /tmp
$ virtualenv venv
$ source venv/bin/activate
$ pip install <path of the Git repository>/dist/mayan-edms-1.1.1.tar.gz
$ mayan-edms.py initialsetup
$ mayan-edms.py runserver
cd /tmp
virtualenv venv
source venv/bin/activate
pip install <path of the Git repository>/dist/mayan-edms-x.y.z.tar.gz
mayan-edms.py initialsetup
mayan-edms.py runserver
Wheel package
~~~~~~~~~~~~~
1. Install wheel::
1. Install the development requirements::
$ pip install wheel
$ pip install -r requirements/development.txt
2. Create wheel package using the source file package (Until issue #99 of wheel is fixed: https://bitbucket.org/pypa/wheel/issue/99/cannot-exclude-directory)::
$ pip wheel --no-index --no-deps --wheel-dir dist dist/mayan-edms-1.1.1.tar.gz
$ pip wheel --no-index --no-deps --wheel-dir dist dist/mayan-edms-x.y.z.tar.gz
3. Do a test install::
$ cd /tmp
$ virtualenv venv
$ source venv/bin/activate
$ pip install <path of the Git repository>/dist/mayan_edms-1.1.1-py2-none-any.whl
$ pip install <path of the Git repository>/dist/mayan_edms-x.y.z-py2-none-any.whl
$ mayan-edms.py initialsetup
$ mayan-edms.py runserver

View File

@@ -0,0 +1,17 @@
==============
Document types
==============
The basic unit of data in **Mayan EDMS** is the ``document type``. A document
type can be interpreted also as a document category, a document class, or a
document template. Document types need to be created before documents can be
uploaded. It is not possible to upload documents without assigning them a
document type. Examples of document type: **invoices**, **blueprints**,
**receipts**.
Settings and attributes are applied to document types and documents will
inherit those settings and attributes based on the document type they were
assigned when uploaded into **Mayan EDMS**. A document can only be of one
type at a given moment, but if needed, the type of a document can be changed.
Upon changing its type, the document will lose its previous settings and
attributes, and will inherit the settings and attributes of its new type.

View File

@@ -4,7 +4,8 @@ Features
* :doc:`Document versioning <../topics/versioning>`.
* Store many versions of the same document, download or revert to a previous version.
* Store many versions of the same document, download or revert to a previous
version.
* :doc:`Electronic signature verification <../topics/signatures>`.
@@ -18,39 +19,48 @@ Features
* Office document format support.
* **Mayan EDMS** can detect the presence of Libre Office and use it to support word processing files, spreadsheets and presentations.
* **Mayan EDMS** can detect the presence of Libre Office and use it to support
word processing files, spreadsheets and presentations.
* User defined metadata fields.
* Several metadata fields can be matched to a document type as per technical, legal or structural requirements such as the `Dublin core`_.
* Several metadata fields can be matched to a document type as per technical,
legal or structural requirements such as the `Dublin core`_.
* Dynamic default values for metadata.
* Metadata fields can have an initial value, which can be static or determined by an user provided Python code snippet.
* Metadata fields can have an initial value, which can be static or determined
by an user provided template code snippet.
* Documents can be uploaded from different sources.
* Local file or server side file uploads, multifunctional copier, or even via email.
* Local file or server side file uploads, multifunctional copier, or even via
email.
* Batch upload many documents with the same metadata.
* Clone a document's metadata for speedier uploads and eliminate repetitive data entry.
* Clone a document's metadata for speedier uploads and eliminate repetitive
data entry.
* Previews for a great deal of image formats.
* Previews for many file formats.
* **Mayan EDMS** provides different file conversion backends with different levels of functionality and requirements to adapt to different deployment environments.
* **Mayan EDMS** provides image preview generation for many popular file
formats.
* Full text searching.
* Documents can be searched by their text content, their metadata or any other file attribute such as name, extension, etc.
* Documents can be searched by their text content, their metadata or any other
file attribute such as name, extension, etc.
* Configurable document grouping.
* Automatic linking of documents based on metadata values or document properties.
* Automatic linking of documents based on metadata values or document
properties.
* :doc:`Roles support <../topics/permissions>`.
* It is possible to create an unlimited amount of different roles not being restricted to the traditional admin, operator, guest paradigm.
* It is possible to create an unlimited amount of different roles not being
restricted to the traditional admin, operator, guest paradigm.
* :doc:`Fine grained permissions system <../topics/permissions>`.
@@ -62,20 +72,25 @@ Features
* Automatic OCR processing.
* The task of transcribing text from documents via OCR can be distributed among several physical or virtual computers to decrease load and increase availability.
* The task of transcribing text from documents via OCR can be distributed
among several physical or virtual computers to decrease load and increase
availability.
* Multilingual user interface.
* **Mayan EDMS** being written using the Django_ framework, can be translated to practically any language spoken in the world.
For a list of translated languages have a look at Transifex_.
* **Mayan EDMS** being written using the Django_ framework, can be translated
to practically any language spoken in the world. For a list of translated
languages have a look at the Transifex_ project location.
* Multilingual OCR support.
* Current language of the document is passed to the corresponding OCR engine to increase the rate of data vs. recognition errors.
* The current language of the document is passed to the corresponding OCR
engine to increase the text recognition rate.
* :doc:`Plugable storage backends <../topics/file_storage>`.
* Very easy to use 3rd party plugins such as the ones available for Amazon EC2.
* It is very easy to use 3rd party plugins such as the ones available for
Amazon EC2.
* Color coded tagging.
@@ -83,7 +98,8 @@ Features
* Workflows.
* Keep track of the state a document, along with the log of the previous state changes.
* Keep track of the state of documents, along with the log of the previous
state changes.
.. _`Dublin core`: http://dublincore.org/metadata-basics/

View File

@@ -3,15 +3,26 @@ File storage
============
The files are stored and placed under **Mayan EDMS** "control" to avoid
filename clashes (each file gets renamed to its UUID and without extension)
and stored in a simple flat arrangement in a directory. This doesn't
stop access to the files but it is not recommended because moving,
renaming or updating the files directly would throw the database out
filename clashes each file gets renamed to its ``UUID`` (Universally Unique ID),
without extension, and stored in a simple flat arrangement in a directory.
.. blockdiag::
blockdiag {
file [ label = 'mayan_1-1.pdf', width=120];
document [ label = 'mayan/media/document_storage/ab6c1cfe-8a8f-4a30-96c9-f54f606b9248', width=450];
file -> document [label = "upload"];
file -> document;
}
This doesn't stop access to the files but renaming, moving or updating
directly them is not recommended because it would throw the database out
of sync.
**Mayan EDMS** components are as decoupled from each other as possible,
storage in this case is very decoupled and its behavior is controlled
not by the project but by the Storage progamming class. Why this design?
All the other parts don't make any assumptions about the actual file
storage, files can be saved locally, over the network or even across the
internet and everything will still operate exactly the same.
Because **Mayan EDMS** components are as decoupled from each other as possible,
storage in this case is decoupled and its behavior is controlled
not by the project but by the ``Storage`` module class. All the other
modules don't make any assumptions about how the actual document files are
stored. This way files can be saved locally, over the network or even across
the Internet and everything will still operate exactly the same.

View File

@@ -1,85 +0,0 @@
===============
Getting started
===============
Before starting to use **Mayan EDMS**, two things need to be configured:
- At least one document source
- At least one document type
Document sources
----------------
Document sources define from where documents will be uploaded or gathered.
To add a document source go to the ``Setup`` section, then to the ``Sources`` section.
To obtain the fastest working setup, create a new source of type ``Web form``.
``Web forms`` are just HTML forms with a ``Browse`` button that will open the file upload
dialog when clicked. Name it something simple like ``Local documents`` and select whether or not
compressed files uploaded from this source will be automatically decompressed and
their content treated as individual documents.
Document types
--------------
Examples of document types are: ``Legal documents``, ``Internal documents``, ``Medical records``, ``Designing specifications``, ``Permits``.
A document type represent a class of documents which share some common property.
A good indicator that can help you determine your document types is what kind of
information or ``metadata`` is attached to those documents.
Once a document source and a document type have been created you have all the minimal
elements required to start uploading documents.
Defining metadata
-----------------
With your document types defined it should be much easier now to define the required
``metadata`` for each of these document types. When creating ``metadata`` types,
the first thing that will be needed is the internal name with which this metadata
type will be referenced in other areas of **Mayan EDMS**. The internal name must not
contain spaces or uppercase characters. After the internal name, enter the name that
will be visible to you and your users, which usually will be similar or the same as the
internal name, but with proper capitalization and spacing. The ``metadata types``
can have default values to speed up data entry. They can be single number or a
words enclosed in quotes, ie::
"Building A"
or::
"Storage room 1"
Default values can also be defined as ``Python`` statements or functions such as::
current_date()
If you want to restrict or standardize the values for a metadata type, use the ``Lookup`` field to
define the list of options that are allowed. Define the lookup list using a ``Python``
list of quoted values, for example::
["2000", "2001", "2002", "2003", "2004"].
Instead of a free entry text field, your users will get a dropdown list of years,
this will ensure an unified data entry formatting. You can also use a
``Python`` expression to generate the lookup list.
Metadata types can be assigned in two ways to a document type, by making it an
optional or a required metadata type for a specific document. This method
allows metadata very important for some types of documents (like Invoice
numbers to Invoices) to be required for an Invoice to be able to be uploaded.
Accordingly optional metadata types will be presented, but users are not required to
enter a value to be able to upload a document.
Indexes
-------
After defining all your metadata types you can also define indexes to
let **Mayan EDMS** automatically categorize your documents based on their metadata values.
To create an index to organize invoices by a year metadata field do the following:
- Create a year metadata type with the name ``year`` and the label ``Year``.
- Create an invoice document type and assign it the ``year`` metadata type as a required metadata type.
- Create a new index, give it the name ``invoices_per_year`` and the label ``Invoices per year``.
- Edit the index's ``Tree template``, add a ``New child node``, and enter ``document.metadata_value_of.year`` as the ``Indexing expression``, check the ``Link documents`` checkbox and save.
- Link this new index to the invoice document type using the ``Document types`` button of the index.
Now every time a new invoice upload or an existing invoice's ``year`` metadata value is changed, a new folder will be created in the ``Invoices`` index with the corresponding invoices for that year.

View File

@@ -1,16 +1,22 @@
Concepts
========
Introductions to all the key parts of Mayan EDMS you'll need to know:
Introductions to all the key parts of **Mayan EDMS** you'll need to know:
.. toctree::
:maxdepth: 1
file_storage
document_types
metadata
permissions
sources
acls
transformations
checkouts
versioning
signatures
indexes
smart_links
tags
file_storage
screenshots

View File

@@ -2,21 +2,92 @@
Indexes
=======
Indexes are an automatic method to hierarchically organize documents in relation to their properties.
Indexes are an automatic method to hierarchically organize documents in
relation to their properties (:doc:`metadata`, label, MIME type, etc). To use
indexes you need to first create an index template. Once created, associate
the index to one or more :doc:`document_types`.
Index templates
===============
Index are hierarchical models so a tree template needs to be specified for them.
This tree template will contain references to document metadata or properties
that will be replaced with the actual value for those metadata or properties.
Since multiple indexes can be defined, the first step is to create an empty index.
Administrators then define the tree template showing how the index will be structured.
Each branch can be a pseudo folder, which can hold other child 'folders' or
a document container which will have all the links to the documents that
matched the criteria of the document container.
Example:
Index instances
===============
- Document type: ``Product sheet``
- Metadata type: ``Product year``, associated as a required metadata for the document type ``Product sheet``.
The template is the skeleton from which an instance of the index is then
auto-populated with links to the documents depending on the rules of each
branch of the index evaluated against the metadata and properties of the documents.
- Index: ``Product sheets per year``, and associated to the document type ``Product sheet``.
- Index slug: ``product-sheets-per-year``. Slugs are internal unique identifiers that can be used by other **Mayan EDMS** modules to reference each index.
- Index tree template as follows:
.. blockdiag::
blockdiag {
index [ label = 'Product sheets per year', width=180 ];
root [ label = 'Root (Has document links? No)', width=450];
level_2 [ label = '{{ document.metadata_value_of.product_year }} (Has document links? Yes)', width=450];
group {
label = "Tree template";
color = "#dddddd";
style = dashed;
root; level_2;
}
index -> root
root -> level_2 [folded];
}
Now every time a new ``Product sheet`` is uploaded a hierarchical unit with the value
of the metadata type ``Product year`` is created and a link to the uploaded ``Product sheet`` added to it.
Example:
Suppose three ``Product sheets`` are uploaded with the following values as their
``Product year`` metadata: 2001, 2002, 2001 respectively. The result index
that will be generate based on the tree template would be as follows:
.. blockdiag::
blockdiag {
index [ label = 'Product sheets per year', width=180 ];
year_1 [ label = '2001', width = 60 ];
year_2 [ label = '2002', width = 60 ];
document_1 [ label = 'Product A data sheet (2001)', width = 200 ];
document_2 [ label = 'Product B data sheet (2002)', width = 200 ];
document_3 [ label = 'Product C data sheet (2001)', width = 200 ];
group {
label = "Index content";
color = "#dddddd";
style = dashed;
year_1, year_2, document_1, document_2, document_3;
}
index -> year_1;
index -> year_2;
year_1 -> document_1;
year_2 -> document_2;
year_1 -> document_3;
}
Mirroring
=========
Indexes can be exported as `FUSE <https://en.wikipedia.org/wiki/Filesystem_in_Userspace>`_
filesystems. Using the management command ``mountindex`` we could export the
previous example index as follows::
mkdir -p ~/indexes/products
mayan-edms.py mountindex product-sheets-per-year ~/indexes/products
The ``~/indexes/products`` directory will now have a directory and files structure
identical to that of the index. Once indexes are mounted with this command, they
behave like any other filesystem directory and can even be further shared
via the network with network file system software like
`Samba <https://www.samba.org/>`_ or
`NFS <https://en.wikipedia.org/wiki/Network_File_System>`_.
Indexes and mirrored indexes are Read Only as they are generated as a result of
prior activities like document uploads, metadata changes.

View File

@@ -2,45 +2,33 @@
Installation
============
**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_.
Being a Django_ and a Python_ project familiarity with these technologies is
required to understand why **Mayan EDMS** does some of the things it does the way
it does them.
Being a Django_ and a Python_ project, familiarity with these technologies is
recommended to better understand why **Mayan EDMS** does some of the things it
does.
Before installing **Mayan EDMS**, the binary requirements must be installed first.
Bellow are the step needed for a test install.
Binary dependencies
===================
Ubuntu
------
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, get the executable
requirements using::
$ sudo apt-get install libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv tesseract-ocr unpaper poppler-utils -y
sudo apt-get install libjpeg-dev libmagic1 libpng-dev libreoffice libtiff-dev gcc ghostscript gpgv python-dev python-virtualenv tesseract-ocr unpaper poppler-utils -y
Initialize a ``virtualenv`` to deploy the project:
.. code-block:: bash
$ virtualenv venv
$ source venv/bin/activate
$ pip install mayan-edms
By default **Mayan EDMS** will create a single file SQLite_ database, which makes
it very easy to start using **Mayan EDMS**. Populate the database with the project's schema doing:
.. code-block:: bash
$ mayan-edms.py initialsetup
$ mayan-edms.py runserver
Point your browser to http://127.0.0.1:8000. If everything was installed
correctly you should see the login screen and panel showing a randomly generated admin password.
Mac OSX
-------
**Mayan EDMS** is dependant on a number of binary packages and the recommended way is
to use a package manager such as `MacPorts <https://www.macports.org/>`_ or `Homebrew <http://brew.sh/>`.
**Mayan EDMS** is dependent on a number of binary packages and the recommended
way is to use a package manager such as `MacPorts <https://www.macports.org/>`_
or `Homebrew <http://brew.sh/>`_.
Use MacPorts to install binary dependencies
@@ -50,14 +38,9 @@ With MacPorts installed run the command:
.. code-block:: bash
sudo port install python-dev gcc tesseract-ocr unpaper python-virtualenv ghostscript libjpeg-dev libpng-dev poppler-utils
**Mayan EDMS** can use either Pillow, ImageMagick or GraphicsMagick as the backend to
convert images so in addition you can install GraphicsMagick ...
.. code-block:: bash
sudo port install graphicsmagick
sudo port install python-dev gcc tesseract-ocr unpaper \
python-virtualenv ghostscript libjpeg-dev libpng-dev \
poppler-utils
Set the Binary paths
********************
@@ -68,19 +51,12 @@ to /usr/bin/ with ...
.. code-block:: bash
sudo ln -s /opt/local/bin/tesseract /usr/bin/tesseract && \
sudo ln -s /opt/local/bin/identify /usr/bin/identify && \
sudo ln -s /opt/local/bin/gs /usr/bin/gs
sudo ln -s /opt/local/bin/tesseract /usr/bin/tesseract
... alternatively set the paths in the ``settings/locals.py``
.. code-block:: python
# document converters
CONVERTER_IM_CONVERT_PATH = '/opt/local/bin/convert'
IM_IDENTIFY_PATH = '/opt/local/bin/identify'
GRAPHICS_BACKEND = 'converter.backends.graphicsmagick.GraphicsMagick'
GM_PATH = '/opt/local/bin/gm'
LIBREOFFICE_PATH = '/Applications/LibreOffice.app/Contents/MacOS/soffice'
Or Use Homebrew
@@ -90,7 +66,7 @@ With Homebrew installed run the command:
.. code-block:: bash
brew install python gcc tesseract unpaper poppler libpng graphicsmagick postgresql
brew install python gcc tesseract unpaper poppler libpng postgresql
Set the Binary paths
********************
@@ -102,57 +78,52 @@ to /usr/bin/ with ...
.. code-block:: bash
sudo ln -s /usr/local/bin/tesseract /usr/bin/tesseract && \
sudo ln -s /usr/local/bin/identify /usr/bin/identify && \
sudo ln -s /usr/local/bin/unpaper /usr/bin/unpaper && \
sudo ln -s /usr/local/bin/pdftotext /usr/bin/pdftotext && \
sudo ln -s /usr/local/bin/gs /usr/bin/gs && \
sudo ln -s /usr/local/bin/gs /usr/bin/gs
... alternatively set the paths in the ``settings/locals.py``
.. code-block:: python
# document converters
CONVERTER_IM_CONVERT_PATH = '/usr/local/bin/convert'
IM_IDENTIFY_PATH = '/usr/local/bin/identify'
GRAPHICS_BACKEND = 'converter.backends.graphicsmagick.GraphicsMagick'
GM_PATH = '/usr/local/bin/gm'
LIBREOFFICE_PATH = '/Applications/LibreOffice.app/Contents/MacOS/soffice'
Testing the install
-------------------
Actual project installation
===========================
To create a custom settings file for **Mayan EDMS**, create a Python (.py) file
in the directory: venv/lib/python2.7/site-packages/mayan/settings/ with the following basic content::
Initialize a ``virtualenv`` to deploy the project:
# venv/lib/python2.7/site-packages/mayan/settings/my_settings.py
.. code-block:: bash
from __future__ import unicode_literals
virtualenv venv
source venv/bin/activate
pip install mayan-edms
from .local import *
By default **Mayan EDMS** will create a single file SQLite_ database, which makes
it very easy to start using **Mayan EDMS**. Populate the database with the
project's schema doing:
<Your customized settings>
.. code-block:: bash
To test your settings launch **Mayan EDMS** using::
mayan-edms.py initialsetup
mayan-edms.py runserver
$ mayan-edms.py runserver --settings=mayan.settings.my_settings
Point your browser to http://127.0.0.1:8000. If everything was installed
correctly you should see the login screen and panel showing a randomly generated
admin password.
Note: Background tasks and scheduled tasks will not run when using the test server.
Production use
--------------
==============
After making sure everything is running correctly, stop the `runserver` command.
Deploy **Mayan EDMS** using the webserver of your preference. For more information
on deployment instructions and examples, checkout Django's official documentation
on the topic https://docs.djangoproject.com/en/1.6/howto/deployment/
Other database managers
-----------------------
If you want to use a database manager other than SQLite_ install any
corresponding python database drivers and add the corresponding database settings
to your settings file (see above) as shown here: https://docs.djangoproject.com/en/1.6/ref/settings/#std:setting-DATABASES
on the topic https://docs.djangoproject.com/en/1.7/howto/deployment/
For a simple production deployment setup follow the instructions in the
:doc:`deploying` chapter.
.. _Debian: http://www.debian.org/

28
docs/topics/metadata.rst Normal file
View File

@@ -0,0 +1,28 @@
========
Metadata
========
Metadata is the name of the attribute of a document. The concept of metadata is
divided in two: **metadata types** (size, color, distance) and **metadata values** for
those types. Metadata types are defined in the setup menu and associated with
document types. Then when a document is uploaded, a value for that metadata
can be entered. There are two kinds of metadata type to document type relations:
optional and required. When a metadata type is optional for a document type,
it can be left blank for a document being uploaded and the upload will still
be successful. On the other hand required metadata type must be given a value
or it will not be possible to upload the document at hand.
Examples of metadata type: Invoice number, color, employee id.
The data entry of metadata types can be set to allow any value to be provided
(the default) or a list of possible values can be entered in the ``Lookup``
configuration option and users will be presented with a drop down list of options
instead of the default text entry box.
If metadata types are setup to allow any value to be entered a ``validation``
option can be chosen to block the entry of invalid data. Metadata types also
provide ``parsers`` which will not block the entry of data but are able to
interpret and modify the value provided by the user to a conform to a specific
format. An example of a provided parser is the date parser which will interpret
and correct dates provided by users regardless of the format in which they are
entered.

View File

@@ -2,46 +2,24 @@
Permissions
===========
**Mayan EDMS** provides finegrained control over which activities users can
perform. This control is divided into two levels of operation:
**Mayan EDMS** provides very fine control over which actions users can
perform. Action control works by allowing ``roles``, that are composed of
``groups`` of ``users`` to be granted a ``permission`` such that the holder of
that permission can exercise it throughout the entire system.
2 tier permissions assignement
==============================
.. blockdiag::
This level of activity control works by allowing roles that are composed
of users or groups, to be granted a permission such that the holder of that
permission can exercise it throughout the entire collection of objects
(document, folders, tags, etc). This method could be thought out as a global
permission.
blockdiag {
user [ label = 'Users' ];
group [ label = 'Groups' ];
role [ label = 'Roles' ];
permission [ label = 'Permissions' ];
3 tier access control
=====================
When more control is desired over which objects actors
(user, groups and roles) can exercise an action, this method should be
used. Under this method, actors are granted a permission but only in relation
to a selected object. Example: Granting user
``Joe`` the ``Document view`` access control for document ``Payroll``, would
allow him to view this document only.
user -> group -> role <- permission;
}
The permission system enforces inheritance by first checking, if the user
has a global permission, is a member of a group or a role that has a global
permission and if not, then checks to see if that user, a group or role to
which he belongs, has been granted access to the specific object to which
he is desiring to perform a given action.
Only when these checks fail the user is forbidden to perform the action and
a generic message is displayed to avoid providing any information
that could be used to sidetrack the permission system or obtain any kind of
information about the object to which the user was not allowed access.
Default Access Control Lists (Default ACLs)
-------------------------------------------
Default Access Control Lists allow assigment of an access control list to a
type of object (Document, Tags, Folders) before it is created. It is the default
permissions an object will have when it is created. With Default Access Control Lists
specific permissions can be granted to the creator of a document for example.
Changes to the Default Access Control Lists (Default ACLs) only affect objects
created after the change, they will not affect documents previously uploaded.
In other words, users themselves can't hold a permission, permissions are
granted only to roles. Users can't directly belong to a role, they can only
belong to a group. Groups can be members of roles. Roles are system permission
units and groups are business organizational units.

View File

@@ -0,0 +1,64 @@
===========
Screenshots
===========
.. figure:: /_static/main.png
:figwidth: 40%
:scale: 30 %
:alt: Home screen
:align: left
Home screen
.. figure:: /_static/page_view.png
:figwidth: 40%
:scale: 30 %
:alt: Page view
:align: right
Page view
.. figure:: /_static/document_view.png
:figwidth: 40%
:scale: 30 %
:alt: Document view
:align: left
Document view
.. figure:: /_static/api.png
:figwidth: 40%
:scale: 30 %
:alt: REST API
:align: right
REST API
.. figure:: /_static/tools.png
:figwidth: 40%
:scale: 30 %
:alt: Tools
:align: left
Tools
.. figure:: /_static/setup.png
:figwidth: 40%
:scale: 30 %
:alt: Setup
:align: right
Setup
.. figure:: /_static/statistics.png
:figwidth: 40%
:scale: 30 %
:alt: Statistics
:align: left
Statistics

View File

@@ -2,13 +2,31 @@
Smart links
===========
Smart links are a way to link documents without changing how they are organized
in their respective indexes. Smart links are useful when two documents are
related somehow but are of different type or different hierarchical units.
Smart links are usefull for navigation between documents. They are rule
based, but don't create any organizational structure. They just show the documents
that match the rules as evaluated against the metadata of the currently
displayed document.
Example: A patient record can be related to a prescription drug information
document, but they each belong to their own :doc:`indexes`.
Smart links are usefull when a patient file in a patients index needs to be linked
to the medical documentation of a prescription the patient is using, but that medical
documentation is in it's own prescription index. Smart links can provide a reference
between documents of different indexes without any change in the indexes' structures.
Smart links are rule based, but don't create any organizational structure.
Smart links just show the documents that match the rules as evaluated against
the metadata or properties of the currently displayed document.
Indexes are automatic hierarchical units used to group documents, smart links
are automatic references between documents.
Example:
- Document type: ``Patient records``
- Metadata type: ``Prescription``, associated as an optional metadata for the document type ``Patient records``.
- Document type: ``Prescription information sheets``
A smart link with the following condition, will automatically links patient
records to the prescription information sheets based on the value of the
metadata type of the patient record.
.. code-block:: bash
foreign label is equal to {{ document.metadata_value_of.prescription }}

27
docs/topics/sources.rst Normal file
View File

@@ -0,0 +1,27 @@
=======
Sources
=======
Document sources define places from which documents can be uploaded or gathered.
The current document sources supported are:
- Web - ``HTML`` forms with a ``Browse`` button that will open the file dialog
when clicked to allow selection of files in the user's computer to be
uploaded as documents.
- Staging folder - Folder where networked attached scanned can save image
files. The files in these staging folders are scanned and a preview is
generated to help the process of upload.
- POP3 email - Provide the email, server and credential of a ``POP3`` based
email to be scanned periodically for email. The body of the email is uploaded
as a document and the attachments of the email are uploaded as separate
documents.
- IMAP email - Same as the ``POP3`` email source but for email accounts using
the ``IMAP`` protocol.
- Watch folder - A filesystem folder that is scanned periodically for files.
Any file in the watch folder is automatically uploaded.
Document source can be configure to allow document bundles to uploaded as
compressed files which are decompressed and their content uploaded as separate
documents. This feature is useful when migrating from another document
manager system.

View File

@@ -2,8 +2,8 @@
Tags
====
Tags allow giving documents a toggable property. Documents can also be tagged
with more than one tag. Once tagged, documents can be searched also by their tags
and from the tags main menu a list of all the documents with a particular tag
can be obtained easily. Aside from their texts, tags can be assigned a particular
color.
Tags allow giving documents a binary property. Documents can also be tagged
with more than one tag. Once tagged, documents can be searched also by their
tags and from the tags main menu a list of all the documents with a particular
tag can be obtained easily. Aside from their texts, tags can be assigned a
particular color.

View File

@@ -1,12 +1,11 @@
=========================
What are transformations?
=========================
===============
Transformations
===============
Transformation are useful to manipulate the preview of the stored documents
in a persistent manner, for example some scanning equipment only produce
landscape PDFs, in this case a default transformation for that document
source would be "rotation: 270 degress". This way whenever a document is
uploaded from that scanner it appears in portrait orientation.
The transformation remains attached to the document, the file being
preserved in it's original state (a requirement in legal environments) and
only the representation being transformed.
Transformation are persistent manipulations to the previews of the stored
documents. For example: a scanning equipment may only produce landscape PDFs.
In this case an useful transformation for that document source would be to
rotate all documents scanned by 270 degrees after being uploaded, this way
whenever a document is uploaded from that scanner it will appear in portrait
orientation. Transformations do not physically modify the document file but
are just associated with the document's temporary graphical representation.

View File

@@ -0,0 +1,17 @@
============
Translations
============
Translations are handled online via the **Transifex** website:
https://www.transifex.com/projects/p/mayan-edms/. To create a translation team
for a new language or contribute to an already existing language translation,
create a **Transifex** account and contact the team coordinator of the
respective language in which you are interested.
Feel free to open translation issues inside **Transifex** itself if you have a
question about the usage or meaning of a source text string. If you open a
translation issue, it will be your responsibility to close it after you get an
answers that satisfies your question. Administrator will not close new issues
as they have no way to determine if your question has been properly answered.
However to avoid clutter, answered questions will be scanned periodically and
closed if no activity is observed from the original poster in a period of time.

View File

@@ -5,10 +5,8 @@ Document versioning
**Mayan EDMS** has the ability to store different versions of the same
document. A comment field is provided to allow users to summarize the new
version changes in comparison with the previous one. If a new version was
uploded by mistake or such new version is no longer necessary the option to
uploaded by mistake or such new version is no longer necessary the option to
revert to a previous version of the document is provided.
To upload a new document version, select an existing document, click on the
version tab of the document, and click on the 'upload new version' on the
side bar. A new view very similar to the new document upload view will
appear, showing the same interactive document sources that have been defined.
Only the interactive document sources (:doc:`sources`) (``Web`` and ``Staging folders``) are
available to upload new document versions.

3
environment Normal file
View File

@@ -0,0 +1,3 @@
POSTGRES_DB=mayan
POSTGRES_PASSWORD=mayanpassword
POSTGRES_USER=mayan

View File

@@ -8,4 +8,3 @@ if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

13
mayan/LICENSE Normal file
View File

@@ -0,0 +1,13 @@
Copyright 2011-2015 Roberto Rosario
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,8 +1,10 @@
from __future__ import unicode_literals
__title__ = 'Mayan EDMS'
__version__ = '1.1.1'
__build__ = 0x010101
__version__ = '2.0.0'
__build__ = 0x020000
__author__ = 'Roberto Rosario'
__author_email__ = 'roberto.rosario@mayan-edms.com'
__description__ = 'Free Open Source Electronic Document Management System'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2011-2015 Roberto Rosario'

View File

@@ -1,33 +1,5 @@
from __future__ import unicode_literals
from django.dispatch import receiver
from .classes import ModelPermission # NOQA
from south.signals import post_migrate
from navigation.api import register_links
from project_setup.api import register_setup
from .classes import (
AccessHolder, AccessObject, AccessObjectClass, ClassAccessHolder
)
from .links import (
acl_class_acl_detail, acl_class_acl_list, acl_class_grant, acl_class_list,
acl_class_new_holder_for, acl_class_revoke, acl_detail, acl_grant,
acl_holder_new, acl_revoke, acl_setup_valid_classes
)
from .models import CreatorSingleton
register_links([AccessObject], [acl_holder_new], menu_name='sidebar')
register_links(AccessObjectClass, [acl_class_acl_list, acl_class_new_holder_for])
register_links(AccessHolder, [acl_detail])
register_links(['acls:acl_setup_valid_classes', 'acls:acl_class_acl_list', 'acls:acl_class_new_holder_for', 'acls:acl_class_acl_detail', 'acls:acl_class_multiple_grant', 'acls:acl_class_multiple_revoke'], [acl_class_list], menu_name='secondary_menu')
register_links(ClassAccessHolder, [acl_class_acl_detail])
register_links(['acls:acl_detail'], [acl_grant, acl_revoke], menu_name='multi_item_links')
register_links(['acls:acl_class_acl_detail'], [acl_class_grant, acl_class_revoke], menu_name='multi_item_links')
register_setup(acl_setup_valid_classes)
@receiver(post_migrate, dispatch_uid='create_creator_user')
def create_creator_user(sender, **kwargs):
if kwargs['app'] == 'acls':
CreatorSingleton.objects.get_or_create()
default_app_config = 'acls.apps.ACLsApp'

View File

@@ -2,15 +2,15 @@ from __future__ import unicode_literals
from django.contrib import admin
from .models import AccessEntry
from .models import AccessControlList
class AccessEntryAdmin(admin.ModelAdmin):
model = AccessEntry
list_display = ('pk', 'holder_object', 'permission', 'content_object')
@admin.register(AccessControlList)
class AccessControlListAdmin(admin.ModelAdmin):
filter_horizontal = ('permissions',)
list_display = ('pk', 'role', 'content_type', 'content_object')
list_display_links = ('pk',)
list_filter = ('content_type',)
related_lookup_fields = {
'generic': [['holder_type', 'holder_id'], ['content_type', 'object_id']],
'generic': (('content_type', 'object_id'),),
}
admin.site.register(AccessEntry, AccessEntryAdmin)

View File

@@ -1,28 +0,0 @@
from __future__ import unicode_literals
from django.contrib.contenttypes.models import ContentType
_class_permissions = {}
def class_permissions(cls, permission_list):
"""
Associate a permissions list to a class
"""
stored_permissions = _class_permissions.setdefault(cls, [])
stored_permissions.extend(permission_list)
def get_class_permissions_for(obj):
"""
Return a list of permissions associated with a content type
"""
content_type = ContentType.objects.get_for_model(obj)
return _class_permissions.get(content_type.model_class(), [])
def get_classes():
"""
Return a list of encapsulated classes that have been registered
"""
return _class_permissions.keys()

34
mayan/apps/acls/apps.py Normal file
View File

@@ -0,0 +1,34 @@
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from common import MayanAppConfig, menu_object, menu_sidebar
from navigation import SourceColumn
from .links import link_acl_new, link_acl_delete, link_acl_permissions
from .models import AccessControlList
class ACLsApp(MayanAppConfig):
name = 'acls'
test = True
verbose_name = _('ACLs')
def ready(self):
super(ACLsApp, self).ready()
SourceColumn(
source=AccessControlList, label=_('Permissions'),
attribute='get_permission_titles'
)
SourceColumn(
source=AccessControlList, label=_('Role'), attribute='role'
)
menu_object.bind_links(
links=(link_acl_permissions, link_acl_delete),
sources=(AccessControlList,)
)
menu_sidebar.bind_links(
links=(link_acl_new,), sources=('acls:acl_list',)
)

View File

@@ -1,153 +1,44 @@
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
import logging
import sys
import types
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.base import ModelBase
from common.models import AnonymousUserSingleton
from permissions.models import StoredPermission
logger = logging.getLogger(__name__)
_cache = {}
def get_source_object(obj):
if isinstance(obj, EncapsulatedObject):
return obj.source_object
else:
return obj
class EncapsulatedObject(object):
source_object_name = 'source_object'
class ModelPermission(object):
_registry = {}
_proxies = {}
_inheritances = {}
@classmethod
def object_key(cls, app_label=None, model=None, pk=None):
if pk:
return '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk)
else:
return '%s.%s.%s' % (cls.__name__, app_label, model)
def register(cls, model, permissions):
cls._registry.setdefault(model, [])
for permission in permissions:
cls._registry[model].append(permission)
@classmethod
def add_to_class(cls, name, value):
if hasattr(value, 'contribute_to_class'):
value.contribute_to_class(cls, name)
else:
setattr(cls, name, value)
@classmethod
def set_source_object_name(cls, new_name):
cls.source_object_name = new_name
# @classmethod
# def encapsulate_list(cls, source_object=None, app_label=None, model=None, pk=None):
@classmethod
def encapsulate(cls, source_object):
source_object = AnonymousUserSingleton.objects.passthru_check(source_object)
content_type = ContentType.objects.get_for_model(source_object)
if hasattr(source_object, 'pk'):
# Object
object_key = cls.object_key(content_type.app_label, content_type.model, source_object.pk)
else:
# Class
object_key = cls.object_key(content_type.app_label, content_type.model)
def get_for_instance(cls, instance):
try:
return _cache[object_key]
except KeyError:
encapsulated_object = cls(source_object)
_cache[object_key] = encapsulated_object
return encapsulated_object
@classmethod
def get(cls, gid):
elements = gid.split('.')
if len(elements) == 3:
app_label, model, pk = elements[0], elements[1], elements[2]
elif len(elements) == 2:
app_label, model = elements[0], elements[1]
pk = None
object_key = cls.object_key(*elements)
try:
return _cache[object_key]
permissions = cls._registry[type(instance)]
except KeyError:
try:
content_type = ContentType.objects.get(app_label=app_label, model=model)
except ContentType.DoesNotExist:
raise ObjectDoesNotExist('%s matching query does not exist.' % ContentType._meta.object_name)
else:
source_object_model_class = content_type.model_class()
if pk:
try:
source_object = content_type.get_object_for_this_type(pk=pk)
except source_object_model_class.DoesNotExist:
raise ObjectDoesNotExist('%s matching query does not exist.' % source_object_model_class._meta.object_name)
else:
source_object = source_object_model_class
permissions = cls._registry[cls._proxies[type(instance)]]
except KeyError:
permissions = ()
return cls.encapsulate(source_object)
pks = [permission.stored_permission.pk for permission in permissions]
return StoredPermission.objects.filter(pk__in=pks)
def __init__(self, source_object):
self.content_type = ContentType.objects.get_for_model(source_object)
self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.model)
@classmethod
def register_proxy(cls, source, model):
cls._proxies[model] = source
if isinstance(source_object, ModelBase):
# Class
self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.model)
else:
# Object
self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.model, source_object.pk)
@classmethod
def register_inheritance(cls, model, related):
cls._inheritances[model] = related
setattr(self, self.__class__.source_object_name, source_object)
def __unicode__(self):
if isinstance(self.source_object, ModelBase):
return unicode(self.source_object._meta.verbose_name_plural)
elif self.ct_fullname == 'auth.user':
return '%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name())
elif self.ct_fullname == 'common.anonymoususersingleton':
return unicode(self.source_object)
elif self.ct_fullname == 'acls.creatorsingleton':
return unicode(self.source_object)
else:
return '%s %s' % (self.source_object._meta.verbose_name, self.source_object)
def __repr__(self):
return self.__unicode__()
@property
def source_object(self):
return getattr(self, self.__class__.source_object_name, None)
class AccessHolder(EncapsulatedObject):
source_object_name = 'holder_object'
class AccessObject(EncapsulatedObject):
source_object_name = 'obj'
class AccessObjectClass(EncapsulatedObject):
source_object_name = 'cls'
class ClassAccessHolder(EncapsulatedObject):
source_object_name = 'class_holder'
if sys.version_info < (2, 5):
# Prior to Python 2.5, Exception was an old-style class
def subclass_exception(name, parents, unused):
return types.ClassType(name, parents, {})
else:
def subclass_exception(name, parents, module):
return type(name, parents, {'__module__': module})
@classmethod
def get_inheritance(cls, model):
return cls._inheritances[model]

View File

@@ -1,62 +0,0 @@
from __future__ import absolute_import, unicode_literals
from django import forms
from django.contrib.auth.models import User, Group
from django.utils.translation import ugettext_lazy as _
from django.utils.functional import SimpleLazyObject
from common.models import AnonymousUserSingleton
from common.utils import get_object_name
from permissions.models import Role
from .classes import AccessHolder
from .models import CreatorSingleton
anonymous_singleton = SimpleLazyObject(lambda: AnonymousUserSingleton.objects.get())
creator_singleton = SimpleLazyObject(lambda: CreatorSingleton.objects.get())
def _as_choice_list(holders):
return sorted([(AccessHolder.encapsulate(holder).gid, get_object_name(holder, display_object_type=False)) for holder in holders], key=lambda x: x[1])
class BaseHolderSelectionForm(forms.Form):
holder_gid = forms.ChoiceField(
label=_('New holder')
)
def __init__(self, *args, **kwargs):
current_holders = kwargs.pop('current_holders', [])
if current_holders:
current_holders = [holder.source_object for holder in current_holders]
staff_users = User.objects.filter(is_staff=True)
super_users = User.objects.filter(is_superuser=True)
users = set(User.objects.filter(is_active=True)) - set(staff_users) - set(super_users) - set(current_holders)
roles = set(Role.objects.all()) - set(current_holders)
groups = set(Group.objects.all()) - set(current_holders)
special = set(self.special_holders) - set(current_holders)
non_holder_list = []
if users:
non_holder_list.append((_('Users'), _as_choice_list(list(users))))
if groups:
non_holder_list.append((_('Groups'), _as_choice_list(list(groups))))
if roles:
non_holder_list.append((_('Roles'), _as_choice_list(list(roles))))
if special:
non_holder_list.append((_('Special'), _as_choice_list(list(special))))
super(BaseHolderSelectionForm, self).__init__(*args, **kwargs)
self.fields['holder_gid'].choices = non_holder_list
class HolderSelectionForm(BaseHolderSelectionForm):
special_holders = [anonymous_singleton]
class ClassHolderSelectionForm(BaseHolderSelectionForm):
special_holders = [anonymous_singleton, creator_singleton]

View File

@@ -1,21 +1,40 @@
from __future__ import unicode_literals
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
from .permissions import (
ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL, ACLS_EDIT_ACL, ACLS_VIEW_ACL
from navigation import Link
from .permissions import permission_acl_view, permission_acl_edit
def get_kwargs_factory(variable_name):
def get_kwargs(context):
content_type = ContentType.objects.get_for_model(
context[variable_name]
)
return {
'app_label': '"{}"'.format(content_type.app_label),
'model': '"{}"'.format(content_type.model),
'object_id': '{}.pk'.format(variable_name)
}
return get_kwargs
link_acl_delete = Link(
permissions=(permission_acl_edit,), tags='dangerous', text=_('Delete'),
view='acls:acl_delete', args='resolved_object.pk'
)
link_acl_list = Link(
permissions=(permission_acl_view,), text=_('ACLs'), view='acls:acl_list',
kwargs=get_kwargs_factory('resolved_object')
)
link_acl_new = Link(
permissions=(permission_acl_edit,), text=_('New ACL'),
view='acls:acl_new', kwargs=get_kwargs_factory('resolved_object')
)
link_acl_permissions = Link(
permissions=(permission_acl_edit,), text=_('Permissions'),
view='acls:acl_permissions', args='resolved_object.pk'
)
acl_list = {'text': _('ACLs'), 'view': 'acls:acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]}
acl_detail = {'text': _('Details'), 'view': 'acls:acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'key_go', 'permissions': [ACLS_VIEW_ACL]}
acl_grant = {'text': _('Grant'), 'view': 'acls:acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]}
acl_revoke = {'text': _('Revoke'), 'view': 'acls:acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]}
acl_holder_new = {'text': _('New holder'), 'view': 'acls:acl_holder_new', 'args': 'access_object.gid', 'famfam': 'user', 'permissions': [ACLS_EDIT_ACL]}
acl_setup_valid_classes = {'text': _('Default ACLs'), 'view': 'acls:acl_setup_valid_classes', 'icon': 'main/icons/lock.png', 'permissions': [ACLS_CLASS_VIEW_ACL]}
acl_class_list = {'text': _('Classes'), 'view': 'acls:acl_setup_valid_classes', 'famfam': 'package', 'permissions': [ACLS_CLASS_VIEW_ACL]}
acl_class_acl_list = {'text': _('ACLs for class'), 'view': 'acls:acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock_go', 'permissions': [ACLS_CLASS_VIEW_ACL]}
acl_class_acl_detail = {'text': _('Details'), 'view': 'acls:acl_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'key_go', 'permissions': [ACLS_CLASS_VIEW_ACL]}
acl_class_new_holder_for = {'text': _('New holder'), 'view': 'acls:acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user', 'permissions': [ACLS_CLASS_EDIT_ACL]}
acl_class_grant = {'text': _('Grant'), 'view': 'acls:acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_CLASS_EDIT_ACL]}
acl_class_revoke = {'text': _('Revoke'), 'view': 'acls:acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_CLASS_EDIT_ACL]}

View File

@@ -1,14 +0,0 @@
from __future__ import unicode_literals
# Content type <-> fam fam icon mapping
CONTENT_TYPE_ICON_MAP = {
'auth.user': 'user',
'auth.group': 'group',
'documents.document': 'page',
'permissions.role': 'medal_gold_1',
'folders.folder': 'folder',
'tags.tag': 'tag_blue',
'linking.smartlink': 'page_link',
'common.anonymoususersingleton': 'user',
'acls.creatorsingleton': 'user',
}

View File

@@ -4,235 +4,217 @@
#
# Translators:
# Translators:
# Mohammed ALDOUB <voulnet@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-15 18:59-0400\n"
"PO-Revision-Date: 2014-10-25 06:47+0000\n"
"POT-Creation-Date: 2015-09-24 16:24-0400\n"
"PO-Revision-Date: 2015-09-24 05:15+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Arabic (http://www.transifex.com/projects/p/mayan-edms/language/ar/)\n"
"Language-Team: Arabic (http://www.transifex.com/rosarior/mayan-edms/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#: forms.py:25 links.py:13 links.py:19
msgid "New holder"
msgstr "New holder"
#: forms.py:42
msgid "Users"
msgstr "Users"
#: forms.py:45
msgid "Groups"
msgstr "Groups"
#: forms.py:48
msgid "Roles"
msgstr "Roles"
#: forms.py:51
msgid "Special"
msgstr "Special"
#: links.py:9
#: apps.py:14 links.py:30
msgid "ACLs"
msgstr "ACLs"
#: links.py:10 links.py:18
msgid "Details"
msgstr ""
#: links.py:11 links.py:20
msgid "Grant"
#: apps.py:20 links.py:38 models.py:36
msgid "Permissions"
msgstr ""
#: links.py:12 links.py:21
msgid "Revoke"
#: apps.py:24 models.py:38
#| msgid "Roles"
msgid "Role"
msgstr ""
#: links.py:15
msgid "Default ACLs"
msgstr "Default ACLs"
#: links.py:16 views.py:379
msgid "Classes"
#: links.py:26
msgid "Delete"
msgstr ""
#: links.py:17
msgid "ACLs for class"
msgstr "ACLs for class"
#: links.py:34
#| msgid "View ACLs"
msgid "New ACL"
msgstr ""
#: managers.py:118 managers.py:130
#: managers.py:72
msgid "Insufficient access."
msgstr "Insufficient access."
#: models.py:25 models.py:67
msgid "Permission"
msgstr ""
#: models.py:51
#: models.py:44
msgid "Access entry"
msgstr ""
#: models.py:52
#: models.py:45
msgid "Access entries"
msgstr ""
#: models.py:88
msgid "Default access entry"
#: models.py:60
msgid "None"
msgstr ""
#: models.py:89
msgid "Default access entries"
msgstr ""
#: models.py:108 models.py:111 models.py:112
msgid "Creator"
msgstr "Creator"
#: permissions.py:7 permissions.py:8
#: permissions.py:7
msgid "Access control lists"
msgstr "Access control lists"
msgstr ""
#: permissions.py:10
msgid "Edit ACLs"
msgstr "Edit ACLs"
#: permissions.py:11
msgid "View ACLs"
msgstr "View ACLs"
msgstr ""
#: permissions.py:13
msgid "Edit class default ACLs"
msgstr "Edit class default ACLs"
msgid "View ACLs"
msgstr ""
#: permissions.py:14
msgid "View class default ACLs"
msgstr "View class default ACLs"
#: views.py:48
#: views.py:61
#, python-format
msgid "Access control lists for: %s"
msgstr ""
#: views.py:50 views.py:402
msgid "Holder"
#: views.py:107
#, python-format
msgid "New access control lists for: %s"
msgstr ""
#: views.py:51 views.py:403
msgid "Permissions"
#: views.py:132
#, python-format
#| msgid "Default ACLs"
msgid "Delete ACL: %s"
msgstr ""
#: views.py:98
#, python-format
msgid "Permissions available to: %(actor)s for %(obj)s"
#: views.py:147
msgid "Available permissions"
msgstr ""
#: views.py:105 views.py:434
msgid "Namespace"
#: views.py:148
msgid "Granted permissions"
msgstr ""
#: views.py:106 views.py:435
msgid "Label"
#: views.py:187
msgid "Disabled permissions are inherited from a parent object."
msgstr ""
#: views.py:108 views.py:437
msgid "Has permission"
#: views.py:218
#, python-format
msgid "Role \"%(role)s\" permission's for \"%(object)s\""
msgstr ""
#: views.py:181 views.py:272 views.py:516 views.py:593
msgid ", "
msgstr ", "
#~ msgid "New holder"
#~ msgstr "New holder"
#: views.py:182 views.py:273 views.py:517 views.py:594
#, python-format
msgid " for %s"
msgstr " for %s"
#~ msgid "Users"
#~ msgstr "Users"
#: views.py:183 views.py:518
#, python-format
msgid " to %s"
msgstr " to %s"
#~ msgid "Groups"
#~ msgstr "Groups"
#: views.py:186 views.py:521
#, python-format
msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
msgstr "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgid "Special"
#~ msgstr "Special"
#: views.py:188 views.py:523
#, python-format
msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
msgstr "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgid "Details"
#~ msgstr "details"
#: views.py:195 views.py:530
#, python-format
msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
msgstr "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgid "Grant"
#~ msgstr "grant"
#: views.py:201 views.py:536
#, python-format
msgid ""
"%(actor)s, already had the permission \"%(permission)s\" granted for "
"%(object)s."
msgstr "%(actor)s, already had the permission \"%(permission)s\" granted for %(object)s."
#~ msgid "Revoke"
#~ msgstr "revoke"
#: views.py:274 views.py:595
#, python-format
msgid " from %s"
msgstr " from %s"
#~ msgid "Classes"
#~ msgstr "classes"
#: views.py:277 views.py:598
#, python-format
msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
msgstr "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgid "ACLs for class"
#~ msgstr "ACLs for class"
#: views.py:279 views.py:600
#, python-format
msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
msgstr "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgid "Permission"
#~ msgstr "permissions"
#: views.py:286 views.py:607
#, python-format
msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
msgstr "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgid "Default access entry"
#~ msgstr "default access entry"
#: views.py:292 views.py:613
#, python-format
msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
msgstr "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgid "Default access entries"
#~ msgstr "default access entries"
#: views.py:346
#, python-format
msgid "Add new holder for: %s"
msgstr ""
#~ msgid "Creator"
#~ msgstr "Creator"
#: views.py:347 views.py:477
msgid "Select"
msgstr "Select"
#~ msgid "Edit class default ACLs"
#~ msgstr "Edit class default ACLs"
#: views.py:381
msgid "Class"
msgstr ""
#~ msgid "View class default ACLs"
#~ msgstr "View class default ACLs"
#: views.py:400
#, python-format
msgid "Default access control lists for class: %s"
msgstr ""
#~ msgid "Holder"
#~ msgstr "holder"
#: views.py:428
#, python-format
msgid "Permissions available to: %(actor)s for class %(class)s"
msgstr ""
#~ msgid "Permissions available to: %(actor)s for %(obj)s"
#~ msgstr "permissions available to: %(actor)s for %(obj)s"
#: views.py:475
#, python-format
msgid "Add new holder for class: %s"
msgstr ""
#~ msgid "Namespace"
#~ msgstr "namespace"
#~ msgid "Label"
#~ msgstr "label"
#~ msgid ", "
#~ msgstr ", "
#~ msgid " for %s"
#~ msgstr " for %s"
#~ msgid " to %s"
#~ msgstr " to %s"
#~ msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgid ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgstr ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgid " from %s"
#~ msgstr " from %s"
#~ msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgstr "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgid "Add new holder for: %s"
#~ msgstr "add new holder for: %s"
#~ msgid "Select"
#~ msgstr "Select"
#~ msgid "Class"
#~ msgstr "class"
#~ msgid "Default access control lists for class: %s"
#~ msgstr "default access control lists for class: %s"
#~ msgid "Permissions available to: %(actor)s for class %(class)s"
#~ msgstr "permissions available to: %(actor)s for class %(class)s"
#~ msgid "Add new holder for class: %s"
#~ msgstr "add new holder for class: %s"
#~ msgid "List of classes"
#~ msgstr "List of classes"

View File

@@ -4,237 +4,217 @@
#
# Translators:
# Translators:
# Iliya Georgiev <ikgeorgiev@gmail.com>, 2012
# Pavlin Koldamov <pkoldamov@gmail.com>, 2012
# Pavlin Koldamov <pkoldamov@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-15 18:59-0400\n"
"PO-Revision-Date: 2014-10-25 06:47+0000\n"
"POT-Creation-Date: 2015-09-24 16:24-0400\n"
"PO-Revision-Date: 2015-09-24 05:15+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Bulgarian (http://www.transifex.com/projects/p/mayan-edms/language/bg/)\n"
"Language-Team: Bulgarian (http://www.transifex.com/rosarior/mayan-edms/language/bg/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bg\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:25 links.py:13 links.py:19
msgid "New holder"
msgstr "Нов притежател"
#: forms.py:42
msgid "Users"
msgstr "Потребители"
#: forms.py:45
msgid "Groups"
msgstr "Групи"
#: forms.py:48
msgid "Roles"
msgstr "Роли"
#: forms.py:51
msgid "Special"
msgstr ""
#: links.py:9
#: apps.py:14 links.py:30
msgid "ACLs"
msgstr "Контролни списъци за достъп"
#: links.py:10 links.py:18
msgid "Details"
msgstr ""
#: links.py:11 links.py:20
msgid "Grant"
#: apps.py:20 links.py:38 models.py:36
msgid "Permissions"
msgstr ""
#: links.py:12 links.py:21
msgid "Revoke"
#: apps.py:24 models.py:38
#| msgid "Roles"
msgid "Role"
msgstr ""
#: links.py:15
msgid "Default ACLs"
msgstr "Контролни списъци за достъп по подразбиране"
#: links.py:16 views.py:379
msgid "Classes"
#: links.py:26
msgid "Delete"
msgstr ""
#: links.py:17
msgid "ACLs for class"
msgstr "Контролни списъци за клас"
#: links.py:34
#| msgid "View ACLs"
msgid "New ACL"
msgstr ""
#: managers.py:118 managers.py:130
#: managers.py:72
msgid "Insufficient access."
msgstr "Недостатъчен достъп."
#: models.py:25 models.py:67
msgid "Permission"
msgstr ""
#: models.py:51
#: models.py:44
msgid "Access entry"
msgstr ""
#: models.py:52
#: models.py:45
msgid "Access entries"
msgstr ""
#: models.py:88
msgid "Default access entry"
#: models.py:60
msgid "None"
msgstr ""
#: models.py:89
msgid "Default access entries"
msgstr ""
#: models.py:108 models.py:111 models.py:112
msgid "Creator"
msgstr ""
#: permissions.py:7 permissions.py:8
#: permissions.py:7
msgid "Access control lists"
msgstr "Контролни списъци за достъп"
msgstr ""
#: permissions.py:10
msgid "Edit ACLs"
msgstr ""
#: permissions.py:11
#: permissions.py:13
msgid "View ACLs"
msgstr ""
#: permissions.py:13
msgid "Edit class default ACLs"
msgstr ""
#: permissions.py:14
msgid "View class default ACLs"
msgstr ""
#: views.py:48
#: views.py:61
#, python-format
msgid "Access control lists for: %s"
msgstr ""
#: views.py:50 views.py:402
msgid "Holder"
msgstr ""
#: views.py:51 views.py:403
msgid "Permissions"
msgstr ""
#: views.py:98
#: views.py:107
#, python-format
msgid "Permissions available to: %(actor)s for %(obj)s"
msgid "New access control lists for: %s"
msgstr ""
#: views.py:105 views.py:434
msgid "Namespace"
#: views.py:132
#, python-format
#| msgid "Default ACLs"
msgid "Delete ACL: %s"
msgstr ""
#: views.py:106 views.py:435
msgid "Label"
#: views.py:147
msgid "Available permissions"
msgstr ""
#: views.py:108 views.py:437
msgid "Has permission"
#: views.py:148
msgid "Granted permissions"
msgstr ""
#: views.py:181 views.py:272 views.py:516 views.py:593
msgid ", "
#: views.py:187
msgid "Disabled permissions are inherited from a parent object."
msgstr ""
#: views.py:182 views.py:273 views.py:517 views.py:594
#: views.py:218
#, python-format
msgid " for %s"
msgstr " за %s"
#: views.py:183 views.py:518
#, python-format
msgid " to %s"
msgstr " към %s"
#: views.py:186 views.py:521
#, python-format
msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
msgstr "Сигурни ли сте, че искате да дадете разрешение за %(title_suffix)s?"
#: views.py:188 views.py:523
#, python-format
msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
msgstr "Сигурни ли сте, че искате да дадете разрешения за %(title_suffix)s?"
#: views.py:195 views.py:530
#, python-format
msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
msgid "Role \"%(role)s\" permission's for \"%(object)s\""
msgstr ""
#: views.py:201 views.py:536
#, python-format
msgid ""
"%(actor)s, already had the permission \"%(permission)s\" granted for "
"%(object)s."
msgstr ""
#~ msgid "New holder"
#~ msgstr "New holder"
#: views.py:274 views.py:595
#, python-format
msgid " from %s"
msgstr " от %s"
#~ msgid "Users"
#~ msgstr "Users"
#: views.py:277 views.py:598
#, python-format
msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
msgstr "Сигурни ли сте, че искате да отнемете разрешението за %(title_suffix)s?"
#~ msgid "Groups"
#~ msgstr "Groups"
#: views.py:279 views.py:600
#, python-format
msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
msgstr "Сигурни ли сте, че искате да отнемете разрешенията за %(title_suffix)s?"
#~ msgid "Special"
#~ msgstr "Special"
#: views.py:286 views.py:607
#, python-format
msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
msgstr ""
#~ msgid "Details"
#~ msgstr "details"
#: views.py:292 views.py:613
#, python-format
msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
msgstr ""
#~ msgid "Grant"
#~ msgstr "grant"
#: views.py:346
#, python-format
msgid "Add new holder for: %s"
msgstr ""
#~ msgid "Revoke"
#~ msgstr "revoke"
#: views.py:347 views.py:477
msgid "Select"
msgstr ""
#~ msgid "Classes"
#~ msgstr "classes"
#: views.py:381
msgid "Class"
msgstr ""
#~ msgid "ACLs for class"
#~ msgstr "ACLs for class"
#: views.py:400
#, python-format
msgid "Default access control lists for class: %s"
msgstr ""
#~ msgid "Permission"
#~ msgstr "permissions"
#: views.py:428
#, python-format
msgid "Permissions available to: %(actor)s for class %(class)s"
msgstr ""
#~ msgid "Default access entry"
#~ msgstr "default access entry"
#: views.py:475
#, python-format
msgid "Add new holder for class: %s"
msgstr ""
#~ msgid "Default access entries"
#~ msgstr "default access entries"
#~ msgid "Creator"
#~ msgstr "Creator"
#~ msgid "Edit class default ACLs"
#~ msgstr "Edit class default ACLs"
#~ msgid "View class default ACLs"
#~ msgstr "View class default ACLs"
#~ msgid "Holder"
#~ msgstr "holder"
#~ msgid "Permissions available to: %(actor)s for %(obj)s"
#~ msgstr "permissions available to: %(actor)s for %(obj)s"
#~ msgid "Namespace"
#~ msgstr "namespace"
#~ msgid "Label"
#~ msgstr "label"
#~ msgid ", "
#~ msgstr ", "
#~ msgid " for %s"
#~ msgstr " for %s"
#~ msgid " to %s"
#~ msgstr " to %s"
#~ msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgid ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgstr ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgid " from %s"
#~ msgstr " from %s"
#~ msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgstr "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgid "Add new holder for: %s"
#~ msgstr "add new holder for: %s"
#~ msgid "Select"
#~ msgstr "Select"
#~ msgid "Class"
#~ msgstr "class"
#~ msgid "Default access control lists for class: %s"
#~ msgstr "default access control lists for class: %s"
#~ msgid "Permissions available to: %(actor)s for class %(class)s"
#~ msgstr "permissions available to: %(actor)s for class %(class)s"
#~ msgid "Add new holder for class: %s"
#~ msgstr "add new holder for class: %s"
#~ msgid "List of classes"
#~ msgstr "List of classes"

View File

@@ -4,235 +4,217 @@
#
# Translators:
# Translators:
# www.ping.ba <jomer@ping.ba>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-15 18:59-0400\n"
"PO-Revision-Date: 2014-10-25 06:47+0000\n"
"POT-Creation-Date: 2015-09-24 16:24-0400\n"
"PO-Revision-Date: 2015-09-24 05:15+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Bosnian (Bosnia and Herzegovina) (http://www.transifex.com/projects/p/mayan-edms/language/bs_BA/)\n"
"Language-Team: Bosnian (Bosnia and Herzegovina) (http://www.transifex.com/rosarior/mayan-edms/language/bs_BA/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bs_BA\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: forms.py:25 links.py:13 links.py:19
msgid "New holder"
msgstr "Novi posjednik"
#: forms.py:42
msgid "Users"
msgstr "Korisnici"
#: forms.py:45
msgid "Groups"
msgstr "Grupe"
#: forms.py:48
msgid "Roles"
msgstr "Role"
#: forms.py:51
msgid "Special"
msgstr "Posebno"
#: links.py:9
#: apps.py:14 links.py:30
msgid "ACLs"
msgstr "ACLs"
#: links.py:10 links.py:18
msgid "Details"
msgstr ""
#: links.py:11 links.py:20
msgid "Grant"
#: apps.py:20 links.py:38 models.py:36
msgid "Permissions"
msgstr ""
#: links.py:12 links.py:21
msgid "Revoke"
#: apps.py:24 models.py:38
#| msgid "Roles"
msgid "Role"
msgstr ""
#: links.py:15
msgid "Default ACLs"
msgstr "Difoltne ACLs"
#: links.py:16 views.py:379
msgid "Classes"
#: links.py:26
msgid "Delete"
msgstr ""
#: links.py:17
msgid "ACLs for class"
msgstr "ACLs za klasu"
#: links.py:34
#| msgid "View ACLs"
msgid "New ACL"
msgstr ""
#: managers.py:118 managers.py:130
#: managers.py:72
msgid "Insufficient access."
msgstr "Nedovoljne dozvole."
#: models.py:25 models.py:67
msgid "Permission"
msgstr ""
#: models.py:51
#: models.py:44
msgid "Access entry"
msgstr ""
#: models.py:52
#: models.py:45
msgid "Access entries"
msgstr ""
#: models.py:88
msgid "Default access entry"
#: models.py:60
msgid "None"
msgstr ""
#: models.py:89
msgid "Default access entries"
msgstr ""
#: models.py:108 models.py:111 models.py:112
msgid "Creator"
msgstr "Kreator"
#: permissions.py:7 permissions.py:8
#: permissions.py:7
msgid "Access control lists"
msgstr "Liste kontrole pristupa (ACLs)"
msgstr ""
#: permissions.py:10
msgid "Edit ACLs"
msgstr "Izmjeniti ACLs"
#: permissions.py:11
msgid "View ACLs"
msgstr "Pregledati ACLs"
msgstr ""
#: permissions.py:13
msgid "Edit class default ACLs"
msgstr "Izmjeniti difoltne ACLs klase"
msgid "View ACLs"
msgstr ""
#: permissions.py:14
msgid "View class default ACLs"
msgstr "Pregledati difoltne ACLs klase"
#: views.py:48
#: views.py:61
#, python-format
msgid "Access control lists for: %s"
msgstr ""
#: views.py:50 views.py:402
msgid "Holder"
#: views.py:107
#, python-format
msgid "New access control lists for: %s"
msgstr ""
#: views.py:51 views.py:403
msgid "Permissions"
#: views.py:132
#, python-format
#| msgid "Default ACLs"
msgid "Delete ACL: %s"
msgstr ""
#: views.py:98
#, python-format
msgid "Permissions available to: %(actor)s for %(obj)s"
#: views.py:147
msgid "Available permissions"
msgstr ""
#: views.py:105 views.py:434
msgid "Namespace"
#: views.py:148
msgid "Granted permissions"
msgstr ""
#: views.py:106 views.py:435
msgid "Label"
#: views.py:187
msgid "Disabled permissions are inherited from a parent object."
msgstr ""
#: views.py:108 views.py:437
msgid "Has permission"
#: views.py:218
#, python-format
msgid "Role \"%(role)s\" permission's for \"%(object)s\""
msgstr ""
#: views.py:181 views.py:272 views.py:516 views.py:593
msgid ", "
msgstr ", "
#~ msgid "New holder"
#~ msgstr "New holder"
#: views.py:182 views.py:273 views.py:517 views.py:594
#, python-format
msgid " for %s"
msgstr " za %s"
#~ msgid "Users"
#~ msgstr "Users"
#: views.py:183 views.py:518
#, python-format
msgid " to %s"
msgstr " prema %s"
#~ msgid "Groups"
#~ msgstr "Groups"
#: views.py:186 views.py:521
#, python-format
msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
msgstr "Jeste li sigurni da želite odobriti dozvolu %(title_suffix)s?"
#~ msgid "Special"
#~ msgstr "Special"
#: views.py:188 views.py:523
#, python-format
msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
msgstr "Jeste li sigurni da želite odobriti dozvole %(title_suffix)s?"
#~ msgid "Details"
#~ msgstr "details"
#: views.py:195 views.py:530
#, python-format
msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
msgstr "Dozvola \"%(permission)s\" odobrena za %(actor)s prema %(object)s."
#~ msgid "Grant"
#~ msgstr "grant"
#: views.py:201 views.py:536
#, python-format
msgid ""
"%(actor)s, already had the permission \"%(permission)s\" granted for "
"%(object)s."
msgstr "%(actor)s, već ima dozvolu \"%(permission)s\" prema %(object)s."
#~ msgid "Revoke"
#~ msgstr "revoke"
#: views.py:274 views.py:595
#, python-format
msgid " from %s"
msgstr " od %s"
#~ msgid "Classes"
#~ msgstr "classes"
#: views.py:277 views.py:598
#, python-format
msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
msgstr "Jeste li sigurni da želite ukinuti dozvolu %(title_suffix)s?"
#~ msgid "ACLs for class"
#~ msgstr "ACLs for class"
#: views.py:279 views.py:600
#, python-format
msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
msgstr "Jeste li sigurni da želite ukinuti dozvole %(title_suffix)s?"
#~ msgid "Permission"
#~ msgstr "permissions"
#: views.py:286 views.py:607
#, python-format
msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
msgstr "Dozvola \"%(permission)s\" povučena za %(actor)s prema %(object)s."
#~ msgid "Default access entry"
#~ msgstr "default access entry"
#: views.py:292 views.py:613
#, python-format
msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
msgstr "%(actor)s, nije imao/la dozvolu \"%(permission)s\" prema %(object)s."
#~ msgid "Default access entries"
#~ msgstr "default access entries"
#: views.py:346
#, python-format
msgid "Add new holder for: %s"
msgstr ""
#~ msgid "Creator"
#~ msgstr "Creator"
#: views.py:347 views.py:477
msgid "Select"
msgstr "Odabrati"
#~ msgid "Edit class default ACLs"
#~ msgstr "Edit class default ACLs"
#: views.py:381
msgid "Class"
msgstr ""
#~ msgid "View class default ACLs"
#~ msgstr "View class default ACLs"
#: views.py:400
#, python-format
msgid "Default access control lists for class: %s"
msgstr ""
#~ msgid "Holder"
#~ msgstr "holder"
#: views.py:428
#, python-format
msgid "Permissions available to: %(actor)s for class %(class)s"
msgstr ""
#~ msgid "Permissions available to: %(actor)s for %(obj)s"
#~ msgstr "permissions available to: %(actor)s for %(obj)s"
#: views.py:475
#, python-format
msgid "Add new holder for class: %s"
msgstr ""
#~ msgid "Namespace"
#~ msgstr "namespace"
#~ msgid "Label"
#~ msgstr "label"
#~ msgid ", "
#~ msgstr ", "
#~ msgid " for %s"
#~ msgstr " for %s"
#~ msgid " to %s"
#~ msgstr " to %s"
#~ msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgid ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgstr ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgid " from %s"
#~ msgstr " from %s"
#~ msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgstr "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgid "Add new holder for: %s"
#~ msgstr "add new holder for: %s"
#~ msgid "Select"
#~ msgstr "Select"
#~ msgid "Class"
#~ msgstr "class"
#~ msgid "Default access control lists for class: %s"
#~ msgstr "default access control lists for class: %s"
#~ msgid "Permissions available to: %(actor)s for class %(class)s"
#~ msgstr "permissions available to: %(actor)s for class %(class)s"
#~ msgid "Add new holder for class: %s"
#~ msgstr "add new holder for class: %s"
#~ msgid "List of classes"
#~ msgstr "List of classes"

View File

@@ -8,93 +8,55 @@ msgid ""
msgstr ""
"Project-Id-Version: Mayan EDMS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-15 18:59-0400\n"
"PO-Revision-Date: 2014-10-25 06:47+0000\n"
"POT-Creation-Date: 2015-09-24 16:24-0400\n"
"PO-Revision-Date: 2015-09-24 05:15+0000\n"
"Last-Translator: Roberto Rosario\n"
"Language-Team: Danish (http://www.transifex.com/projects/p/mayan-edms/language/da/)\n"
"Language-Team: Danish (http://www.transifex.com/rosarior/mayan-edms/language/da/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: da\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:25 links.py:13 links.py:19
msgid "New holder"
msgstr ""
#: forms.py:42
msgid "Users"
msgstr ""
#: forms.py:45
msgid "Groups"
msgstr ""
#: forms.py:48
msgid "Roles"
msgstr ""
#: forms.py:51
msgid "Special"
msgstr ""
#: links.py:9
#: apps.py:14 links.py:30
msgid "ACLs"
msgstr ""
#: links.py:10 links.py:18
msgid "Details"
#: apps.py:20 links.py:38 models.py:36
msgid "Permissions"
msgstr ""
#: links.py:11 links.py:20
msgid "Grant"
#: apps.py:24 models.py:38
#| msgid "Roles"
msgid "Role"
msgstr ""
#: links.py:12 links.py:21
msgid "Revoke"
#: links.py:26
msgid "Delete"
msgstr ""
#: links.py:15
msgid "Default ACLs"
#: links.py:34
#| msgid "View ACLs"
msgid "New ACL"
msgstr ""
#: links.py:16 views.py:379
msgid "Classes"
msgstr ""
#: links.py:17
msgid "ACLs for class"
msgstr ""
#: managers.py:118 managers.py:130
#: managers.py:72
msgid "Insufficient access."
msgstr ""
#: models.py:25 models.py:67
msgid "Permission"
msgstr ""
#: models.py:51
#: models.py:44
msgid "Access entry"
msgstr ""
#: models.py:52
#: models.py:45
msgid "Access entries"
msgstr ""
#: models.py:88
msgid "Default access entry"
#: models.py:60
msgid "None"
msgstr ""
#: models.py:89
msgid "Default access entries"
msgstr ""
#: models.py:108 models.py:111 models.py:112
msgid "Creator"
msgstr ""
#: permissions.py:7 permissions.py:8
#: permissions.py:7
msgid "Access control lists"
msgstr ""
@@ -102,136 +64,157 @@ msgstr ""
msgid "Edit ACLs"
msgstr ""
#: permissions.py:11
#: permissions.py:13
msgid "View ACLs"
msgstr ""
#: permissions.py:13
msgid "Edit class default ACLs"
msgstr ""
#: permissions.py:14
msgid "View class default ACLs"
msgstr ""
#: views.py:48
#: views.py:61
#, python-format
msgid "Access control lists for: %s"
msgstr ""
#: views.py:50 views.py:402
msgid "Holder"
msgstr ""
#: views.py:51 views.py:403
msgid "Permissions"
msgstr ""
#: views.py:98
#: views.py:107
#, python-format
msgid "Permissions available to: %(actor)s for %(obj)s"
msgid "New access control lists for: %s"
msgstr ""
#: views.py:105 views.py:434
msgid "Namespace"
msgstr ""
#: views.py:106 views.py:435
msgid "Label"
msgstr ""
#: views.py:108 views.py:437
msgid "Has permission"
msgstr ""
#: views.py:181 views.py:272 views.py:516 views.py:593
msgid ", "
msgstr ""
#: views.py:182 views.py:273 views.py:517 views.py:594
#: views.py:132
#, python-format
msgid " for %s"
#| msgid "Default ACLs"
msgid "Delete ACL: %s"
msgstr ""
#: views.py:183 views.py:518
#: views.py:147
msgid "Available permissions"
msgstr ""
#: views.py:148
msgid "Granted permissions"
msgstr ""
#: views.py:187
msgid "Disabled permissions are inherited from a parent object."
msgstr ""
#: views.py:218
#, python-format
msgid " to %s"
msgid "Role \"%(role)s\" permission's for \"%(object)s\""
msgstr ""
#: views.py:186 views.py:521
#, python-format
msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
msgstr ""
#~ msgid "New holder"
#~ msgstr "New holder"
#: views.py:188 views.py:523
#, python-format
msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
msgstr ""
#~ msgid "Users"
#~ msgstr "Users"
#: views.py:195 views.py:530
#, python-format
msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
msgstr ""
#~ msgid "Groups"
#~ msgstr "Groups"
#: views.py:201 views.py:536
#, python-format
msgid ""
"%(actor)s, already had the permission \"%(permission)s\" granted for "
"%(object)s."
msgstr ""
#~ msgid "Special"
#~ msgstr "Special"
#: views.py:274 views.py:595
#, python-format
msgid " from %s"
msgstr ""
#~ msgid "Details"
#~ msgstr "details"
#: views.py:277 views.py:598
#, python-format
msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
msgstr ""
#~ msgid "Grant"
#~ msgstr "grant"
#: views.py:279 views.py:600
#, python-format
msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
msgstr ""
#~ msgid "Revoke"
#~ msgstr "revoke"
#: views.py:286 views.py:607
#, python-format
msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
msgstr ""
#~ msgid "Classes"
#~ msgstr "classes"
#: views.py:292 views.py:613
#, python-format
msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
msgstr ""
#~ msgid "ACLs for class"
#~ msgstr "ACLs for class"
#: views.py:346
#, python-format
msgid "Add new holder for: %s"
msgstr ""
#~ msgid "Permission"
#~ msgstr "permissions"
#: views.py:347 views.py:477
msgid "Select"
msgstr ""
#~ msgid "Default access entry"
#~ msgstr "default access entry"
#: views.py:381
msgid "Class"
msgstr ""
#~ msgid "Default access entries"
#~ msgstr "default access entries"
#: views.py:400
#, python-format
msgid "Default access control lists for class: %s"
msgstr ""
#~ msgid "Creator"
#~ msgstr "Creator"
#: views.py:428
#, python-format
msgid "Permissions available to: %(actor)s for class %(class)s"
msgstr ""
#~ msgid "Edit class default ACLs"
#~ msgstr "Edit class default ACLs"
#: views.py:475
#, python-format
msgid "Add new holder for class: %s"
msgstr ""
#~ msgid "View class default ACLs"
#~ msgstr "View class default ACLs"
#~ msgid "Holder"
#~ msgstr "holder"
#~ msgid "Permissions available to: %(actor)s for %(obj)s"
#~ msgstr "permissions available to: %(actor)s for %(obj)s"
#~ msgid "Namespace"
#~ msgstr "namespace"
#~ msgid "Label"
#~ msgstr "label"
#~ msgid ", "
#~ msgstr ", "
#~ msgid " for %s"
#~ msgstr " for %s"
#~ msgid " to %s"
#~ msgstr " to %s"
#~ msgid "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to grant the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" granted to %(actor)s for %(object)s."
#~ msgid ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgstr ""
#~ "%(actor)s, already had the permission \"%(permission)s\" granted for "
#~ "%(object)s."
#~ msgid " from %s"
#~ msgstr " from %s"
#~ msgid "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permission %(title_suffix)s?"
#~ msgid "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgstr "Are you sure you wish to revoke the permissions %(title_suffix)s?"
#~ msgid "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgstr "Permission \"%(permission)s\" revoked of %(actor)s for %(object)s."
#~ msgid "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgstr "%(actor)s, didn't had the permission \"%(permission)s\" for %(object)s."
#~ msgid "Add new holder for: %s"
#~ msgstr "add new holder for: %s"
#~ msgid "Select"
#~ msgstr "Select"
#~ msgid "Class"
#~ msgstr "class"
#~ msgid "Default access control lists for class: %s"
#~ msgstr "default access control lists for class: %s"
#~ msgid "Permissions available to: %(actor)s for class %(class)s"
#~ msgstr "permissions available to: %(actor)s for class %(class)s"
#~ msgid "Add new holder for class: %s"
#~ msgstr "add new holder for class: %s"
#~ msgid "List of classes"
#~ msgstr "List of classes"

Some files were not shown because too many files have changed in this diff Show More