Add file caching app

Convert document image cache to use file cache manager app.
Add setting DOCUMENTS_CACHE_MAXIMUM_SIZE defaults to 500 MB.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2019-07-15 01:33:32 -04:00
parent 3c7a23a5a9
commit 8c064c953a
42 changed files with 2001 additions and 114 deletions

View File

@@ -115,6 +115,12 @@ source_lang = en
source_file = mayan/apps/events/locale/en/LC_MESSAGES/django.po source_file = mayan/apps/events/locale/en/LC_MESSAGES/django.po
type = PO type = PO
[mayan-edms.file_caching-3-0]
file_filter = mayan/apps/file_caching/locale/<lang>/LC_MESSAGES/django.po
source_lang = en
source_file = mayan/apps/file_caching/locale/en/LC_MESSAGES/django.po
type = PO
[mayan-edms.file_metadata-3-0] [mayan-edms.file_metadata-3-0]
file_filter = mayan/apps/file_metadata/locale/<lang>/LC_MESSAGES/django.po file_filter = mayan/apps/file_metadata/locale/<lang>/LC_MESSAGES/django.po
source_lang = en source_lang = en

View File

@@ -36,6 +36,10 @@
- Remove encapsulate helper. - Remove encapsulate helper.
- Add support for menu inheritance. - Add support for menu inheritance.
- Emphasize source column labels. - Emphasize source column labels.
- Backport file cache manager app.
- Convert document image cache to use file cache manager app.
Add setting DOCUMENTS_CACHE_MAXIMUM_SIZE defaults to 500 MB.
3.2.6 (2019-07-10) 3.2.6 (2019-07-10)
================== ==================

View File

@@ -13,11 +13,11 @@ APP_LIST = (
'checkouts', 'common', 'converter', 'dashboards', 'dependencies', 'checkouts', 'common', 'converter', 'dashboards', 'dependencies',
'django_gpg', 'document_comments', 'document_indexing', 'django_gpg', 'document_comments', 'document_indexing',
'document_parsing', 'document_signatures', 'document_states', 'document_parsing', 'document_signatures', 'document_states',
'documents', 'dynamic_search', 'events', 'file_metadata', 'linking', 'documents', 'dynamic_search', 'events', 'file_caching',
'lock_manager', 'mailer', 'mayan_statistics', 'metadata', 'mirroring', 'file_metadata', 'linking', 'lock_manager', 'mailer',
'motd', 'navigation', 'ocr', 'permissions', 'platform', 'rest_api', 'mayan_statistics', 'metadata', 'mirroring', 'motd', 'navigation',
'smart_settings', 'sources', 'storage', 'tags', 'task_manager', 'ocr', 'permissions', 'platform', 'rest_api', 'smart_settings',
'user_management' 'sources', 'storage', 'tags', 'task_manager', 'user_management'
) )
LANGUAGE_LIST = ( LANGUAGE_LIST = (

View File

@@ -49,6 +49,10 @@ Changes
- Remove encapsulate helper. - Remove encapsulate helper.
- Add support for menu inheritance. - Add support for menu inheritance.
- Emphasize source column labels. - Emphasize source column labels.
- Backport file cache manager app.
- Convert document image cache to use file cache manager app.
Add setting DOCUMENTS_CACHE_MAXIMUM_SIZE defaults to 500 MB.
Removals Removals
-------- --------

View File

@@ -36,7 +36,6 @@ from .serializers import (
WritableDocumentTypeSerializer, WritableDocumentVersionSerializer WritableDocumentTypeSerializer, WritableDocumentVersionSerializer
) )
from .settings import settings_document_page_image_cache_time from .settings import settings_document_page_image_cache_time
from .storages import storage_documentimagecache
from .tasks import task_generate_document_page_image from .tasks import task_generate_document_page_image
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -205,11 +204,13 @@ class APIDocumentPageImageView(generics.RetrieveAPIView):
) )
cache_filename = task.get(timeout=DOCUMENT_IMAGE_TASK_TIMEOUT) cache_filename = task.get(timeout=DOCUMENT_IMAGE_TASK_TIMEOUT)
with storage_documentimagecache.open(cache_filename) as file_object: cache_file = self.get_object().cache_partition.get_file(filename=cache_filename)
with cache_file.open() as file_object:
response = HttpResponse(file_object.read(), content_type='image') response = HttpResponse(file_object.read(), content_type='image')
if '_hash' in request.GET: if '_hash' in request.GET:
patch_cache_control( patch_cache_control(
response, max_age=settings_document_page_image_cache_time.value response=response,
max_age=settings_document_page_image_cache_time.value
) )
return response return response

