diff --git a/mayan/apps/documents/managers.py b/mayan/apps/documents/managers.py index 2f7bd3434f..32754e4a57 100644 --- a/mayan/apps/documents/managers.py +++ b/mayan/apps/documents/managers.py @@ -1,9 +1,11 @@ from __future__ import unicode_literals +from datetime import timedelta import logging from django.apps import apps from django.db import models +from django.utils.timezone import now from .settings import setting_recent_count @@ -39,6 +41,68 @@ class DocumentTypeManager(models.Manager): def get_by_natural_key(self, name): return self.get(name=name) + def check_delete_periods(self): + logger.info('Executing') + + for document_type in self.all(): + logger.info( + 'Checking deletion period of document type: %s', document_type + ) + if document_type.delete_time_period and document_type.delete_time_unit: + delta = timedelta( + **{ + document_type.delete_time_unit: document_type.delete_time_period + } + ) + logger.info( + 'Document type: %s, has a deletion period delta of: %s', + document_type, delta + ) + for document in document_type.deleted_documents.filter(deleted_date_time__lt=now() - delta): + logger.info( + 'Document "%s" with id: %d, trashed on: %s, exceded ' + 'delete period', document, document.pk, + document.deleted_date_time + ) + document.delete() + else: + logger.info( + 'Document type: %s, has a no retention delta', document_type + ) + + logger.info('Finshed') + + def check_trash_periods(self): + logger.info('Executing') + + for document_type in self.all(): + logger.info( + 'Checking trash period of document type: %s', document_type + ) + if document_type.trash_time_period and document_type.trash_time_unit: + delta = timedelta( + **{ + document_type.trash_time_unit: document_type.trash_time_period + } + ) + logger.info( + 'Document type: %s, has a trash period delta of: %s', + document_type, delta + ) + for document in document_type.documents.filter(date_added__lt=now() - delta): + logger.info( + 'Document "%s" with id: %d, added on: %s, exceded ' + 'trash period', document, document.pk, + document.date_added + ) + document.delete() + else: + logger.info( + 'Document type: %s, has a no retention delta', document_type + ) + + logger.info('Finshed') + class DocumentManager(models.Manager): def get_queryset(self): diff --git a/mayan/apps/documents/models.py b/mayan/apps/documents/models.py index 95c741b75c..8a3c66c57f 100644 --- a/mayan/apps/documents/models.py +++ b/mayan/apps/documents/models.py @@ -100,6 +100,10 @@ class DocumentType(models.Model): return super(DocumentType, self).delete(*args, **kwargs) + @property + def deleted_documents(self): + return DeletedDocument.objects.filter(document_type=self) + def new_document(self, file_object, label=None, description=None, language=None, _user=None): try: with transaction.atomic(): diff --git a/mayan/apps/documents/tasks.py b/mayan/apps/documents/tasks.py index 44f05d7565..11356f6755 100644 --- a/mayan/apps/documents/tasks.py +++ b/mayan/apps/documents/tasks.py @@ -24,72 +24,12 @@ logger = logging.getLogger(__name__) @app.task(ignore_result=True) def task_check_delete_periods(): - logger.info('Executing') - - for document_type in DocumentType.objects.all(): - logger.info( - 'Checking deletion period of document type: %s', document_type - ) - if document_type.delete_time_period and document_type.delete_time_unit: - delta = timedelta( - **{ - document_type.delete_time_unit: document_type.delete_time_period - } - ) - logger.info( - 'Document type: %s, has a deletion period delta of: %s', - document_type, delta - ) - for document in DeletedDocument.objects.filter(document_type=document_type): - # TODO: Don't iterate, filter documents by expiration - if now() > document.deleted_date_time + delta: - logger.info( - 'Document "%s" with id: %d, trashed on: %s, exceded ' - 'delete period', document, document.pk, - document.deleted_date_time - ) - document.delete() - else: - logger.info( - 'Document type: %s, has a no retention delta', document_type - ) - - logger.info('Finshed') + DocumentType.objects.check_delete_periods() @app.task(ignore_result=True) def task_check_trash_periods(): - logger.info('Executing') - - for document_type in DocumentType.objects.all(): - logger.info( - 'Checking trash period of document type: %s', document_type - ) - if document_type.trash_time_period and document_type.trash_time_unit: - delta = timedelta( - **{ - document_type.trash_time_unit: document_type.trash_time_period - } - ) - logger.info( - 'Document type: %s, has a trash period delta of: %s', - document_type, delta - ) - for document in Document.objects.filter(document_type=document_type): - # TODO: Don't iterate, filter documents by expiration - if now() > document.date_added + delta: - logger.info( - 'Document "%s" with id: %d, added on: %s, exceded ' - 'trash period', document, document.pk, - document.date_added - ) - document.delete() - else: - logger.info( - 'Document type: %s, has a no retention delta', document_type - ) - - logger.info('Finshed') + DocumentType.objects.check_trash_periods() @app.task(ignore_result=True) diff --git a/mayan/apps/documents/tests/test_models.py b/mayan/apps/documents/tests/test_models.py index dccd9014a6..0a02871b2f 100644 --- a/mayan/apps/documents/tests/test_models.py +++ b/mayan/apps/documents/tests/test_models.py @@ -5,6 +5,8 @@ import time from django.core.files import File from django.test import TestCase, override_settings +from common.literals import TIME_DELTA_UNIT_DAYS + from .literals import ( TEST_DOCUMENT_TYPE, TEST_DOCUMENT_PATH, TEST_MULTI_PAGE_TIFF_PATH, TEST_OFFICE_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_PATH @@ -79,6 +81,53 @@ class DocumentTestCase(TestCase): self.assertEqual(DeletedDocument.objects.count(), 0) self.assertEqual(Document.objects.count(), 0) + def test_auto_trashing(self): + """ + Test document type trashing policies. Documents are moved to the trash, + x amount of time after being uploaded + """ + + self.document_type.trash_time_period = 1 + # 'seconds' is not a choice via the model, used here for convenience + self.document_type.trash_time_unit = 'seconds' + self.document_type.save() + + time.sleep(1) + + self.assertEqual(Document.objects.count(), 1) + self.assertEqual(DeletedDocument.objects.count(), 0) + + DocumentType.objects.check_trash_periods() + + self.assertEqual(Document.objects.count(), 0) + self.assertEqual(DeletedDocument.objects.count(), 1) + + def test_auto_delete(self): + """ + Test document type deletion policies. Documents are deleted from the + trash, x amount of time after being trashed + """ + + self.document_type.delete_time_period = 1 + # 'seconds' is not a choice via the model, used here for convenience + self.document_type.delete_time_unit = 'seconds' + self.document_type.save() + + self.assertEqual(Document.objects.count(), 1) + self.assertEqual(DeletedDocument.objects.count(), 0) + + self.document.delete() + + self.assertEqual(Document.objects.count(), 0) + self.assertEqual(DeletedDocument.objects.count(), 1) + + time.sleep(1) + + DocumentType.objects.check_delete_periods() + + self.assertEqual(Document.objects.count(), 0) + self.assertEqual(DeletedDocument.objects.count(), 0) + @override_settings(OCR_AUTO_OCR=False) class OfficeDocumentTestCase(TestCase):