Files
mayan-edms/mayan/apps/sources/tasks.py
Roberto Rosario 36a51eeb73 Switch to full app paths
Instead of inserting the path of the apps into the Python app,
the apps are now referenced by their full import path.

This solves name clashes with external or native Python libraries.
Example: Mayan statistics app vs. Python new statistics library.

Every app reference is now prepended with 'mayan.apps'.

Existing config.yml files need to be updated manually.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
2019-04-05 02:02:57 -04:00

211 lines
8.0 KiB
Python

import logging
from django.apps import apps
from django.contrib.auth import get_user_model
from django.core.files import File
from django.db import OperationalError
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from mayan.celery import app
from mayan.apps.common.compressed_files import Archive
from mayan.apps.common.exceptions import NoMIMETypeMatch
from mayan.apps.lock_manager import LockError
from mayan.apps.lock_manager.runtime import locking_backend
from .literals import (
DEFAULT_SOURCE_LOCK_EXPIRE, DEFAULT_SOURCE_TASK_RETRY_DELAY
)
logger = logging.getLogger(__name__)
@app.task(ignore_result=True)
def task_check_interval_source(source_id, test=False):
Source = apps.get_model(
app_label='sources', model_name='Source'
)
lock_id = 'task_check_interval_source-%d' % source_id
try:
logger.debug('trying to acquire lock: %s', lock_id)
lock = locking_backend.acquire_lock(lock_id, DEFAULT_SOURCE_LOCK_EXPIRE)
except LockError:
logger.debug('unable to obtain lock: %s' % lock_id)
else:
logger.debug('acquired lock: %s', lock_id)
try:
source = Source.objects.get_subclass(pk=source_id)
if source.enabled or test:
source.check_source(test=test)
except Exception as exception:
logger.error('Error processing source: %s; %s', source, exception)
source.logs.create(
message=_('Error processing source: %s') % exception
)
else:
source.logs.all().delete()
finally:
lock.release()
@app.task()
def task_generate_staging_file_image(staging_folder_pk, encoded_filename, *args, **kwargs):
StagingFolderSource = apps.get_model(
app_label='sources', model_name='StagingFolderSource'
)
staging_folder = StagingFolderSource.objects.get(pk=staging_folder_pk)
staging_file = staging_folder.get_file(encoded_filename=encoded_filename)
return staging_file.generate_image(*args, **kwargs)
@app.task(bind=True, default_retry_delay=DEFAULT_SOURCE_TASK_RETRY_DELAY, ignore_result=True)
def task_source_handle_upload(self, document_type_id, shared_uploaded_file_id, source_id, description=None, expand=False, label=None, language=None, querystring=None, skip_list=None, user_id=None):
SharedUploadedFile = apps.get_model(
app_label='common', model_name='SharedUploadedFile'
)
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
)
try:
document_type = DocumentType.objects.get(pk=document_type_id)
shared_upload = SharedUploadedFile.objects.get(
pk=shared_uploaded_file_id
)
if not label:
label = shared_upload.filename
except OperationalError as exception:
logger.warning(
'Operational error during attempt to load data to handle source '
'upload: %s. Retrying.', exception
)
raise self.retry(exc=exception)
kwargs = {
'description': description, 'document_type_id': document_type.pk,
'label': label, 'language': language, 'querystring': querystring,
'source_id': source_id, 'user_id': user_id
}
if not skip_list:
skip_list = []
with shared_upload.open() as file_object:
if expand:
try:
compressed_file = Archive.open(file_object=file_object)
for compressed_file_child in compressed_file.get_members():
# TODO: find way to uniquely identify child files
# Use filename in the meantime.
if force_text(compressed_file_child) not in skip_list:
kwargs.update(
{'label': force_text(compressed_file_child)}
)
try:
child_shared_uploaded_file = SharedUploadedFile.objects.create(
file=File(compressed_file_child)
)
except OperationalError as exception:
logger.warning(
'Operational error while preparing to upload '
'child document: %s. Rescheduling.', exception
)
# TODO: Don't call the task itself again
# Update to use celery's retry feature
task_source_handle_upload.delay(
document_type_id=document_type_id,
shared_uploaded_file_id=shared_uploaded_file_id,
source_id=source_id, description=description,
expand=expand, label=label,
language=language,
skip_list=skip_list, querystring=querystring,
user_id=user_id
)
return
else:
skip_list.append(force_text(compressed_file_child))
task_upload_document.delay(
shared_uploaded_file_id=child_shared_uploaded_file.pk,
**kwargs
)
finally:
compressed_file_child.close()
compressed_file_child.close()
try:
shared_upload.delete()
except OperationalError as exception:
logger.warning(
'Operational error during attempt to delete shared '
'upload file: %s; %s. Retrying.', shared_upload,
exception
)
except NoMIMETypeMatch:
logging.debug('Exception: NoMIMETypeMatch')
task_upload_document.delay(
shared_uploaded_file_id=shared_upload.pk, **kwargs
)
else:
task_upload_document.delay(
shared_uploaded_file_id=shared_upload.pk, **kwargs
)
@app.task(bind=True, default_retry_delay=DEFAULT_SOURCE_TASK_RETRY_DELAY, ignore_result=True)
def task_upload_document(self, source_id, document_type_id, shared_uploaded_file_id, description=None, label=None, language=None, querystring=None, user_id=None):
SharedUploadedFile = apps.get_model(
app_label='common', model_name='SharedUploadedFile'
)
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
)
Source = apps.get_model(
app_label='sources', model_name='Source'
)
try:
document_type = DocumentType.objects.get(pk=document_type_id)
source = Source.objects.get_subclass(pk=source_id)
shared_upload = SharedUploadedFile.objects.get(
pk=shared_uploaded_file_id
)
if user_id:
user = get_user_model().objects.get(pk=user_id)
else:
user = None
with shared_upload.open() as file_object:
source.upload_document(
file_object=file_object, document_type=document_type,
description=description, label=label, language=language,
querystring=querystring, user=user,
)
except OperationalError as exception:
logger.warning(
'Operational exception while trying to create new document "%s" '
'from source id %d; %s. Retying.',
label or shared_upload.filename, source_id, exception
)
raise self.retry(exc=exception)
else:
try:
shared_upload.delete()
except OperationalError as exception:
logger.warning(
'Operational error during attempt to delete shared upload '
'file: %s; %s. Retrying.', shared_upload, exception
)