View File

@@ -1,6 +1,6 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.db.models.signals import post_delete from django.db.models.signals import post_delete, post_migrate
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.classes import ModelPermission from mayan.apps.acls.classes import ModelPermission
@@ -43,8 +43,8 @@ from .events import (
event_document_view event_document_view
) )
from .handlers import ( from .handlers import (
handler_create_default_document_type, handler_remove_empty_duplicates_lists, handler_create_default_document_type, handler_create_document_cache,
handler_scan_duplicates_for, handler_remove_empty_duplicates_lists, handler_scan_duplicates_for
) )
from .links import ( from .links import (
link_clear_image_cache, link_document_clear_transformations, link_clear_image_cache, link_document_clear_transformations,
@@ -527,6 +527,10 @@ class DocumentsApp(MayanAppConfig):
dispatch_uid='handler_create_default_document_type', dispatch_uid='handler_create_default_document_type',
receiver=handler_create_default_document_type receiver=handler_create_default_document_type
) )
post_migrate.connect(
dispatch_uid='documents_handler_create_document_cache',
receiver=handler_create_document_cache,
)
post_version_upload.connect( post_version_upload.connect(
dispatch_uid='handler_scan_duplicates_for', dispatch_uid='handler_scan_duplicates_for',
receiver=handler_scan_duplicates_for receiver=handler_scan_duplicates_for

View File

@@ -1,8 +1,13 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.apps import apps from django.apps import apps
from django.utils.translation import ugettext_lazy as _
from .literals import DEFAULT_DOCUMENT_TYPE_LABEL from .literals import (
DEFAULT_DOCUMENT_TYPE_LABEL, DOCUMENT_CACHE_STORAGE_INSTANCE_PATH,
DOCUMENT_IMAGES_CACHE_NAME
)
from .settings import setting_document_cache_maximum_size
from .signals import post_initial_document_type from .signals import post_initial_document_type
from .tasks import task_clean_empty_duplicate_lists, task_scan_duplicates_for from .tasks import task_clean_empty_duplicate_lists, task_scan_duplicates_for
@@ -21,6 +26,17 @@ def handler_create_default_document_type(sender, **kwargs):
) )
def handler_create_document_cache(sender, **kwargs):
Cache = apps.get_model(app_label='file_caching', model_name='Cache')
Cache.objects.update_or_create(
defaults={
'label': _('Document images'),
'storage_instance_path': DOCUMENT_CACHE_STORAGE_INSTANCE_PATH,
'maximum_size': setting_document_cache_maximum_size.value,
}, name=DOCUMENT_IMAGES_CACHE_NAME,
)
def handler_scan_duplicates_for(sender, instance, **kwargs): def handler_scan_duplicates_for(sender, instance, **kwargs):
task_scan_duplicates_for.apply_async( task_scan_duplicates_for.apply_async(
kwargs={'document_id': instance.document.pk} kwargs={'document_id': instance.document.pk}

View File

@@ -9,6 +9,7 @@ CHECK_TRASH_PERIOD_INTERVAL = 60
DELETE_STALE_STUBS_INTERVAL = 60 * 10 # 10 minutes DELETE_STALE_STUBS_INTERVAL = 60 * 10 # 10 minutes
DEFAULT_DELETE_PERIOD = 30 DEFAULT_DELETE_PERIOD = 30
DEFAULT_DELETE_TIME_UNIT = TIME_DELTA_UNIT_DAYS DEFAULT_DELETE_TIME_UNIT = TIME_DELTA_UNIT_DAYS
DEFAULT_DOCUMENTS_CACHE_MAXIMUM_SIZE = 500 * 2 ** 20 # 500 Megabytes
DEFAULT_DOCUMENTS_HASH_BLOCK_SIZE = 65535 DEFAULT_DOCUMENTS_HASH_BLOCK_SIZE = 65535
DEFAULT_LANGUAGE = 'eng' DEFAULT_LANGUAGE = 'eng'
DEFAULT_LANGUAGE_CODES = ( DEFAULT_LANGUAGE_CODES = (
@@ -30,6 +31,8 @@ DEFAULT_LANGUAGE_CODES = (
DEFAULT_ZIP_FILENAME = 'document_bundle.zip' DEFAULT_ZIP_FILENAME = 'document_bundle.zip'
DEFAULT_DOCUMENT_TYPE_LABEL = _('Default') DEFAULT_DOCUMENT_TYPE_LABEL = _('Default')
DOCUMENT_IMAGE_TASK_TIMEOUT = 120 DOCUMENT_IMAGE_TASK_TIMEOUT = 120
DOCUMENT_IMAGES_CACHE_NAME = 'document_images'
DOCUMENT_CACHE_STORAGE_INSTANCE_PATH = 'mayan.apps.documents.storages.storage_documentimagecache'
STUB_EXPIRATION_INTERVAL = 60 * 60 * 24 # 24 hours STUB_EXPIRATION_INTERVAL = 60 * 60 * 24 # 24 hours
UPDATE_PAGE_COUNT_RETRY_DELAY = 10 UPDATE_PAGE_COUNT_RETRY_DELAY = 10
UPLOAD_NEW_VERSION_RETRY_DELAY = 10 UPLOAD_NEW_VERSION_RETRY_DELAY = 10

View File

@@ -0,0 +1,37 @@
from __future__ import unicode_literals
from django.db import migrations
from ..storages import storage_documentimagecache
def operation_clear_old_cache(apps, schema_editor):
DocumentPageCachedImage = apps.get_model(
'documents', 'DocumentPageCachedImage'
)
for cached_image in DocumentPageCachedImage.objects.using(schema_editor.connection.alias).all():
# Delete each cached image directly since the model doesn't exists and
# will not trigger the physical deletion of the stored file
storage_documentimagecache.delete(cached_image.filename)
cached_image.delete()
class Migration(migrations.Migration):
dependencies = [
('documents', '0048_auto_20190711_0544'),
]
operations = [
migrations.RunPython(
code=operation_clear_old_cache,
reverse_code=migrations.RunPython.noop
),
migrations.RemoveField(
model_name='documentpagecachedimage',
name='document_page',
),
migrations.DeleteModel(
name='DocumentPageCachedImage',
),
]

View File

@@ -4,13 +4,14 @@ import logging
from furl import furl from furl import furl
from django.core.files.base import ContentFile
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from mayan.apps.converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION from mayan.apps.converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION
from mayan.apps.converter.models import Transformation from mayan.apps.converter.models import Transformation
from mayan.apps.converter.transformations import ( from mayan.apps.converter.transformations import (
BaseTransformation, TransformationResize, TransformationRotate, BaseTransformation, TransformationResize, TransformationRotate,
@@ -24,7 +25,6 @@ from ..settings import (
setting_display_width, setting_display_height, setting_zoom_max_level, setting_display_width, setting_display_height, setting_zoom_max_level,
setting_zoom_min_level setting_zoom_min_level
) )
from ..storages import storage_documentimagecache
from .document_version_models import DocumentVersion from .document_version_models import DocumentVersion
@@ -56,9 +56,12 @@ class DocumentPage(models.Model):
def __str__(self): def __str__(self):
return self.get_label() return self.get_label()
@property @cached_property
def cache_filename(self): def cache_partition(self):
return 'page-cache-{}'.format(self.uuid) partition, created = self.document_version.cache.partitions.get_or_create(
name=self.uuid
)
return partition
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
self.invalidate_cache() self.invalidate_cache()
@@ -80,29 +83,24 @@ class DocumentPage(models.Model):
def generate_image(self, *args, **kwargs): def generate_image(self, *args, **kwargs):
transformation_list = self.get_combined_transformation_list(*args, **kwargs) transformation_list = self.get_combined_transformation_list(*args, **kwargs)
combined_cache_filename = BaseTransformation.combine(transformation_list)
cache_filename = '{}-{}'.format(
self.cache_filename, BaseTransformation.combine(transformation_list)
)
# Check is transformed image is available # Check is transformed image is available
logger.debug('transformations cache filename: %s', cache_filename) logger.debug('transformations cache filename: %s', combined_cache_filename)
if not setting_disable_transformed_image_cache.value and storage_documentimagecache.exists(cache_filename): if not setting_disable_transformed_image_cache.value and self.cache_partition.get_file(filename=combined_cache_filename):
logger.debug( logger.debug(
'transformations cache file "%s" found', cache_filename 'transformations cache file "%s" found', combined_cache_filename
) )
else: else:
logger.debug( logger.debug(
'transformations cache file "%s" not found', cache_filename 'transformations cache file "%s" not found', combined_cache_filename
) )
image = self.get_image(transformations=transformation_list) image = self.get_image(transformations=transformation_list)
with storage_documentimagecache.open(cache_filename, 'wb+') as file_object: with self.cache_partition.create_file(filename=combined_cache_filename) as file_object:
file_object.write(image.getvalue()) file_object.write(image.getvalue())
self.cached_images.create(filename=cache_filename) return combined_cache_filename
return cache_filename
def get_absolute_url(self): def get_absolute_url(self):
return reverse( return reverse(
@@ -159,7 +157,6 @@ class DocumentPage(models.Model):
zoom_level = setting_zoom_max_level.value zoom_level = setting_zoom_max_level.value
# Generate transformation hash # Generate transformation hash
transformation_list = [] transformation_list = []
# Stored transformations first # Stored transformations first
@@ -186,13 +183,15 @@ class DocumentPage(models.Model):
return transformation_list return transformation_list
def get_image(self, transformations=None): def get_image(self, transformations=None):
cache_filename = self.cache_filename cache_filename = 'base_image'
logger.debug('Page cache filename: %s', cache_filename) logger.debug('Page cache filename: %s', cache_filename)
if not setting_disable_base_image_cache.value and storage_documentimagecache.exists(cache_filename): cache_file = self.cache_partition.get_file(filename=cache_filename)
if not setting_disable_base_image_cache.value and cache_file:
logger.debug('Page cache file "%s" found', cache_filename) logger.debug('Page cache file "%s" found', cache_filename)
with storage_documentimagecache.open(cache_filename) as file_object: with cache_file.open as file_object:
converter = get_converter_class()( converter = get_converter_class()(
file_object=file_object file_object=file_object
) )
@@ -200,8 +199,8 @@ class DocumentPage(models.Model):
converter.seek_page(page_number=0) converter.seek_page(page_number=0)
# This code is also repeated below to allow using a context # This code is also repeated below to allow using a context
# manager with storage_documentimagecache.open and close it # manager with cache_file.open and close it automatically.
# automatically. # Apply runtime transformations
for transformation in transformations: for transformation in transformations:
converter.transform(transformation=transformation) converter.transform(transformation=transformation)
@@ -218,14 +217,11 @@ class DocumentPage(models.Model):
page_image = converter.get_page() page_image = converter.get_page()
# Since open "wb+" doesn't create files, check if the file # Since open "wb+" doesn't create files, create it explicitly
# exists, if not then create it with self.cache_partition.create_file(filename=cache_filename) as file_object:
if not storage_documentimagecache.exists(cache_filename):
storage_documentimagecache.save(name=cache_filename, content=ContentFile(content=''))
with storage_documentimagecache.open(cache_filename, 'wb+') as file_object:
file_object.write(page_image.getvalue()) file_object.write(page_image.getvalue())
# Apply runtime transformations
for transformation in transformations: for transformation in transformations:
converter.transform(transformation=transformation) converter.transform(transformation=transformation)
@@ -236,13 +232,10 @@ class DocumentPage(models.Model):
'Error creating page cache file "%s"; %s', 'Error creating page cache file "%s"; %s',
cache_filename, exception cache_filename, exception
) )
storage_documentimagecache.delete(cache_filename)
raise raise
def invalidate_cache(self): def invalidate_cache(self):
storage_documentimagecache.delete(self.cache_filename) self.cache_partition.purge()
for cached_image in self.cached_images.all():
cached_image.delete()
@property @property
def is_in_trash(self): def is_in_trash(self):
@@ -277,38 +270,6 @@ class DocumentPage(models.Model):
return '{}-{}'.format(self.document_version.uuid, self.pk) return '{}-{}'.format(self.document_version.uuid, self.pk)
class DocumentPageCachedImage(models.Model):
document_page = models.ForeignKey(
on_delete=models.CASCADE, related_name='cached_images',
to=DocumentPage, verbose_name=_('Document page')
)
datetime = models.DateTimeField(
auto_now_add=True, db_index=True, verbose_name=_('Date time')
)
filename = models.CharField(max_length=128, verbose_name=_('Filename'))
file_size = models.PositiveIntegerField(
db_index=True, default=0, verbose_name=_('File size')
)
objects = DocumentPageCachedImage()
class Meta:
verbose_name = _('Document page cached image')
verbose_name_plural = _('Document page cached images')
def delete(self, *args, **kwargs):
storage_documentimagecache.delete(self.filename)
return super(DocumentPageCachedImage, self).delete(*args, **kwargs)
def natural_key(self):
return (self.filename, self.document_page.natural_key())
natural_key.dependencies = ['documents.DocumentPage']
def save(self, *args, **kwargs):
self.file_size = storage_documentimagecache.size(self.filename)
return super(DocumentPageCachedImage, self).save(*args, **kwargs)
class DocumentPageResult(DocumentPage): class DocumentPageResult(DocumentPage):
class Meta: class Meta:
ordering = ('document_version__document', 'page_number') ordering = ('document_version__document', 'page_number')

View File

@@ -7,11 +7,11 @@ import shutil
import uuid import uuid
from django.apps import apps from django.apps import apps
from django.core.files.base import ContentFile
from django.db import models, transaction from django.db import models, transaction
from django.template import Template, Context from django.template import Template, Context
from django.urls import reverse from django.urls import reverse
from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from mayan.apps.converter.exceptions import InvalidOfficeFormat, PageCountError from mayan.apps.converter.exceptions import InvalidOfficeFormat, PageCountError
@@ -21,10 +21,11 @@ from mayan.apps.converter.utils import get_converter_class
from mayan.apps.mimetype.api import get_mimetype from mayan.apps.mimetype.api import get_mimetype
from ..events import event_document_new_version, event_document_version_revert from ..events import event_document_new_version, event_document_version_revert
from ..literals import DOCUMENT_IMAGES_CACHE_NAME
from ..managers import DocumentVersionManager from ..managers import DocumentVersionManager
from ..settings import setting_fix_orientation, setting_hash_block_size from ..settings import setting_fix_orientation, setting_hash_block_size
from ..signals import post_document_created, post_version_upload from ..signals import post_document_created, post_version_upload
from ..storages import storage_documentversion, storage_documentimagecache from ..storages import storage_documentversion
from .document_models import Document from .document_models import Document
@@ -61,14 +62,6 @@ class DocumentVersion(models.Model):
_pre_open_hooks = {} _pre_open_hooks = {}
_post_save_hooks = {} _post_save_hooks = {}
@classmethod
def register_pre_open_hook(cls, order, func):
cls._pre_open_hooks[order] = func
@classmethod
def register_post_save_hook(cls, order, func):
cls._post_save_hooks[order] = func
document = models.ForeignKey( document = models.ForeignKey(
on_delete=models.CASCADE, related_name='versions', to=Document, on_delete=models.CASCADE, related_name='versions', to=Document,
verbose_name=_('Document') verbose_name=_('Document')
@@ -118,12 +111,28 @@ class DocumentVersion(models.Model):
objects = DocumentVersionManager() objects = DocumentVersionManager()
@classmethod
def register_pre_open_hook(cls, order, func):
cls._pre_open_hooks[order] = func
@classmethod
def register_post_save_hook(cls, order, func):
cls._post_save_hooks[order] = func
def __str__(self): def __str__(self):
return self.get_rendered_string() return self.get_rendered_string()
@property @cached_property
def cache_filename(self): def cache(self):
return 'document-version-{}'.format(self.uuid) Cache = apps.get_model(app_label='file_caching', model_name='Cache')
return Cache.objects.get(name=DOCUMENT_IMAGES_CACHE_NAME)
@cached_property
def cache_partition(self):
partition, created = self.cache.partitions.get_or_create(
name='version-{}'.format(self.uuid)
)
return partition
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
for page in self.pages.all(): for page in self.pages.all():
@@ -164,43 +173,36 @@ class DocumentVersion(models.Model):
return first_page.get_api_image_url(*args, **kwargs) return first_page.get_api_image_url(*args, **kwargs)
def get_intermediate_file(self): def get_intermediate_file(self):
cache_filename = self.cache_filename cache_filename = 'intermediate_file'
logger.debug('Intermidiate filename: %s', cache_filename) cache_file = self.cache_partition.get_file(filename=cache_filename)
if cache_file:
if storage_documentimagecache.exists(cache_filename): logger.debug('Intermidiate file found.')
logger.debug('Intermidiate file "%s" found.', cache_filename) return cache_file.open()
return storage_documentimagecache.open(cache_filename)
else: else:
logger.debug('Intermidiate file "%s" not found.', cache_filename) logger.debug('Intermidiate file not found.')
try: try:
with self.open() as version_file_object: with self.open() as version_file_object:
converter = get_converter_class()(file_object=version_file_object) converter = get_converter_class()(
file_object=version_file_object
)
with converter.to_pdf() as pdf_file_object: with converter.to_pdf() as pdf_file_object:
with self.cache_partition.create_file(filename=cache_filename) as file_object:
# Since open "wb+" doesn't create files, check if the file
# exists, if not then create it
if not storage_documentimagecache.exists(cache_filename):
storage_documentimagecache.save(
name=cache_filename, content=ContentFile(content='')
)
with storage_documentimagecache.open(cache_filename, mode='wb+') as file_object:
shutil.copyfileobj( shutil.copyfileobj(
fsrc=pdf_file_object, fdst=file_object fsrc=pdf_file_object, fdst=file_object
) )
return storage_documentimagecache.open(cache_filename) return self.cache_partition.get_file(filename=cache_filename).open()
except InvalidOfficeFormat: except InvalidOfficeFormat:
return self.open() return self.open()
except Exception as exception: except Exception as exception:
# Cleanup in case of error
logger.error( logger.error(
'Error creating intermediate file "%s"; %s.', 'Error creating intermediate file "%s"; %s.',
cache_filename, exception cache_filename, exception
) )
storage_documentimagecache.delete(cache_filename) cache_file = self.cache_partition.get_file(filename=cache_filename)
if cache_file:
cache_file.delete()
raise raise
def get_rendered_string(self, preserve_extension=False): def get_rendered_string(self, preserve_extension=False):
@@ -224,7 +226,7 @@ class DocumentVersion(models.Model):
natural_key.dependencies = ['documents.Document'] natural_key.dependencies = ['documents.Document']
def invalidate_cache(self): def invalidate_cache(self):
storage_documentimagecache.delete(self.cache_filename) self.cache_partition.purge()
for page in self.pages.all(): for page in self.pages.all():
page.invalidate_cache() page.invalidate_cache()

View File

@@ -8,11 +8,22 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.smart_settings.classes import Namespace from mayan.apps.smart_settings.classes import Namespace
from .literals import ( from .literals import (
DEFAULT_DOCUMENTS_HASH_BLOCK_SIZE, DEFAULT_LANGUAGE, DEFAULT_LANGUAGE_CODES DEFAULT_DOCUMENTS_CACHE_MAXIMUM_SIZE, DEFAULT_DOCUMENTS_HASH_BLOCK_SIZE,
DEFAULT_LANGUAGE, DEFAULT_LANGUAGE_CODES
) )
from .utils import callback_update_cache_size
namespace = Namespace(label=_('Documents'), name='documents') namespace = Namespace(label=_('Documents'), name='documents')
setting_document_cache_maximum_size = namespace.add_setting(
global_name='DOCUMENTS_CACHE_MAXIMUM_SIZE',
default=DEFAULT_DOCUMENTS_CACHE_MAXIMUM_SIZE,
help_text=_(
'The threshold at which the DOCUMENT_CACHE_STORAGE_BACKEND will start '
'deleting the oldest document image cache files. Specify the size in '
'bytes.'
), post_edit_function=callback_update_cache_size
)
setting_documentimagecache_storage = namespace.add_setting( setting_documentimagecache_storage = namespace.add_setting(
global_name='DOCUMENTS_CACHE_STORAGE_BACKEND', global_name='DOCUMENTS_CACHE_STORAGE_BACKEND',
default='django.core.files.storage.FileSystemStorage', help_text=_( default='django.core.files.storage.FileSystemStorage', help_text=_(

View File

@@ -2,9 +2,17 @@ from __future__ import unicode_literals
import pycountry import pycountry
from django.apps import apps
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .settings import setting_language_codes from .literals import DOCUMENT_IMAGES_CACHE_NAME
def callback_update_cache_size(setting):
Cache = apps.get_model(app_label='common', model_name='Cache')
cache = Cache.objects.get(name=DOCUMENT_IMAGES_CACHE_NAME)
cache.maximum_size = setting.value
cache.save()
def get_language(language_code): def get_language(language_code):
@@ -19,6 +27,8 @@ def get_language(language_code):
def get_language_choices(): def get_language_choices():
from .settings import setting_language_codes
return sorted( return sorted(
[ [
( (

View File

@@ -0,0 +1,3 @@
from __future__ import unicode_literals
default_app_config = 'mayan.apps.file_caching.apps.FileCachingConfig'

View File

@@ -0,0 +1,10 @@
from __future__ import unicode_literals
from django.contrib import admin
from .models import Cache
@admin.register(Cache)
class CacheAdmin(admin.ModelAdmin):
list_display = ('name', 'label', 'storage_instance_path', 'maximum_size')

View File

@@ -0,0 +1,8 @@
from __future__ import unicode_literals
from mayan.apps.common.apps import MayanAppConfig
class FileCachingConfig(MayanAppConfig):
has_tests = False
name = 'mayan.apps.file_caching'

View File

@@ -0,0 +1,72 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,73 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n"
"%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,73 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-07 21:32-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:23 models.py:70
msgid "Name"
msgstr ""
#: models.py:25
msgid "Label"
msgstr ""
#: models.py:26
msgid "Maximum size"
msgstr ""
#: models.py:28
msgid "Storage instance path"
msgstr ""
#: models.py:32 models.py:67
msgid "Cache"
msgstr ""
#: models.py:33
msgid "Caches"
msgstr ""
#: models.py:75 models.py:141
msgid "Cache partition"
msgstr ""
#: models.py:76
msgid "Cache partitions"
msgstr ""
#: models.py:144
msgid "Date time"
msgstr ""
#: models.py:146
msgid "Filename"
msgstr ""
#: models.py:148
msgid "File size"
msgstr ""
#: models.py:154
msgid "Cache partition file"
msgstr ""
#: models.py:155
msgid "Cache partition files"
msgstr ""

View File

@@ -0,0 +1,64 @@
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Cache',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
('label', models.CharField(max_length=128, verbose_name='Label')),
('maximum_size', models.PositiveIntegerField(verbose_name='Maximum size')),
('storage_instance_path', models.CharField(max_length=255, unique=True, verbose_name='Storage instance path')),
],
options={
'verbose_name': 'Cache',
'verbose_name_plural': 'Caches',
},
),
migrations.CreateModel(
name='CachePartition',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('cache', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='partitions', to='file_caching.Cache', verbose_name='Cache')),
],
options={
'verbose_name': 'Cache partition',
'verbose_name_plural': 'Cache partitions',
},
),
migrations.CreateModel(
name='CachePartitionFile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('datetime', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Date time')),
('filename', models.CharField(max_length=255, verbose_name='Filename')),
('file_size', models.PositiveIntegerField(default=0, verbose_name='File size')),
('partition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='file_caching.CachePartition', verbose_name='Cache partition')),
],
options={
'get_latest_by': 'datetime',
'verbose_name': 'Cache partition file',
'verbose_name_plural': 'Cache partition files',
},
),
migrations.AlterUniqueTogether(
name='cachepartitionfile',
unique_together=set([('partition', 'filename')]),
),
migrations.AlterUniqueTogether(
name='cachepartition',
unique_together=set([('cache', 'name')]),
),
]

View File

@@ -0,0 +1,184 @@
from __future__ import unicode_literals
from contextlib import contextmanager
import logging
from django.core.files.base import ContentFile
from django.db import models, transaction
from django.db.models import Sum
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.module_loading import import_string
from django.utils.translation import ugettext_lazy as _
from mayan.apps.lock_manager.exceptions import LockError
from mayan.apps.lock_manager.runtime import locking_backend
logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class Cache(models.Model):
name = models.CharField(
max_length=128, unique=True, verbose_name=_('Name')
)
label = models.CharField(max_length=128, verbose_name=_('Label'))
maximum_size = models.PositiveIntegerField(verbose_name=_('Maximum size'))
storage_instance_path = models.CharField(
max_length=255, unique=True, verbose_name=_('Storage instance path')
)
class Meta:
verbose_name = _('Cache')
verbose_name_plural = _('Caches')
def __str__(self):
return self.label
def get_files(self):
return CachePartitionFile.objects.filter(partition__cache__id=self.pk)
def get_total_size(self):
return self.get_files().aggregate(
file_size__sum=Sum('file_size')
)['file_size__sum'] or 0
def prune(self):
while self.get_total_size() > self.maximum_size:
self.get_files().earliest().delete()
def purge(self):
for partition in self.partitions.all():
partition.purge()
def save(self, *args, **kwargs):
result = super(Cache, self).save(*args, **kwargs)
self.prune()
return result
@cached_property
def storage(self):
return import_string(self.storage_instance_path)
class CachePartition(models.Model):
cache = models.ForeignKey(
on_delete=models.CASCADE, related_name='partitions',
to=Cache, verbose_name=_('Cache')
)
name = models.CharField(
max_length=128, verbose_name=_('Name')
)
class Meta:
unique_together = ('cache', 'name')
verbose_name = _('Cache partition')
verbose_name_plural = _('Cache partitions')
@staticmethod
def get_combined_filename(parent, filename):
return '{}-{}'.format(parent, filename)
@contextmanager
def create_file(self, filename):
lock_id = 'cache_partition-create_file-{}-{}'.format(self.pk, filename)
try:
logger.debug('trying to acquire lock: %s', lock_id)
lock = locking_backend.acquire_lock(lock_id)
logger.debug('acquired lock: %s', lock_id)
try:
self.cache.prune()
# Since open "wb+" doesn't create files force the creation of an
# empty file.
self.cache.storage.delete(
name=self.get_full_filename(filename=filename)
)
self.cache.storage.save(
name=self.get_full_filename(filename=filename),
content=ContentFile(content='')
)
try:
with transaction.atomic():
partition_file = self.files.create(filename=filename)
yield partition_file.open(mode='wb')
partition_file.update_size()
except Exception as exception:
logger.error(
'Unexpected exception while trying to save new '
'cache file; %s', exception
)
self.cache.storage.delete(
name=self.get_full_filename(filename=filename)
)
raise
finally:
lock.release()
except LockError:
logger.debug('unable to obtain lock: %s' % lock_id)
raise
def get_file(self, filename):
try:
return self.files.get(filename=filename)
except self.files.model.DoesNotExist:
return None
def get_full_filename(self, filename):
return CachePartition.get_combined_filename(
parent=self.name, filename=filename
)
def purge(self):
for parition_file in self.files.all():
parition_file.delete()
class CachePartitionFile(models.Model):
partition = models.ForeignKey(
on_delete=models.CASCADE, related_name='files',
to=CachePartition, verbose_name=_('Cache partition')
)
datetime = models.DateTimeField(
auto_now_add=True, db_index=True, verbose_name=_('Date time')
)
filename = models.CharField(max_length=255, verbose_name=_('Filename'))
file_size = models.PositiveIntegerField(
default=0, verbose_name=_('File size')
)
class Meta:
get_latest_by = 'datetime'
unique_together = ('partition', 'filename')
verbose_name = _('Cache partition file')
verbose_name_plural = _('Cache partition files')
def delete(self, *args, **kwargs):
self.partition.cache.storage.delete(name=self.full_filename)
return super(CachePartitionFile, self).delete(*args, **kwargs)
@cached_property
def full_filename(self):
return CachePartition.get_combined_filename(
parent=self.partition.name, filename=self.filename
)
def open(self, mode='rb'):
# Open the file for reading. If the file is written to, the
# .update_size() must be called.
try:
return self.partition.cache.storage.open(
name=self.full_filename, mode=mode
)
except Exception as exception:
logger.error(
'Unexpected exception opening the cache file; %s', exception
)
raise
def update_size(self):
self.file_size = self.partition.cache.storage.size(
name=self.full_filename
)
self.save()

View File

@@ -95,6 +95,7 @@ INSTALLED_APPS = (
'mayan.apps.django_gpg', 'mayan.apps.django_gpg',
'mayan.apps.dynamic_search', 'mayan.apps.dynamic_search',
'mayan.apps.events', 'mayan.apps.events',
'mayan.apps.file_caching',
'mayan.apps.lock_manager', 'mayan.apps.lock_manager',
'mayan.apps.mimetype', 'mayan.apps.mimetype',
'mayan.apps.navigation', 'mayan.apps.navigation',