Merge remote-tracking branch 'origin/versions/micro' into merges/micro_to_minor
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
@@ -173,7 +173,8 @@ test-mysql:
|
||||
script:
|
||||
- apt-get install -qq libmysqlclient-dev mysql-client
|
||||
- . venv/bin/activate
|
||||
- pip install mysqlclient
|
||||
- set -a && . ./config.env && set +a
|
||||
- pip install mysqlclient==$PYTHON_MYSQL_VERSION
|
||||
- mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD" -e "set global character_set_server=utf8mb4;"
|
||||
- python manage.py test --mayan-apps --settings=mayan.settings.testing.gitlab-ci.db_mysql --nomigrations
|
||||
tags:
|
||||
@@ -189,7 +190,8 @@ test-postgres:
|
||||
script:
|
||||
- apt-get install -qq libpq-dev
|
||||
- . venv/bin/activate
|
||||
- pip install psycopg2
|
||||
- set -a && . ./config.env && set +a
|
||||
- pip install psycopg2==$PYTHON_PSYCOPG2_VERSION
|
||||
- python manage.py test --mayan-apps --settings=mayan.settings.testing.gitlab-ci.db_postgres --nomigrations
|
||||
tags:
|
||||
- postgres
|
||||
|
||||
13
HISTORY.rst
13
HISTORY.rst
@@ -137,6 +137,19 @@
|
||||
- Add makefile target to launch a production staging Docker image.
|
||||
- Improve duplicated document list view logic to not show
|
||||
documents with trashed duplicates.
|
||||
- Backport Docker composer makefile targets.
|
||||
- Add PermissionTestCaseMixin and SmartSettingTestCaseMixin to better
|
||||
organize cache invalidation of both apps for tests.
|
||||
- Add a version attribute to setting namespace. These are dumped
|
||||
as SMART_SETTINGS_NAMESPACES.
|
||||
- Add savesettings command.
|
||||
- Add extra logging to the IMAP email source. GitLab issue #682.
|
||||
Thanks to Patrick Hütter (@PatrickHuetter) for the report.
|
||||
- Rename all instances of the IMAP server from mailbox to
|
||||
server for clarity.
|
||||
- Add book link in the about menu.
|
||||
- Add unknown exception handling when checking for the latest
|
||||
version.
|
||||
|
||||
3.2.8 (2019-10-01)
|
||||
==================
|
||||
|
||||
23
Makefile
23
Makefile
@@ -1,3 +1,5 @@
|
||||
#!make
|
||||
include config.env
|
||||
.PHONY: clean-pyc clean-build
|
||||
|
||||
DOCKER_MYSQL_IMAGE = mysql:8.0
|
||||
@@ -5,11 +7,6 @@ DOCKER_ORACLE_IMAGE = wnameless/oracle-xe-11g
|
||||
DOCKER_POSTGRES_IMAGE = postgres:9.6-alpine
|
||||
DOCKER_REDIS_IMAGE = redis:5.0-alpine
|
||||
|
||||
PYTHON_MYSQL_VERSION = 1.4.4
|
||||
PYTHON_PSYCOPG2_VERSION = 2.8.3
|
||||
PYTHON_RABBITMQ_VERSION = 2.0.0
|
||||
PYTHON_REDIS_VERSION = 3.2.1
|
||||
|
||||
help:
|
||||
@echo "Usage: make <target>\n"
|
||||
@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*?## / { printf " * %-40s -%s\n", $$1, $$2 }' $(MAKEFILE_LIST)|sort
|
||||
@@ -43,7 +40,7 @@ test-all: clean-pyc
|
||||
test-launch-postgres:
|
||||
@docker rm -f test-postgres || true
|
||||
@docker volume rm test-postgres || true
|
||||
docker run -d --name test-postgres -p 5432:5432 -v test-postgres:/var/lib/postgresql/data $(DOCKER_POSTGRES_IMAGE)
|
||||
docker run -d --name test-postgres -p 5432:5432 -v test-postgres:/var/lib/postgresql/data $(DOCKER_POSTGRES_IMAGE_VERSION)
|
||||
sudo apt-get install -q libpq-dev
|
||||
pip install psycopg2==$(PYTHON_PSYCOPG2_VERSION)
|
||||
while ! nc -z 127.0.0.1 5432; do sleep 1; done
|
||||
@@ -63,7 +60,7 @@ test-with-postgres-all: test-launch-postgres
|
||||
test-launch-mysql:
|
||||
@docker rm -f test-mysql || true
|
||||
@docker volume rm test-mysql || true
|
||||
docker run -d --name test-mysql -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=True -e MYSQL_DATABASE=mayan -v test-mysql:/var/lib/mysql $(DOCKER_MYSQL_IMAGE)
|
||||
docker run -d --name test-mysql -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=True -e MYSQL_DATABASE=mayan -v test-mysql:/var/lib/mysql $(DOCKER_MYSQL_IMAGE_VERSION)
|
||||
sudo apt-get install -q libmysqlclient-dev mysql-client
|
||||
pip install mysqlclient==$(PYTHON_MYSQL_VERSION)
|
||||
while ! nc -z 127.0.0.1 3306; do sleep 1; done
|
||||
@@ -85,9 +82,9 @@ test-with-mysql-all: test-launch-mysql
|
||||
test-launch-oracle:
|
||||
@docker rm -f test-oracle || true
|
||||
@docker volume rm test-oracle || true
|
||||
docker run -d --name test-oracle -p 49160:22 -p 49161:1521 -e ORACLE_ALLOW_REMOTE=true -v test-oracle:/u01/app/oracle $(DOCKER_ORACLE_IMAGE)
|
||||
docker run -d --name test-oracle -p 49160:22 -p 49161:1521 -e ORACLE_ALLOW_REMOTE=true -v test-oracle:/u01/app/oracle $(DOCKER_ORACLE_IMAGE_VERSION)
|
||||
# https://gist.github.com/kimus/10012910
|
||||
pip install cx_Oracle
|
||||
pip install cx_Oracle==$(PYTHON_ORACLE_VERSION)
|
||||
while ! nc -z 127.0.0.1 49161; do sleep 1; done
|
||||
sleep 10
|
||||
|
||||
@@ -256,8 +253,8 @@ shell_plus: ## Run the shell_plus command.
|
||||
./manage.py shell_plus --settings=mayan.settings.development
|
||||
|
||||
test-with-docker-services-on: ## Launch and initialize production-like services using Docker (Postgres and Redis).
|
||||
docker run -d --name redis -p 6379:6379 $(DOCKER_REDIS_IMAGE)
|
||||
docker run -d --name postgres -p 5432:5432 $(DOCKER_POSTGRES_IMAGE)
|
||||
docker run -d --name redis -p 6379:6379 $(DOCKER_REDIS_IMAGE_VERSION)
|
||||
docker run -d --name postgres -p 5432:5432 $(DOCKER_POSTGRES_IMAGE_VERSION)
|
||||
while ! nc -z 127.0.0.1 6379; do sleep 1; done
|
||||
while ! nc -z 127.0.0.1 5432; do sleep 1; done
|
||||
sleep 4
|
||||
@@ -275,7 +272,7 @@ test-with-docker-worker: ## Launch a worker instance that uses the production-li
|
||||
DJANGO_SETTINGS_MODULE=mayan.settings.staging.docker ./manage.py celery worker -A mayan -B -l INFO -O fair
|
||||
|
||||
docker-mysql-on: ## Launch and initialize a MySQL Docker container.
|
||||
docker run -d --name mysql -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=True -e MYSQL_DATABASE=mayan_edms $(DOCKER_MYSQL_IMAGE)
|
||||
docker run -d --name mysql -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=True -e MYSQL_DATABASE=mayan_edms $(DOCKER_MYSQL_IMAGE_VERSION)
|
||||
while ! nc -z 127.0.0.1 3306; do sleep 1; done
|
||||
|
||||
docker-mysql-off: ## Stop and delete the MySQL Docker container.
|
||||
@@ -283,7 +280,7 @@ docker-mysql-off: ## Stop and delete the MySQL Docker container.
|
||||
docker rm mysql
|
||||
|
||||
docker-postgres-on: ## Launch and initialize a PostgreSQL Docker container.
|
||||
docker run -d --name postgres -p 5432:5432 $(DOCKER_POSTGRES_IMAGE)
|
||||
docker run -d --name postgres -p 5432:5432 $(DOCKER_POSTGRES_IMAGE_VERSION)
|
||||
while ! nc -z 127.0.0.1 5432; do sleep 1; done
|
||||
|
||||
docker-postgres-off: ## Stop and delete the PostgreSQL Docker container.
|
||||
|
||||
12
config.env
Normal file
12
config.env
Normal file
@@ -0,0 +1,12 @@
|
||||
DOCKER_MYSQL_IMAGE_VERSION=mysql:8.0
|
||||
DOCKER_ORACLE_IMAGE=wnameless/oracle-xe-11g
|
||||
DOCKER_POSTGRES_IMAGE_VERSION=postgres:9.6-alpine
|
||||
DOCKER_RABBITMQ_IMAGE_VERSION=rabbitmq:3
|
||||
DOCKER_REDIS_IMAGE_VERSION=redis:5.0-alpine
|
||||
PYTHON_FLOWER_VERSION=0.9.3
|
||||
PYTHON_LIBRABBITMQ_VERSION=2.0.0
|
||||
PYTHON_MYSQL_VERSION=1.4.4
|
||||
PYTHON_ORACLE_VERSION=7.2.3
|
||||
PYTHON_PSYCOPG2_VERSION=2.8.3
|
||||
PYTHON_PSUTIL_VERSION=5.6.2
|
||||
PYTHON_REDIS_VERSION=3.2.1
|
||||
@@ -8,6 +8,8 @@ FROM debian:10.0-slim as BASE_IMAGE
|
||||
|
||||
LABEL maintainer="Roberto Rosario roberto.rosario@mayan-edms.com"
|
||||
|
||||
COPY config.env /config.env
|
||||
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
LC_ALL=C.UTF-8 \
|
||||
PROJECT_INSTALL_DIR=/opt/mayan-edms
|
||||
@@ -104,18 +106,22 @@ apt-get install -y --no-install-recommends \
|
||||
&& chown -R mayan:mayan /src
|
||||
|
||||
USER mayan
|
||||
RUN python3 -m venv "${PROJECT_INSTALL_DIR}" \
|
||||
|
||||
RUN set -a \
|
||||
&& . /config.env \
|
||||
&& set +a \
|
||||
&& python3 -m venv "${PROJECT_INSTALL_DIR}" \
|
||||
&& . "${PROJECT_INSTALL_DIR}/bin/activate" \
|
||||
&& pip install --no-cache-dir \
|
||||
librabbitmq==2.0.0 \
|
||||
mysqlclient==1.4.2.post1 \
|
||||
psycopg2==2.8.3 \
|
||||
redis==3.2.1 \
|
||||
flower==0.9.3 \
|
||||
librabbitmq==$PYTHON_LIBRABBITMQ_VERSION \
|
||||
mysql-python==$PYTHON_MYSQL_VERSION \
|
||||
psycopg2==$PYTHON_PSYCOPG2_VERSION \
|
||||
redis==$PYTHON_REDIS_VERSION \
|
||||
flower==$PYTHON_FLOWER_VERSION \
|
||||
# psutil is needed by ARM builds otherwise gevent and gunicorn fail to start
|
||||
&& UNAME=`uname -m` && if [ "${UNAME#*arm}" != $UNAME ]; then \
|
||||
pip install --no-cache-dir \
|
||||
psutil==5.6.2 \
|
||||
psutil==$PYTHON_PSUTIL_VERSION \
|
||||
; fi \
|
||||
# Install the Python packages needed to build Mayan EDMS
|
||||
&& pip install --no-cache-dir -r /src/requirements/build.txt \
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#!make
|
||||
include config.env
|
||||
|
||||
HOST_IP = `/sbin/ip route|awk '/docker0/ { print $$9 }'`
|
||||
APT_PROXY ?= $(HOST_IP):3142
|
||||
CONSOLE_COLUMNS ?= `echo $$(tput cols)`
|
||||
@@ -51,13 +54,13 @@ docker-staging-container-postgresql-start:
|
||||
-e POSTGRES_DB=mayan \
|
||||
-e POSTGRES_PASSWORD=mayanuserpass \
|
||||
-v mayan-staging-postgres:/var/lib/postgresql/data \
|
||||
postgres:9.6-alpine
|
||||
$(DOCKER_POSTGRES_IMAGE_VERSION)
|
||||
|
||||
docker-staging-container-redis-start:
|
||||
docker run -d \
|
||||
--name mayan-staging-redis \
|
||||
--network=mayan-staging \
|
||||
redis:5.0-alpine \
|
||||
$(DOCKER_REDIS_IMAGE_VERSION) \
|
||||
redis-server \
|
||||
--databases \
|
||||
"2" \
|
||||
|
||||
@@ -59,7 +59,7 @@ Example::
|
||||
-e POSTGRES_DB=mayan \
|
||||
-e POSTGRES_PASSWORD=mayanuserpass \
|
||||
-v /docker-volumes/mayan-edms/postgres-new:/var/lib/postgresql/data \
|
||||
-d postgres:9.6
|
||||
|DOCKER_POSTGRES_IMAGE_VERSION|
|
||||
|
||||
docker exec -i mayan-edms-pg-new pg_restore -U mayan -d mayan < 2018-06-07_17-09-34.dump
|
||||
|
||||
|
||||
@@ -84,14 +84,14 @@ For another setup that offers more performance and scalability refer to the
|
||||
------------------------------------------------------
|
||||
::
|
||||
|
||||
sudo -u mayan /opt/mayan-edms/bin/pip install --no-cache-dir --no-use-pep517 psycopg2==2.7.3.2 redis==2.10.6
|
||||
sudo -u mayan /opt/mayan-edms/bin/pip install --no-cache-dir --no-use-pep517 psycopg2==|PYTHON_PSYCOPG2_VERSION| redis==|PYTHON_REDIS_VERSION|
|
||||
|
||||
.. note::
|
||||
|
||||
Platforms with the ARM CPU might also need additional requirements.
|
||||
::
|
||||
|
||||
sudo -u mayan /opt/mayan-edms/bin/pip install --no-cache-dir --no-use-pep517 psutil==5.6.2
|
||||
sudo -u mayan /opt/mayan-edms/bin/pip install --no-cache-dir --no-use-pep517 psutil==|PYTHON_PSUTIL_VERSION|
|
||||
|
||||
|
||||
8. Create the database for the installation:
|
||||
@@ -204,7 +204,7 @@ of a restart or power failure. The Gunicorn workers are increased to 3.
|
||||
------------------------------------------
|
||||
::
|
||||
|
||||
sudo -u mayan /opt/mayan-edms/bin/pip install --no-cache-dir --no-use-pep517 librabbitmq==2.0.0
|
||||
sudo -u mayan /opt/mayan-edms/bin/pip install --no-cache-dir --no-use-pep517 librabbitmq==|PYTHON_LIBRABBITMQ_VERSION|
|
||||
|
||||
|
||||
3. Create the RabbitMQ user and vhost:
|
||||
|
||||
@@ -247,7 +247,7 @@ Mayan EDMS follows a simplified model layout based on Vincent Driessen's
|
||||
Working branches for unfinished and unmerged feature. Likely unstable,
|
||||
don't use in production. Once the feature is complete, it is merged
|
||||
into one of the versions branches and deleted.
|
||||
|
||||
|
||||
Special branches:
|
||||
|
||||
``releases/all``
|
||||
@@ -317,7 +317,7 @@ Steps to deploy a development version
|
||||
|
||||
$ git clone https://gitlab.com/mayan-edms/mayan-edms.git
|
||||
$ cd mayan-edms
|
||||
$ git checkout development
|
||||
$ git checkout <Corresponding branch>
|
||||
$ virtualenv venv
|
||||
$ source venv/bin/activate
|
||||
$ pip install -r requirements.txt
|
||||
@@ -558,3 +558,10 @@ Manual release
|
||||
::
|
||||
|
||||
make release-via-docker-ubuntu
|
||||
|
||||
Other steps
|
||||
-----------
|
||||
|
||||
#. Update the contrib/scripts/install/docker.sh values
|
||||
|
||||
#. Upload contrib/scripts/install/docker.sh to https://get.mayan-edms.com
|
||||
|
||||
@@ -23,7 +23,7 @@ tag here, remember to do so in the next steps also.::
|
||||
|
||||
Then download version 9.6 of the Docker PostgreSQL image::
|
||||
|
||||
docker pull postgres:9.6-alpine
|
||||
docker pull |DOCKER_POSTGRES_IMAGE_VERSION|
|
||||
|
||||
Create and run a PostgreSQL container::
|
||||
|
||||
@@ -35,7 +35,7 @@ Create and run a PostgreSQL container::
|
||||
-e POSTGRES_DB=mayan \
|
||||
-e POSTGRES_PASSWORD=mayanuserpass \
|
||||
-v /docker-volumes/mayan-edms/postgres:/var/lib/postgresql/data \
|
||||
-d postgres:9.6-alpine
|
||||
|DOCKER_POSTGRES_IMAGE_VERSION|
|
||||
|
||||
The PostgreSQL container will have one database named ``mayan``, with an user
|
||||
named ``mayan`` too, with a password of ``mayanuserpass``. The container will
|
||||
@@ -92,7 +92,7 @@ binding (``-p 5432:5432``)::
|
||||
-e POSTGRES_DB=mayan \
|
||||
-e POSTGRES_PASSWORD=mayanuserpass \
|
||||
-v /docker-volumes/mayan-edms/postgres:/var/lib/postgresql/data \
|
||||
-d postgres:9.6-alpine
|
||||
|DOCKER_POSTGRES_IMAGE_VERSION|
|
||||
|
||||
Launch the Mayan EDMS container with the network option and change the
|
||||
database hostname to the PostgreSQL container name (``mayan-edms-postgres``)
|
||||
|
||||
@@ -92,7 +92,7 @@ section for the required changes.
|
||||
For the Docker image, launch a separate RabbitMQ container
|
||||
(https://hub.docker.com/_/rabbitmq/)::
|
||||
|
||||
docker run -d --name mayan-edms-rabbitmq -e RABBITMQ_DEFAULT_USER=mayan -e RABBITMQ_DEFAULT_PASS=mayanrabbitmqpassword -e RABBITMQ_DEFAULT_VHOST=mayan rabbitmq:3
|
||||
docker run -d --name mayan-edms-rabbitmq -e RABBITMQ_DEFAULT_USER=mayan -e RABBITMQ_DEFAULT_PASS=mayanrabbitmqpassword -e RABBITMQ_DEFAULT_VHOST=mayan |DOCKER_RABBITMQ_IMAGE_VERSION|
|
||||
|
||||
Pass the MAYAN_CELERY_BROKER_URL environment variable (https://kombu.readthedocs.io/en/latest/userguide/connections.html#connection-urls)
|
||||
to the Mayan EDMS container so that it uses the RabbitMQ container the
|
||||
|
||||
90
docs/conf.py
90
docs/conf.py
@@ -29,12 +29,12 @@ sys.path.append(
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
|
||||
#extensions = ["djangodocs", "sphinx.ext.intersphinx"]
|
||||
# extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
|
||||
# extensions = ["djangodocs", "sphinx.ext.intersphinx"]
|
||||
extensions = [
|
||||
'sphinx.ext.extlinks', 'sphinxcontrib.blockdiag',
|
||||
'sphinxcontrib.spelling'
|
||||
@@ -72,20 +72,20 @@ release = version
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
# language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
@@ -102,7 +102,7 @@ show_authors = False
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
# modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
@@ -119,23 +119,23 @@ html_theme_options = {
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
# html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
# html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
# html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
# html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
@@ -148,40 +148,40 @@ html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = False
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
# html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'MayanEDMSdoc'
|
||||
@@ -191,40 +191,42 @@ html_show_sphinx = False
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
# latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
# latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'MayanEDMS.tex', 'Mayan EDMS Documentation',
|
||||
mayan.__author__, 'manual'),
|
||||
(
|
||||
'index', 'MayanEDMS.tex', 'Mayan EDMS Documentation',
|
||||
mayan.__author__, 'manual'
|
||||
),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
# latex_show_urls = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
# latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
@@ -255,5 +257,25 @@ extlinks = {
|
||||
}
|
||||
|
||||
|
||||
def _load_env_file(filename='../config.env'):
|
||||
result = []
|
||||
with open(filename) as file_object:
|
||||
for line in file_object:
|
||||
if not line.startswith('#'):
|
||||
key, value = line.strip().split('=')
|
||||
result.append(('|{}|'.format(key), value))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def GlobalSubstitution(app, docname, source):
|
||||
for old, new in global_subtitutions:
|
||||
source[0] = source[0].replace(old, new)
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_stylesheet('css/custom.css')
|
||||
app.connect('source-read', GlobalSubstitution)
|
||||
|
||||
|
||||
global_subtitutions = _load_env_file()
|
||||
|
||||
@@ -22,7 +22,7 @@ from .handlers import (
|
||||
handler_user_locale_profile_session_config, handler_user_locale_profile_create
|
||||
)
|
||||
from .links import (
|
||||
link_about, link_current_user_locale_profile_edit, link_license,
|
||||
link_about, link_book, link_current_user_locale_profile_edit, link_license,
|
||||
link_object_error_list_clear, link_setup, link_tools
|
||||
)
|
||||
|
||||
@@ -109,7 +109,7 @@ class CommonApp(MayanAppConfig):
|
||||
|
||||
menu_about.bind_links(
|
||||
links=(
|
||||
link_tools, link_setup, link_about, link_license,
|
||||
link_tools, link_setup, link_about, link_book, link_license,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ icon_add_all = Icon(
|
||||
)
|
||||
icon_assign_remove_add = Icon(driver_name='fontawesome', symbol='plus')
|
||||
icon_assign_remove_remove = Icon(driver_name='fontawesome', symbol='minus')
|
||||
icon_book = Icon(driver_name='fontawesome', symbol='book')
|
||||
icon_confirm_form_submit = Icon(driver_name='fontawesome', symbol='check')
|
||||
icon_confirm_form_cancel = Icon(driver_name='fontawesome', symbol='times')
|
||||
icon_current_user_locale_profile_details = Icon(
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from mayan.apps.navigation.classes import Link
|
||||
|
||||
from .icons import (
|
||||
icon_about, icon_current_user_locale_profile_details,
|
||||
icon_about, icon_book, icon_current_user_locale_profile_details,
|
||||
icon_current_user_locale_profile_edit, icon_documentation,
|
||||
icon_forum, icon_license, icon_setup, icon_source_code, icon_support,
|
||||
icon_tools
|
||||
@@ -35,6 +35,10 @@ def get_kwargs_factory(variable_name):
|
||||
link_about = Link(
|
||||
icon_class=icon_about, text=_('About this'), view='common:about_view'
|
||||
)
|
||||
link_book = Link(
|
||||
icon_class=icon_book, tags='new_window', text=_('Get the book'),
|
||||
url='https://mayan-edms.com/book/'
|
||||
)
|
||||
link_current_user_locale_profile_details = Link(
|
||||
icon_class=icon_current_user_locale_profile_details,
|
||||
text=_('Locale profile'),
|
||||
|
||||
@@ -6,8 +6,10 @@ from django_downloadview import assert_download_response
|
||||
|
||||
from mayan.apps.acls.tests.mixins import ACLTestCaseMixin
|
||||
from mayan.apps.converter.tests.mixins import LayerTestCaseMixin
|
||||
from mayan.apps.permissions.classes import Permission
|
||||
from mayan.apps.smart_settings.classes import Namespace
|
||||
from mayan.apps.permissions.tests.mixins import PermissionTestCaseMixin
|
||||
from mayan.apps.smart_settings.tests.mixins import SmartSettingsTestCaseMixin
|
||||
|
||||
|
||||
from mayan.apps.user_management.tests.mixins import UserTestMixin
|
||||
|
||||
from .mixins import (
|
||||
@@ -22,19 +24,15 @@ from .mixins import (
|
||||
class BaseTestCase(
|
||||
LayerTestCaseMixin, SilenceLoggerTestCaseMixin, ConnectionsCheckTestCaseMixin,
|
||||
RandomPrimaryKeyModelMonkeyPatchMixin, ACLTestCaseMixin,
|
||||
ModelTestCaseMixin, OpenFileCheckTestCaseMixin,
|
||||
TempfileCheckTestCasekMixin, UserTestMixin, TestCase
|
||||
ModelTestCaseMixin, OpenFileCheckTestCaseMixin, PermissionTestCaseMixin,
|
||||
SmartSettingsTestCaseMixin, TempfileCheckTestCasekMixin, UserTestMixin,
|
||||
TestCase
|
||||
):
|
||||
"""
|
||||
This is the most basic test case class any test in the project should use.
|
||||
"""
|
||||
assert_download_response = assert_download_response
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTestCase, self).setUp()
|
||||
Namespace.invalidate_cache_all()
|
||||
Permission.invalidate_cache()
|
||||
|
||||
|
||||
class GenericViewTestCase(
|
||||
ClientMethodsTestCaseMixin, ContentTypeCheckTestCaseMixin,
|
||||
|
||||
@@ -28,6 +28,12 @@ class CheckVersionView(SimpleView):
|
||||
'It is not possible to determine the latest version '
|
||||
'available.'
|
||||
)
|
||||
except Exception as exception:
|
||||
message = _(
|
||||
'Unexpected error trying to determine the latest version '
|
||||
'available. Make sure your installation has a connection to '
|
||||
'the internet; %s'
|
||||
) % exception
|
||||
else:
|
||||
message = _('Your version is up-to-date.')
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from ..classes import PermissionNamespace
|
||||
from ..classes import Permission, PermissionNamespace
|
||||
from ..models import Role
|
||||
|
||||
from .literals import (
|
||||
@@ -45,6 +45,12 @@ class PermissionTestMixin(object):
|
||||
)
|
||||
|
||||
|
||||
class PermissionTestCaseMixin(object):
|
||||
def setUp(self):
|
||||
super(PermissionTestCaseMixin, self).setUp()
|
||||
Permission.invalidate_cache()
|
||||
|
||||
|
||||
class RoleAPIViewTestMixin(object):
|
||||
def _request_test_role_create_api_view(self, extra_data=None):
|
||||
data = {
|
||||
|
||||
@@ -21,6 +21,7 @@ from mayan.apps.common.serialization import yaml_dump, yaml_load
|
||||
from .utils import read_configuration_file
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
SMART_SETTINGS_NAMESPACES_NAME = 'SMART_SETTINGS_NAMESPACES'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
@@ -39,26 +40,35 @@ class Namespace(object):
|
||||
exception
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
return cls._registry[name]
|
||||
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
return sorted(cls._registry.values(), key=lambda x: x.label)
|
||||
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
return cls._registry[name]
|
||||
def get_namespace_config(cls, name):
|
||||
return cls.get_namespaces_config().get(name, {})
|
||||
|
||||
@classmethod
|
||||
def get_namespaces_config(cls):
|
||||
return getattr(settings, SMART_SETTINGS_NAMESPACES_NAME, {})
|
||||
|
||||
@classmethod
|
||||
def invalidate_cache_all(cls):
|
||||
for namespace in cls.get_all():
|
||||
namespace.invalidate_cache()
|
||||
|
||||
def __init__(self, name, label):
|
||||
def __init__(self, name, label, version='0001'):
|
||||
if name in self.__class__._registry:
|
||||
raise Exception(
|
||||
'Namespace names must be unique; "%s" already exists.' % name
|
||||
)
|
||||
self.name = name
|
||||
self.label = label
|
||||
self.version = version
|
||||
self.__class__._registry[name] = self
|
||||
self._settings = []
|
||||
|
||||
@@ -68,6 +78,9 @@ class Namespace(object):
|
||||
def add_setting(self, **kwargs):
|
||||
return Setting(namespace=self, **kwargs)
|
||||
|
||||
def get_config_version(self):
|
||||
return Namespace.get_namespace_config(name=self.name).get('version', None)
|
||||
|
||||
def invalidate_cache(self):
|
||||
for setting in self._settings:
|
||||
setting.invalidate_cache()
|
||||
@@ -123,7 +136,18 @@ class Setting(object):
|
||||
def dump_data(cls, filter_term=None, namespace=None):
|
||||
dictionary = {}
|
||||
|
||||
if not namespace:
|
||||
namespace_dictionary = {}
|
||||
for _namespace in Namespace.get_all():
|
||||
namespace_dictionary[_namespace.name] = {
|
||||
'version': _namespace.version
|
||||
}
|
||||
|
||||
dictionary[SMART_SETTINGS_NAMESPACES_NAME] = namespace_dictionary
|
||||
|
||||
for setting in cls.get_all():
|
||||
# If a namespace is specified, filter the list by that namespace
|
||||
# otherwise return always True to include all (or not None == True)
|
||||
if (namespace and setting.namespace.name == namespace) or not namespace:
|
||||
if (filter_term and filter_term.lower() in setting.global_name.lower()) or not filter_term:
|
||||
dictionary[setting.global_name] = Setting.express_promises(setting.value)
|
||||
@@ -157,9 +181,12 @@ class Setting(object):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def save_configuration(cls, path=settings.CONFIGURATION_FILEPATH):
|
||||
def save_configuration(cls, path=None):
|
||||
if not path:
|
||||
path = settings.CONFIGURATION_FILEPATH
|
||||
|
||||
try:
|
||||
with open(path, 'w') as file_object:
|
||||
with open(path, mode='w') as file_object:
|
||||
file_object.write(cls.dump_data())
|
||||
except IOError as exception:
|
||||
if exception.errno == errno.ENOENT:
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core import management
|
||||
|
||||
from ...classes import Setting
|
||||
|
||||
|
||||
class Command(management.BaseCommand):
|
||||
help = 'Save the current settings into the configuration file.'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--filepath', action='store', dest='filepath',
|
||||
help='Filename and path where to save the configuration file.'
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
Setting.save_configuration(path=options.get('filepath'))
|
||||
@@ -5,6 +5,12 @@ from ..classes import Namespace
|
||||
from .literals import TEST_NAMESPACE_LABEL, TEST_NAMESPACE_NAME
|
||||
|
||||
|
||||
class SmartSettingsTestCaseMixin(object):
|
||||
def setUp(self):
|
||||
super(SmartSettingsTestCaseMixin, self).setUp()
|
||||
Namespace.invalidate_cache_all()
|
||||
|
||||
|
||||
class SmartSettingTestMixin(object):
|
||||
def _create_test_settings_namespace(self):
|
||||
try:
|
||||
|
||||
@@ -261,7 +261,14 @@ class IMAPEmail(EmailBaseModel):
|
||||
server = imaplib.IMAP4(host=self.host, port=self.port)
|
||||
|
||||
server.login(user=self.username, password=self.password)
|
||||
server.select(mailbox=self.mailbox)
|
||||
try:
|
||||
server.select(mailbox=self.mailbox)
|
||||
except Exception as exception:
|
||||
raise SourceException(
|
||||
'Error selecting mailbox: {}; {}'.format(
|
||||
self.mailbox, exception
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
status, data = server.uid(
|
||||
@@ -280,10 +287,26 @@ class IMAPEmail(EmailBaseModel):
|
||||
|
||||
for uid in uids:
|
||||
logger.debug('message uid: %s', uid)
|
||||
status, data = server.uid('FETCH', uid, '(RFC822)')
|
||||
EmailBaseModel.process_message(
|
||||
source=self, message_text=data[0][1]
|
||||
)
|
||||
|
||||
try:
|
||||
status, data = server.uid('FETCH', uid, '(RFC822)')
|
||||
except Exception as exception:
|
||||
raise SourceException(
|
||||
'Error fetching message uid: {}; {}'.format(
|
||||
uid, exception
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
EmailBaseModel.process_message(
|
||||
source=self, message_text=data[0][1]
|
||||
)
|
||||
except Exception as exception:
|
||||
raise SourceException(
|
||||
'Error processing message uid: {}; {}'.format(
|
||||
uid, exception
|
||||
)
|
||||
)
|
||||
|
||||
if not test:
|
||||
if self.store_commands:
|
||||
|
||||
Reference in New Issue
Block a user