Update project to use Django 1.7.7. Issue #33

This commit is contained in:
Roberto Rosario
2015-03-30 03:42:53 -04:00
parent d6150f950b
commit bd041457c9
68 changed files with 1485 additions and 1236 deletions

View File

@@ -55,7 +55,7 @@ Add new static media::
Remove unused dependencies::
$ pip uninstall XXXXX
$ pip uninstall South
The upgrade procedure is now complete.

View File

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

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

@@ -0,0 +1,40 @@
from __future__ import unicode_literals
from django import apps
from django.db.models.signals import post_migrate
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_links
from project_setup.api import register_setup
from .classes import (
AccessHolder, AccessObject, AccessObjectClass, ClassAccessHolder
)
from .links import (
acl_class_acl_detail, acl_class_acl_list, acl_class_grant, acl_class_list,
acl_class_new_holder_for, acl_class_revoke, acl_detail, acl_grant,
acl_holder_new, acl_revoke, acl_setup_valid_classes
)
from .models import CreatorSingleton
def create_creator_user(sender, **kwargs):
if kwargs.get('app') == 'acls':
CreatorSingleton.objects.get_or_create()
class ACLsApp(apps.AppConfig):
name = 'acls'
verbose_name = _('ACLs')
def ready(self):
register_links([AccessObject], [acl_holder_new], menu_name='sidebar')
register_links(AccessObjectClass, [acl_class_acl_list, acl_class_new_holder_for])
register_links(AccessHolder, [acl_detail])
register_links(['acls:acl_setup_valid_classes', 'acls:acl_class_acl_list', 'acls:acl_class_new_holder_for', 'acls:acl_class_acl_detail', 'acls:acl_class_multiple_grant', 'acls:acl_class_multiple_revoke'], [acl_class_list], menu_name='secondary_menu')
register_links(ClassAccessHolder, [acl_class_acl_detail])
register_links(['acls:acl_detail'], [acl_grant, acl_revoke], menu_name='multi_item_links')
register_links(['acls:acl_class_acl_detail'], [acl_class_grant, acl_class_revoke], menu_name='multi_item_links')
register_setup(acl_setup_valid_classes)
post_migrate.connect(create_creator_user, dispatch_uid='create_creator_user')

View File

@@ -1,52 +1 @@
from __future__ import absolute_import, unicode_literals
from datetime import timedelta
from acls.api import class_permissions
from documents.models import Document
from mayan.celery import app
from navigation.api import register_links, register_top_menu
from rest_api.classes import APIEndPoint
from .links import (
checkin_document, checkout_document, checkout_info, checkout_list
)
from .models import DocumentCheckout
from .permissions import (
PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE,
PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE
)
CHECK_EXPIRED_CHECK_OUTS_INTERVAL = 60 # Lowest check out expiration allowed
def initialize_document_checkout_extra_methods():
Document.add_to_class('is_checked_out', lambda document: DocumentCheckout.objects.is_document_checked_out(document))
Document.add_to_class('check_in', lambda document, user=None: DocumentCheckout.objects.check_in_document(document, user))
Document.add_to_class('checkout_info', lambda document: DocumentCheckout.objects.document_checkout_info(document))
Document.add_to_class('checkout_state', lambda document: DocumentCheckout.objects.document_checkout_state(document))
Document.add_to_class('is_new_versions_allowed', lambda document, user=None: DocumentCheckout.objects.is_document_new_versions_allowed(document, user))
app.conf.CELERYBEAT_SCHEDULE.update({
'check_expired_check_outs': {
'task': 'checkouts.tasks.task_check_expired_check_outs',
'schedule': timedelta(seconds=CHECK_EXPIRED_CHECK_OUTS_INTERVAL),
'options': {'queue': 'checkouts'}
},
})
class_permissions(Document, [
PERMISSION_DOCUMENT_CHECKOUT,
PERMISSION_DOCUMENT_CHECKIN,
PERMISSION_DOCUMENT_CHECKIN_OVERRIDE,
PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE
])
initialize_document_checkout_extra_methods()
register_links(Document, [checkout_info], menu_name='form_header')
register_links(['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document'], [checkout_document, checkin_document], menu_name="sidebar")
register_top_menu(name='checkouts', link=checkout_list)
APIEndPoint('checkouts')

View File

@@ -0,0 +1,56 @@
from __future__ import absolute_import, unicode_literals
from datetime import timedelta
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from documents.models import Document
from mayan.celery import app
from navigation.api import register_links, register_top_menu
from rest_api.classes import APIEndPoint
from .links import (
checkin_document, checkout_document, checkout_info, checkout_list
)
from .models import DocumentCheckout
from .permissions import (
PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE,
PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE
)
CHECK_EXPIRED_CHECK_OUTS_INTERVAL = 60 # Lowest check out expiration allowed
class CheckoutsApp(apps.AppConfig):
name = 'checkouts'
verbose_name = _('Checkouts')
def ready(self):
Document.add_to_class('is_checked_out', lambda document: DocumentCheckout.objects.is_document_checked_out(document))
Document.add_to_class('check_in', lambda document, user=None: DocumentCheckout.objects.check_in_document(document, user))
Document.add_to_class('checkout_info', lambda document: DocumentCheckout.objects.document_checkout_info(document))
Document.add_to_class('checkout_state', lambda document: DocumentCheckout.objects.document_checkout_state(document))
Document.add_to_class('is_new_versions_allowed', lambda document, user=None: DocumentCheckout.objects.is_document_new_versions_allowed(document, user))
app.conf.CELERYBEAT_SCHEDULE.update({
'check_expired_check_outs': {
'task': 'checkouts.tasks.task_check_expired_check_outs',
'schedule': timedelta(seconds=CHECK_EXPIRED_CHECK_OUTS_INTERVAL),
'options': {'queue': 'checkouts'}
},
})
class_permissions(Document, [
PERMISSION_DOCUMENT_CHECKOUT,
PERMISSION_DOCUMENT_CHECKIN,
PERMISSION_DOCUMENT_CHECKIN_OVERRIDE,
PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE
])
register_links(Document, [checkout_info], menu_name='form_header')
register_links(['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document'], [checkout_document, checkin_document], menu_name="sidebar")
register_top_menu(name='checkouts', link=checkout_list)
APIEndPoint('checkouts')

View File

@@ -1,102 +1 @@
from __future__ import absolute_import, unicode_literals
import logging
import tempfile
from django.conf import settings
from django.contrib.auth import models as auth_models
from django.contrib.auth.models import User
from django.contrib.auth.signals import user_logged_in
from django.db.models.signals import post_save
from django.dispatch import receiver
from south.signals import post_migrate
from common import settings as common_settings
from navigation.api import register_links, register_top_menu
from .links import (
link_about, link_current_user_details, link_current_user_edit,
link_current_user_locale_profile_details,
link_current_user_locale_profile_edit, link_license, link_logout,
link_password_change
)
from .models import (
AnonymousUserSingleton, AutoAdminSingleton, UserLocaleProfile
)
from .settings import (
AUTO_ADMIN_USERNAME, AUTO_ADMIN_PASSWORD, AUTO_CREATE_ADMIN,
TEMPORARY_DIRECTORY
)
from .utils import validate_path
logger = logging.getLogger(__name__)
register_links(['common:current_user_details', 'common:current_user_edit', 'common:current_user_locale_profile_details', 'common:current_user_locale_profile_edit', 'common:password_change_view'], [link_current_user_details, link_current_user_edit, link_current_user_locale_profile_details, link_current_user_locale_profile_edit, link_password_change, link_logout], menu_name='secondary_menu')
register_links(['common:about_view', 'common:license_view'], [link_about, link_license], menu_name='secondary_menu')
register_top_menu('about', link_about, position=-1)
@receiver(post_migrate, dispatch_uid='create_superuser_and_anonymous_user')
def create_superuser_and_anonymous_user(sender, **kwargs):
"""
From https://github.com/lambdalisue/django-qwert/blob/master/qwert/autoscript/__init__.py
From http://stackoverflow.com/questions/1466827/ --
Prevent interactive question about wanting a superuser created. (This code
has to go in this otherwise empty "models" module so that it gets processed by
the "syncdb" command during database creation.)
Create our own admin super user automatically.
"""
if kwargs['app'] == 'common':
AutoAdminSingleton.objects.get_or_create()
AnonymousUserSingleton.objects.get_or_create()
if AUTO_CREATE_ADMIN:
try:
auth_models.User.objects.get(username=AUTO_ADMIN_USERNAME)
except auth_models.User.DoesNotExist:
logger.info('Creating super admin user -- login: %s, password: %s', AUTO_ADMIN_USERNAME, AUTO_ADMIN_PASSWORD)
assert auth_models.User.objects.create_superuser(AUTO_ADMIN_USERNAME, 'autoadmin@autoadmin.com', AUTO_ADMIN_PASSWORD)
admin = auth_models.User.objects.get(username=AUTO_ADMIN_USERNAME)
# Store the auto admin password properties to display the first login message
auto_admin_properties, created = AutoAdminSingleton.objects.get_or_create()
auto_admin_properties.account = admin
auto_admin_properties.password = AUTO_ADMIN_PASSWORD
auto_admin_properties.password_hash = admin.password
auto_admin_properties.save()
else:
logger.info('Super admin user already exists. -- login: %s', AUTO_ADMIN_USERNAME)
@receiver(post_save, dispatch_uid='auto_admin_account_passwd_change', sender=User)
def auto_admin_account_passwd_change(sender, instance, **kwargs):
auto_admin_properties = AutoAdminSingleton.objects.get()
if instance == auto_admin_properties.account and instance.password != auto_admin_properties.password_hash:
# Only delete the auto admin properties when the password has been changed
auto_admin_properties.account = None
auto_admin_properties.password = None
auto_admin_properties.password_hash = None
auto_admin_properties.save()
@receiver(user_logged_in, dispatch_uid='user_locale_profile_session_config', sender=User)
def user_locale_profile_session_config(sender, request, user, **kwargs):
if hasattr(request, 'session'):
user_locale_profile, created = UserLocaleProfile.objects.get_or_create(user=user)
request.session['django_language'] = user_locale_profile.language
request.session['django_timezone'] = user_locale_profile.timezone
else:
request.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_locale_profile.language)
@receiver(post_save, dispatch_uid='user_locale_profile_create', sender=User)
def user_locale_profile_create(sender, instance, created, **kwargs):
if created:
UserLocaleProfile.objects.create(user=instance)
if (not validate_path(TEMPORARY_DIRECTORY)) or (not TEMPORARY_DIRECTORY):
setattr(common_settings, 'TEMPORARY_DIRECTORY', tempfile.mkdtemp())

107
mayan/apps/common/apps.py Normal file
View File

@@ -0,0 +1,107 @@
from __future__ import absolute_import, unicode_literals
import logging
import tempfile
from django import apps
from django.conf import settings
from django.contrib.auth import models as auth_models
from django.contrib.auth.models import User
from django.contrib.auth.signals import user_logged_in
from django.db.models.signals import post_migrate, post_save
from django.utils.translation import ugettext_lazy as _
from common import settings as common_settings
from navigation.api import register_links, register_top_menu
from .links import (
link_about, link_current_user_details, link_current_user_edit,
link_current_user_locale_profile_details,
link_current_user_locale_profile_edit, link_license, link_logout,
link_password_change
)
from .models import (
AnonymousUserSingleton, AutoAdminSingleton, UserLocaleProfile
)
from .settings import (
AUTO_ADMIN_USERNAME, AUTO_ADMIN_PASSWORD, AUTO_CREATE_ADMIN,
TEMPORARY_DIRECTORY
)
from .utils import validate_path
def create_superuser_and_anonymous_user(sender, **kwargs):
"""
From https://github.com/lambdalisue/django-qwert/blob/master/qwert/autoscript/__init__.py
From http://stackoverflow.com/questions/1466827/ --
Prevent interactive question about wanting a superuser created. (This code
has to go in this otherwise empty "models" module so that it gets processed by
the "syncdb" command during database creation.)
Create our own admin super user automatically.
"""
if kwargs['app'] == 'common':
AutoAdminSingleton.objects.get_or_create()
AnonymousUserSingleton.objects.get_or_create()
if AUTO_CREATE_ADMIN:
try:
auth_models.User.objects.get(username=AUTO_ADMIN_USERNAME)
except auth_models.User.DoesNotExist:
logger.info('Creating super admin user -- login: %s, password: %s', AUTO_ADMIN_USERNAME, AUTO_ADMIN_PASSWORD)
assert auth_models.User.objects.create_superuser(AUTO_ADMIN_USERNAME, 'autoadmin@autoadmin.com', AUTO_ADMIN_PASSWORD)
admin = auth_models.User.objects.get(username=AUTO_ADMIN_USERNAME)
# Store the auto admin password properties to display the first login message
auto_admin_properties, created = AutoAdminSingleton.objects.get_or_create()
auto_admin_properties.account = admin
auto_admin_properties.password = AUTO_ADMIN_PASSWORD
auto_admin_properties.password_hash = admin.password
auto_admin_properties.save()
else:
logger.info('Super admin user already exists. -- login: %s', AUTO_ADMIN_USERNAME)
def auto_admin_account_passwd_change(sender, instance, **kwargs):
auto_admin_properties = AutoAdminSingleton.objects.get()
if instance == auto_admin_properties.account and instance.password != auto_admin_properties.password_hash:
# Only delete the auto admin properties when the password has been changed
auto_admin_properties.account = None
auto_admin_properties.password = None
auto_admin_properties.password_hash = None
auto_admin_properties.save()
def user_locale_profile_session_config(sender, request, user, **kwargs):
if hasattr(request, 'session'):
user_locale_profile, created = UserLocaleProfile.objects.get_or_create(user=user)
request.session['django_language'] = user_locale_profile.language
request.session['django_timezone'] = user_locale_profile.timezone
else:
request.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_locale_profile.language)
def user_locale_profile_create(sender, instance, created, **kwargs):
if created:
UserLocaleProfile.objects.create(user=instance)
class CommonApp(apps.AppConfig):
name = 'common'
verbose_name = _('Common')
def ready(self):
logger = logging.getLogger(__name__)
register_links(['common:current_user_details', 'common:current_user_edit', 'common:current_user_locale_profile_details', 'common:current_user_locale_profile_edit', 'common:password_change_view'], [link_current_user_details, link_current_user_edit, link_current_user_locale_profile_details, link_current_user_locale_profile_edit, link_password_change, link_logout], menu_name='secondary_menu')
register_links(['common:about_view', 'common:license_view'], [link_about, link_license], menu_name='secondary_menu')
register_top_menu('about', link_about, position=-1)
post_migrate.connect(create_superuser_and_anonymous_user, dispatch_uid='create_superuser_and_anonymous_user')
post_save.connect(auto_admin_account_passwd_change, dispatch_uid='auto_admin_account_passwd_change', sender=User)
user_logged_in.connect(user_locale_profile_session_config, dispatch_uid='user_locale_profile_session_config', sender=User)
post_save.connect(user_locale_profile_create, dispatch_uid='user_locale_profile_create', sender=User)
if (not validate_path(TEMPORARY_DIRECTORY)) or (not TEMPORARY_DIRECTORY):
setattr(common_settings, 'TEMPORARY_DIRECTORY', tempfile.mkdtemp())

View File

@@ -1,16 +1 @@
from __future__ import unicode_literals
from hkp import Key as KeyServerKey
from navigation.api import register_links
from project_setup.api import register_setup
from .api import Key
from .links import (
key_delete, key_query, key_receive, key_setup, public_keys
)
register_links(['django_gpg:key_delete', 'django_gpg:key_public_list', 'django_gpg:key_query'], [public_keys, key_query], menu_name='sidebar')
register_links(Key, [key_delete])
register_links(KeyServerKey, [key_receive])
register_setup(key_setup)

View File

@@ -0,0 +1,24 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from hkp import Key as KeyServerKey
from navigation.api import register_links
from project_setup.api import register_setup
from .api import Key
from .links import (
key_delete, key_query, key_receive, key_setup, public_keys
)
class DjangoGPGApp(apps.AppConfig):
name = 'django_gpg'
verbose_name = _('Django GPG')
def ready(self):
register_links(['django_gpg:key_delete', 'django_gpg:key_public_list', 'django_gpg:key_query'], [public_keys, key_query], menu_name='sidebar')
register_links(Key, [key_delete])
register_links(KeyServerKey, [key_receive])
register_setup(key_setup)

View File

@@ -1,15 +1 @@
from __future__ import unicode_literals
from acls.api import class_permissions
from acls.permissions import ACLS_VIEW_ACL, ACLS_EDIT_ACL
from documents.models import Document
from navigation.api import register_links
from .links import acl_list
register_links(Document, [acl_list], menu_name='form_header')
class_permissions(Document, [
ACLS_VIEW_ACL,
ACLS_EDIT_ACL
])

View File

@@ -0,0 +1,24 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from acls.permissions import ACLS_VIEW_ACL, ACLS_EDIT_ACL
from documents.models import Document
from navigation.api import register_links
from .links import acl_list
class DocumentACLsApp(apps.AppConfig):
name = 'document_acls'
verbose_name = _('Document ACLs')
def ready(self):
register_links(Document, [acl_list], menu_name='form_header')
class_permissions(Document, [
ACLS_VIEW_ACL,
ACLS_EDIT_ACL
])

View File

@@ -1,52 +1 @@
from __future__ import absolute_import, unicode_literals
from django.contrib.comments.models import Comment
from django.contrib.contenttypes import generic
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate
from documents.models import Document
from navigation.api import register_links, register_model_list_columns
from .links import comment_add, comment_delete, comments_for_document
from .permissions import (
PERMISSION_COMMENT_CREATE, PERMISSION_COMMENT_DELETE,
PERMISSION_COMMENT_VIEW
)
Document.add_to_class(
'comments',
generic.GenericRelation(
Comment,
content_type_field='content_type',
object_id_field='object_pk'
)
)
class_permissions(Document, [PERMISSION_COMMENT_CREATE,
PERMISSION_COMMENT_DELETE,
PERMISSION_COMMENT_VIEW])
register_model_list_columns(Comment, [
{
'name': _('Date'),
'attribute': 'submit_date'
},
{
'name': _('User'),
'attribute': encapsulate(lambda x: x.user.get_full_name() if x.user.get_full_name() else x.user)
},
{
'name': _('Comment'),
'attribute': 'comment'
}
])
register_links(['comments:comments_for_document', 'comments:comment_add', 'comments:comment_delete', 'comments:comment_multiple_delete'], [comment_add], menu_name='sidebar')
register_links(Comment, [comment_delete])
register_links(Document, [comments_for_document], menu_name='form_header')
ModelAttribute(Document, label=_('Comments'), name='comments', type_name='related')

View File

@@ -0,0 +1,57 @@
from __future__ import absolute_import, unicode_literals
from django import apps
from django.contrib.comments.models import Comment
from django.contrib.contenttypes import generic
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate
from documents.models import Document
from navigation.api import register_links, register_model_list_columns
from .links import comment_add, comment_delete, comments_for_document
from .permissions import (
PERMISSION_COMMENT_CREATE, PERMISSION_COMMENT_DELETE,
PERMISSION_COMMENT_VIEW
)
class DocumentCommentsApp(apps.AppConfig):
name = 'document_comments'
verbose_name = _('Document comments')
def ready(self):
Document.add_to_class(
'comments',
generic.GenericRelation(
Comment,
content_type_field='content_type',
object_id_field='object_pk'
)
)
class_permissions(Document, [PERMISSION_COMMENT_CREATE,
PERMISSION_COMMENT_DELETE,
PERMISSION_COMMENT_VIEW])
register_model_list_columns(Comment, [
{
'name': _('Date'),
'attribute': 'submit_date'
},
{
'name': _('User'),
'attribute': encapsulate(lambda x: x.user.get_full_name() if x.user.get_full_name() else x.user)
},
{
'name': _('Comment'),
'attribute': 'comment'
}
])
register_links(['comments:comments_for_document', 'comments:comment_add', 'comments:comment_delete', 'comments:comment_multiple_delete'], [comment_add], menu_name='sidebar')
register_links(Comment, [comment_delete])
register_links(Document, [comments_for_document], menu_name='form_header')
ModelAttribute(Document, label=_('Comments'), name='comments', type_name='related')

View File

@@ -9,5 +9,5 @@ class CommentForm(forms.ModelForm):
A standard model form to allow users to post a comment
"""
class Meta:
model = Comment
fields = ('comment',)
model = Comment

View File

@@ -1,52 +1 @@
from __future__ import absolute_import, unicode_literals
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from documents.models import Document
from main.api import register_maintenance_links
from metadata.models import DocumentMetadata
from navigation.api import register_links, register_top_menu
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .links import (
document_index_list, document_index_main_menu_link, index_parent,
index_setup, index_setup_create, index_setup_document_types,
index_setup_delete, index_setup_edit, index_setup_list, index_setup_view,
rebuild_index_instances, template_node_create, template_node_delete,
template_node_edit
)
from .models import Index, IndexTemplateNode, IndexInstanceNode
from .tasks import task_delete_empty_index_nodes, task_index_document
@receiver(post_delete, dispatch_uid='document_index_delete', sender=Document)
def document_index_delete(sender, **kwargs):
task_delete_empty_index_nodes.apply_async(queue='indexing')
@receiver(post_save, dispatch_uid='document_metadata_index_update', sender=DocumentMetadata)
def document_metadata_index_update(sender, **kwargs):
task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].document.pk), queue='indexing')
@receiver(post_delete, dispatch_uid='document_metadata_index_post_delete', sender=DocumentMetadata)
def document_metadata_index_post_delete(sender, **kwargs):
task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].document.pk), queue='indexing')
register_maintenance_links([rebuild_index_instances], namespace='document_indexing', title=_('Indexes'))
register_links(Document, [document_index_list], menu_name='form_header')
register_links([Index, 'indexing:index_setup_list', 'indexing:index_setup_create'], [index_setup_list, index_setup_create], menu_name='secondary_menu')
register_links(Index, [index_setup_edit, index_setup_view, index_setup_document_types, index_setup_delete])
register_links(IndexInstanceNode, [index_parent])
register_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete])
register_setup(index_setup)
register_top_menu('indexes', document_index_main_menu_link)
APIEndPoint('indexes', app_name='document_indexing')

View File

@@ -0,0 +1,58 @@
from __future__ import absolute_import, unicode_literals
from django import apps
from django.db.models.signals import post_save, post_delete
from django.utils.translation import ugettext_lazy as _
from documents.models import Document
from main.api import register_maintenance_links
from metadata.models import DocumentMetadata
from navigation.api import register_links, register_top_menu
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .links import (
document_index_list, document_index_main_menu_link, index_parent,
index_setup, index_setup_create, index_setup_document_types,
index_setup_delete, index_setup_edit, index_setup_list, index_setup_view,
rebuild_index_instances, template_node_create, template_node_delete,
template_node_edit
)
from .models import Index, IndexTemplateNode, IndexInstanceNode
from .tasks import task_delete_empty_index_nodes, task_index_document
def document_index_delete(sender, **kwargs):
task_delete_empty_index_nodes.apply_async(queue='indexing')
def document_metadata_index_update(sender, **kwargs):
task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].document.pk), queue='indexing')
def document_metadata_index_post_delete(sender, **kwargs):
task_index_document.apply_async(kwargs=dict(document_id=kwargs['instance'].document.pk), queue='indexing')
class DocumentIndexingApp(apps.AppConfig):
name = 'document_indexing'
verbose_name = _('Document indexing')
def ready(self):
post_delete.connect(document_index_delete, dispatch_uid='document_index_delete', sender=Document)
post_save.connect(document_metadata_index_update, dispatch_uid='document_metadata_index_update', sender=DocumentMetadata)
post_delete.connect(document_metadata_index_post_delete, dispatch_uid='document_metadata_index_post_delete', sender=DocumentMetadata)
register_maintenance_links([rebuild_index_instances], namespace='document_indexing', title=_('Indexes'))
register_links(Document, [document_index_list], menu_name='form_header')
register_links([Index, 'indexing:index_setup_list', 'indexing:index_setup_create'], [index_setup_list, index_setup_create], menu_name='secondary_menu')
register_links(Index, [index_setup_edit, index_setup_view, index_setup_document_types, index_setup_delete])
register_links(IndexInstanceNode, [index_parent])
register_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete])
register_setup(index_setup)
register_top_menu('indexes', document_index_main_menu_link)
APIEndPoint('indexes', app_name='document_indexing')

View File

@@ -1,64 +1 @@
from __future__ import unicode_literals
import logging
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from acls.api import class_permissions
from django_gpg.exceptions import GPGDecryptionError
from django_gpg.runtime import gpg
from documents.models import Document, DocumentVersion
from navigation.api import register_links
from .links import (
document_signature_delete, document_signature_download,
document_signature_upload, document_verify
)
from .models import DocumentVersionSignature
from .permissions import (
PERMISSION_DOCUMENT_VERIFY, PERMISSION_SIGNATURE_DELETE,
PERMISSION_SIGNATURE_DOWNLOAD, PERMISSION_SIGNATURE_UPLOAD
)
logger = logging.getLogger(__name__)
def document_pre_open_hook(descriptor, instance):
if DocumentVersionSignature.objects.has_embedded_signature(instance.document):
# If it has an embedded signature decrypt
try:
result = gpg.decrypt_file(descriptor, close_descriptor=False)
# gpg return a string, turn it into a file like object
except GPGDecryptionError:
# At least return the original raw content
descriptor.seek(0)
return descriptor
else:
descriptor.close()
return StringIO(result.data)
else:
return descriptor
def document_post_save_hook(instance):
if not instance.pk:
document_signature, created = DocumentVersionSignature.objects.get_or_create(
document_version=instance.latest_version,
)
register_links(Document, [document_verify], menu_name='form_header')
register_links(['signatures:document_verify', 'signatures:document_signature_upload', 'signatures:document_signature_download', 'signatures:document_signature_delete'], [document_signature_upload, document_signature_download, document_signature_delete], menu_name='sidebar')
DocumentVersion.register_pre_open_hook(1, document_pre_open_hook)
DocumentVersion.register_post_save_hook(1, document_post_save_hook)
class_permissions(Document, [
PERMISSION_DOCUMENT_VERIFY,
PERMISSION_SIGNATURE_DELETE,
PERMISSION_SIGNATURE_DOWNLOAD,
PERMISSION_SIGNATURE_UPLOAD,
])

View File

@@ -0,0 +1,72 @@
from __future__ import unicode_literals
import logging
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from django_gpg.exceptions import GPGDecryptionError
from django_gpg.runtime import gpg
from documents.models import Document, DocumentVersion
from navigation.api import register_links
from .links import (
document_signature_delete, document_signature_download,
document_signature_upload, document_verify
)
from .models import DocumentVersionSignature
from .permissions import (
PERMISSION_DOCUMENT_VERIFY, PERMISSION_SIGNATURE_DELETE,
PERMISSION_SIGNATURE_DOWNLOAD, PERMISSION_SIGNATURE_UPLOAD
)
logger = logging.getLogger(__name__)
def document_pre_open_hook(descriptor, instance):
if DocumentVersionSignature.objects.has_embedded_signature(instance.document):
# If it has an embedded signature decrypt
try:
result = gpg.decrypt_file(descriptor, close_descriptor=False)
# gpg return a string, turn it into a file like object
except GPGDecryptionError:
# At least return the original raw content
descriptor.seek(0)
return descriptor
else:
descriptor.close()
return StringIO(result.data)
else:
return descriptor
def document_post_save_hook(instance):
if not instance.pk:
document_signature, created = DocumentVersionSignature.objects.get_or_create(
document_version=instance.latest_version,
)
class DocumentSignaturesApp(apps.AppConfig):
name = 'document_signatures'
verbose_name = _('Document signatures')
def ready(self):
register_links(Document, [document_verify], menu_name='form_header')
register_links(['signatures:document_verify', 'signatures:document_signature_upload', 'signatures:document_signature_download', 'signatures:document_signature_delete'], [document_signature_upload, document_signature_download, document_signature_delete], menu_name='sidebar')
DocumentVersion.register_pre_open_hook(1, document_pre_open_hook)
DocumentVersion.register_post_save_hook(1, document_post_save_hook)
class_permissions(Document, [
PERMISSION_DOCUMENT_VERIFY,
PERMISSION_SIGNATURE_DELETE,
PERMISSION_SIGNATURE_DOWNLOAD,
PERMISSION_SIGNATURE_UPLOAD,
])

View File

@@ -1,105 +1 @@
from __future__ import unicode_literals
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from common.utils import encapsulate
from documents.models import Document
from navigation.api import register_links, register_model_list_columns
from project_setup.api import register_setup
from .models import (
Workflow, WorkflowInstance, WorkflowInstanceLogEntry, WorkflowState,
WorkflowTransition
)
from .links import (
link_document_workflow_instance_list, link_setup_workflow_document_types,
link_setup_workflow_create, link_setup_workflow_delete,
link_setup_workflow_edit, link_setup_workflow_list,
link_setup_workflow_states, link_setup_workflow_state_create,
link_setup_workflow_state_delete, link_setup_workflow_state_edit,
link_setup_workflow_transitions, link_setup_workflow_transition_create,
link_setup_workflow_transition_delete, link_setup_workflow_transition_edit,
link_workflow_instance_detail, link_workflow_instance_transition
)
@receiver(post_save, dispatch_uid='launch_workflow', sender=Document)
def launch_workflow(sender, instance, created, **kwargs):
if created:
Workflow.objects.launch_for(instance)
register_setup(link_setup_workflow_list)
register_model_list_columns(Workflow, [
{
'name': _('Initial state'),
'attribute': encapsulate(lambda workflow: workflow.get_initial_state() or _('None'))
},
])
register_model_list_columns(WorkflowState, [
{
'name': _('Is initial state?'),
'attribute': 'initial'
},
])
register_model_list_columns(WorkflowInstance, [
{
'name': _('Current state'),
'attribute': 'get_current_state'
},
{
'name': _('User'),
'attribute': encapsulate(lambda workflow: getattr(workflow.get_last_log_entry(), 'user', _('None')))
},
{
'name': _('Last transition'),
'attribute': 'get_last_transition'
},
{
'name': _('Date and time'),
'attribute': encapsulate(lambda workflow: getattr(workflow.get_last_log_entry(), 'datetime', _('None')))
},
])
register_model_list_columns(WorkflowTransition, [
{
'name': _('Origin state'),
'attribute': 'origin_state'
},
{
'name': _('Destination state'),
'attribute': 'destination_state'
},
])
register_model_list_columns(WorkflowInstanceLogEntry, [
{
'name': _('Date and time'),
'attribute': 'datetime'
},
{
'name': _('User'),
'attribute': 'user'
},
{
'name': _('Transition'),
'attribute': 'transition'
},
{
'name': _('Comment'),
'attribute': 'comment'
},
])
register_links([Document], [link_document_workflow_instance_list], menu_name='form_header')
register_links([WorkflowInstance], [link_workflow_instance_detail, link_workflow_instance_transition])
register_links([Workflow, 'document_states:setup_workflow_create', 'document_states:setup_workflow_list'], [link_setup_workflow_list, link_setup_workflow_create], menu_name='secondary_menu')
register_links([Workflow], [link_setup_workflow_states, link_setup_workflow_transitions, link_setup_workflow_document_types, link_setup_workflow_edit, link_setup_workflow_delete])
register_links([Workflow], [link_setup_workflow_state_create, link_setup_workflow_transition_create], menu_name='sidebar')
register_links([WorkflowState], [link_setup_workflow_state_edit, link_setup_workflow_state_delete])
register_links([WorkflowTransition], [link_setup_workflow_transition_edit, link_setup_workflow_transition_delete])

View File

@@ -0,0 +1,111 @@
from __future__ import unicode_literals
from django import apps
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from common.utils import encapsulate
from documents.models import Document
from navigation.api import register_links, register_model_list_columns
from project_setup.api import register_setup
from .models import (
Workflow, WorkflowInstance, WorkflowInstanceLogEntry, WorkflowState,
WorkflowTransition
)
from .links import (
link_document_workflow_instance_list, link_setup_workflow_document_types,
link_setup_workflow_create, link_setup_workflow_delete,
link_setup_workflow_edit, link_setup_workflow_list,
link_setup_workflow_states, link_setup_workflow_state_create,
link_setup_workflow_state_delete, link_setup_workflow_state_edit,
link_setup_workflow_transitions, link_setup_workflow_transition_create,
link_setup_workflow_transition_delete, link_setup_workflow_transition_edit,
link_workflow_instance_detail, link_workflow_instance_transition
)
def launch_workflow(sender, instance, created, **kwargs):
if created:
Workflow.objects.launch_for(instance)
class DocumentStatesApp(apps.AppConfig):
name = 'document_states'
verbose_name = _('Document states')
def ready(self):
post_save.connect(launch_workflow, dispatch_uid='launch_workflow', sender=Document)
register_setup(link_setup_workflow_list)
register_model_list_columns(Workflow, [
{
'name': _('Initial state'),
'attribute': encapsulate(lambda workflow: workflow.get_initial_state() or _('None'))
},
])
register_model_list_columns(WorkflowState, [
{
'name': _('Is initial state?'),
'attribute': 'initial'
},
])
register_model_list_columns(WorkflowInstance, [
{
'name': _('Current state'),
'attribute': 'get_current_state'
},
{
'name': _('User'),
'attribute': encapsulate(lambda workflow: getattr(workflow.get_last_log_entry(), 'user', _('None')))
},
{
'name': _('Last transition'),
'attribute': 'get_last_transition'
},
{
'name': _('Date and time'),
'attribute': encapsulate(lambda workflow: getattr(workflow.get_last_log_entry(), 'datetime', _('None')))
},
])
register_model_list_columns(WorkflowTransition, [
{
'name': _('Origin state'),
'attribute': 'origin_state'
},
{
'name': _('Destination state'),
'attribute': 'destination_state'
},
])
register_model_list_columns(WorkflowInstanceLogEntry, [
{
'name': _('Date and time'),
'attribute': 'datetime'
},
{
'name': _('User'),
'attribute': 'user'
},
{
'name': _('Transition'),
'attribute': 'transition'
},
{
'name': _('Comment'),
'attribute': 'comment'
},
])
register_links([Document], [link_document_workflow_instance_list], menu_name='form_header')
register_links([WorkflowInstance], [link_workflow_instance_detail, link_workflow_instance_transition])
register_links([Workflow, 'document_states:setup_workflow_create', 'document_states:setup_workflow_list'], [link_setup_workflow_list, link_setup_workflow_create], menu_name='secondary_menu')
register_links([Workflow], [link_setup_workflow_states, link_setup_workflow_transitions, link_setup_workflow_document_types, link_setup_workflow_edit, link_setup_workflow_delete])
register_links([Workflow], [link_setup_workflow_state_create, link_setup_workflow_transition_create], menu_name='sidebar')
register_links([WorkflowState], [link_setup_workflow_state_edit, link_setup_workflow_state_delete])
register_links([WorkflowTransition], [link_setup_workflow_transition_edit, link_setup_workflow_transition_delete])

View File

@@ -1,140 +0,0 @@
from __future__ import absolute_import, unicode_literals
import tempfile
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate, validate_path
from dynamic_search.classes import SearchModel
from events.permissions import PERMISSION_EVENTS_VIEW
from main import FrontPageButton
from main.api import register_maintenance_links
from navigation.api import register_links, register_model_list_columns
from navigation.links import link_spacer
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from statistics.classes import StatisticNamespace
from documents import settings as document_settings
from .links import (
document_clear_image_cache, document_clear_transformations,
document_content, document_delete, document_document_type_edit,
document_events_view, document_multiple_document_type_edit,
document_download, document_edit, document_list, document_list_recent,
document_multiple_delete, document_multiple_clear_transformations,
document_multiple_download, document_multiple_update_page_count,
document_page_edit, document_page_navigation_first,
document_page_navigation_last, document_page_navigation_next,
document_page_navigation_previous, document_page_rotate_left,
document_page_rotate_right, document_page_text,
document_page_transformation_list, document_page_transformation_create,
document_page_transformation_edit, document_page_transformation_delete,
document_page_view, document_page_view_reset, document_page_zoom_in,
document_page_zoom_out, document_preview, document_print,
document_properties, document_type_create, document_type_delete,
document_type_edit, document_type_filename_create,
document_type_filename_delete, document_type_filename_edit,
document_type_filename_list, document_type_list, document_type_setup,
document_update_page_count, document_version_download,
document_version_list, document_version_revert
)
from .models import (
Document, DocumentPage, DocumentPageTransformation, DocumentType,
DocumentTypeFilename, DocumentVersion
)
from .permissions import (
PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD,
PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_NEW_VERSION,
PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_TRANSFORM,
PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_VIEW
)
from .settings import THUMBNAIL_SIZE
from .statistics import DocumentStatistics, DocumentUsageStatistics
from .widgets import document_thumbnail
# Register document type links
register_links(DocumentType, [document_type_edit, document_type_filename_list, document_type_delete])
register_links([DocumentType, 'documents:document_type_create', 'documents:document_type_list'], [document_type_list, document_type_create], menu_name='secondary_menu')
register_links(DocumentTypeFilename, [document_type_filename_edit, document_type_filename_delete])
register_links([DocumentTypeFilename, 'documents:document_type_filename_list', 'documents:document_type_filename_create'], [document_type_filename_create], menu_name='sidebar')
# Register document links
register_links(Document, [document_edit, document_document_type_edit, document_print, document_delete, document_download, document_clear_transformations, document_update_page_count])
register_links([Document], [document_multiple_clear_transformations, document_multiple_delete, document_multiple_download, document_multiple_update_page_count, document_multiple_document_type_edit, link_spacer], menu_name='multi_item_links')
register_links(Document, [document_preview], menu_name='form_header', position=0)
register_links(Document, [document_content], menu_name='form_header', position=1)
register_links(Document, [document_properties], menu_name='form_header', position=2)
register_links(Document, [document_events_view, document_version_list], menu_name='form_header')
# Document Version links
register_links(DocumentVersion, [document_version_revert, document_version_download])
register_links(['documents:document_list_recent', 'documents:document_list'], [document_list_recent, document_list], menu_name='secondary_menu')
register_links(Document, [document_list_recent, document_list], menu_name='secondary_menu')
# Document page links
register_links(DocumentPage, [
document_page_transformation_list, document_page_view,
document_page_text, document_page_edit,
])
# Document page navigation links
register_links(DocumentPage, [
document_page_navigation_first, document_page_navigation_previous,
document_page_navigation_next, document_page_navigation_last
], menu_name='sidebar')
register_links(['documents:document_page_view'], [document_page_rotate_left, document_page_rotate_right, document_page_zoom_in, document_page_zoom_out, document_page_view_reset], menu_name='form_header')
register_links(DocumentPageTransformation, [document_page_transformation_edit, document_page_transformation_delete])
register_links('documents:document_page_transformation_list', [document_page_transformation_create], menu_name='sidebar')
register_links('documents:document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar')
register_links(['documents:document_page_transformation_edit', 'documents:document_page_transformation_delete'], [document_page_transformation_create], menu_name='sidebar')
register_maintenance_links([document_clear_image_cache], namespace='documents', title=_('Documents'))
register_model_list_columns(Document, [
{
'name': _('Thumbnail'), 'attribute':
encapsulate(lambda x: document_thumbnail(x, gallery_name='documents:document_list', title=getattr(x, 'filename', None), size=THUMBNAIL_SIZE))
},
{
'name': _('Type'), 'attribute': 'document_type'
}
])
if (not validate_path(document_settings.CACHE_PATH)) or (not document_settings.CACHE_PATH):
setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp())
register_setup(document_type_setup)
class_permissions(Document, [
PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD,
PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_NEW_VERSION,
PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_TRANSFORM,
PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_VIEW,
PERMISSION_EVENTS_VIEW
])
document_search = SearchModel('documents', 'Document', permission=PERMISSION_DOCUMENT_VIEW, serializer_string='documents.serializers.DocumentSerializer')
# TODO: move these to their respective apps
# Moving these to other apps cause an ImportError; circular import?
document_search.add_model_field('document_type__name', label=_('Document type'))
document_search.add_model_field('versions__mimetype', label=_('MIME type'))
document_search.add_model_field('label', label=_('Label'))
document_search.add_model_field('metadata__metadata_type__name', label=_('Metadata type'))
document_search.add_model_field('metadata__value', label=_('Metadata value'))
document_search.add_model_field('versions__pages__content', label=_('Content'))
document_search.add_model_field('description', label=_('Description'))
document_search.add_model_field('tags__label', label=_('Tags'))
namespace = StatisticNamespace(name='documents', label=_('Documents'))
namespace.add_statistic(DocumentStatistics(name='document_stats', label=_('Document tendencies')))
namespace.add_statistic(DocumentUsageStatistics(name='document_usage', label=_('Document usage')))
APIEndPoint('documents')
ModelAttribute(Document, label=_('Label'), name='label', type_name='field')
FrontPageButton(link=document_list_recent)
FrontPageButton(link=document_list)

View File

@@ -0,0 +1,151 @@
from __future__ import absolute_import, unicode_literals
import tempfile
from django import apps
from django.utils.translation import ugettext_lazy as _
from actstream import registry
from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate, validate_path
from dynamic_search.classes import SearchModel
from events.permissions import PERMISSION_EVENTS_VIEW
from main import FrontPageButton
from main.api import register_maintenance_links
from navigation.api import register_links, register_model_list_columns
from navigation.links import link_spacer
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from statistics.classes import StatisticNamespace
from documents import settings as document_settings
from .links import (
document_clear_image_cache, document_clear_transformations,
document_content, document_delete, document_document_type_edit,
document_events_view, document_multiple_document_type_edit,
document_download, document_edit, document_list, document_list_recent,
document_multiple_delete, document_multiple_clear_transformations,
document_multiple_download, document_multiple_update_page_count,
document_page_edit, document_page_navigation_first,
document_page_navigation_last, document_page_navigation_next,
document_page_navigation_previous, document_page_rotate_left,
document_page_rotate_right, document_page_text,
document_page_transformation_list, document_page_transformation_create,
document_page_transformation_edit, document_page_transformation_delete,
document_page_view, document_page_view_reset, document_page_zoom_in,
document_page_zoom_out, document_preview, document_print,
document_properties, document_type_create, document_type_delete,
document_type_edit, document_type_filename_create,
document_type_filename_delete, document_type_filename_edit,
document_type_filename_list, document_type_list, document_type_setup,
document_update_page_count, document_version_download,
document_version_list, document_version_revert
)
from .models import (
Document, DocumentPage, DocumentPageTransformation, DocumentType,
DocumentTypeFilename, DocumentVersion
)
from .permissions import (
PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD,
PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_NEW_VERSION,
PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_TRANSFORM,
PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_VIEW
)
from .settings import THUMBNAIL_SIZE
from .statistics import DocumentStatistics, DocumentUsageStatistics
from .widgets import document_thumbnail
class DocumentsApp(apps.AppConfig):
name = 'documents'
verbose_name = _('Documents')
def ready(self):
# Register document type links
register_links(DocumentType, [document_type_edit, document_type_filename_list, document_type_delete])
register_links([DocumentType, 'documents:document_type_create', 'documents:document_type_list'], [document_type_list, document_type_create], menu_name='secondary_menu')
register_links(DocumentTypeFilename, [document_type_filename_edit, document_type_filename_delete])
register_links([DocumentTypeFilename, 'documents:document_type_filename_list', 'documents:document_type_filename_create'], [document_type_filename_create], menu_name='sidebar')
# Register document links
register_links(Document, [document_edit, document_document_type_edit, document_print, document_delete, document_download, document_clear_transformations, document_update_page_count])
register_links([Document], [document_multiple_clear_transformations, document_multiple_delete, document_multiple_download, document_multiple_update_page_count, document_multiple_document_type_edit, link_spacer], menu_name='multi_item_links')
register_links(Document, [document_preview], menu_name='form_header', position=0)
register_links(Document, [document_content], menu_name='form_header', position=1)
register_links(Document, [document_properties], menu_name='form_header', position=2)
register_links(Document, [document_events_view, document_version_list], menu_name='form_header')
# Document Version links
register_links(DocumentVersion, [document_version_revert, document_version_download])
register_links(['documents:document_list_recent', 'documents:document_list'], [document_list_recent, document_list], menu_name='secondary_menu')
register_links(Document, [document_list_recent, document_list], menu_name='secondary_menu')
# Document page links
register_links(DocumentPage, [
document_page_transformation_list, document_page_view,
document_page_text, document_page_edit,
])
# Document page navigation links
register_links(DocumentPage, [
document_page_navigation_first, document_page_navigation_previous,
document_page_navigation_next, document_page_navigation_last
], menu_name='sidebar')
register_links(['documents:document_page_view'], [document_page_rotate_left, document_page_rotate_right, document_page_zoom_in, document_page_zoom_out, document_page_view_reset], menu_name='form_header')
register_links(DocumentPageTransformation, [document_page_transformation_edit, document_page_transformation_delete])
register_links('documents:document_page_transformation_list', [document_page_transformation_create], menu_name='sidebar')
register_links('documents:document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar')
register_links(['documents:document_page_transformation_edit', 'documents:document_page_transformation_delete'], [document_page_transformation_create], menu_name='sidebar')
register_maintenance_links([document_clear_image_cache], namespace='documents', title=_('Documents'))
register_model_list_columns(Document, [
{
'name': _('Thumbnail'), 'attribute':
encapsulate(lambda x: document_thumbnail(x, gallery_name='documents:document_list', title=getattr(x, 'filename', None), size=THUMBNAIL_SIZE))
},
{
'name': _('Type'), 'attribute': 'document_type'
}
])
if (not validate_path(document_settings.CACHE_PATH)) or (not document_settings.CACHE_PATH):
setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp())
register_setup(document_type_setup)
class_permissions(Document, [
PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD,
PERMISSION_DOCUMENT_EDIT, PERMISSION_DOCUMENT_NEW_VERSION,
PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_TRANSFORM,
PERMISSION_DOCUMENT_VERSION_REVERT, PERMISSION_DOCUMENT_VIEW,
PERMISSION_EVENTS_VIEW
])
document_search = SearchModel('documents', 'Document', permission=PERMISSION_DOCUMENT_VIEW, serializer_string='documents.serializers.DocumentSerializer')
# TODO: move these to their respective apps
# Moving these to other apps cause an ImportError; circular import?
document_search.add_model_field('document_type__name', label=_('Document type'))
document_search.add_model_field('versions__mimetype', label=_('MIME type'))
document_search.add_model_field('label', label=_('Label'))
document_search.add_model_field('metadata__metadata_type__name', label=_('Metadata type'))
document_search.add_model_field('metadata__value', label=_('Metadata value'))
document_search.add_model_field('versions__pages__content', label=_('Content'))
document_search.add_model_field('description', label=_('Description'))
document_search.add_model_field('tags__label', label=_('Tags'))
namespace = StatisticNamespace(name='documents', label=_('Documents'))
namespace.add_statistic(DocumentStatistics(name='document_stats', label=_('Document tendencies')))
namespace.add_statistic(DocumentUsageStatistics(name='document_usage', label=_('Document usage')))
APIEndPoint('documents')
ModelAttribute(Document, label=_('Label'), name='label', type_name='field')
FrontPageButton(link=document_list_recent)
FrontPageButton(link=document_list)
registry.register(Document)

View File

@@ -20,6 +20,7 @@ from .widgets import DocumentPagesCarouselWidget, DocumentPageImageWidget
# Document page forms
class DocumentPageTransformationForm(forms.ModelForm):
class Meta:
fields = ('order', 'transformation', 'arguments')
model = DocumentPageTransformation
def __init__(self, *args, **kwargs):
@@ -29,8 +30,8 @@ class DocumentPageTransformationForm(forms.ModelForm):
class DocumentPageForm(DetailForm):
class Meta:
model = DocumentPage
fields = ()
model = DocumentPage
def __init__(self, *args, **kwargs):
zoom = kwargs.pop('zoom', 100)
@@ -49,8 +50,8 @@ class DocumentPageForm(DetailForm):
class DocumentPageForm_text(DetailForm):
class Meta:
model = DocumentPage
fields = ('page_label', 'content')
model = DocumentPage
content = forms.CharField(
label=_('Contents'),
@@ -61,8 +62,8 @@ class DocumentPageForm_text(DetailForm):
class DocumentPageForm_edit(forms.ModelForm):
class Meta:
model = DocumentPage
fields = ('page_label', 'content')
model = DocumentPage
def __init__(self, *args, **kwargs):
super(DocumentPageForm_edit, self).__init__(*args, **kwargs)
@@ -123,8 +124,8 @@ class DocumentPropertiesForm(DetailForm):
Detail class form to display a document file based properties
"""
class Meta:
model = Document
fields = ('document_type', 'description', 'language')
model = Document
class DocumentContentForm(forms.Form):
@@ -172,6 +173,7 @@ class DocumentTypeForm(forms.ModelForm):
Model class form to create or edit a document type
"""
class Meta:
fields = ('name', 'ocr')
model = DocumentType
@@ -180,8 +182,8 @@ class DocumentTypeFilenameForm(forms.ModelForm):
Model class form to edit a document type filename
"""
class Meta:
model = DocumentTypeFilename
fields = ('filename', 'enabled')
model = DocumentTypeFilename
class DocumentTypeFilenameForm_create(forms.ModelForm):
@@ -189,8 +191,8 @@ class DocumentTypeFilenameForm_create(forms.ModelForm):
Model class form to create a new document type filename
"""
class Meta:
model = DocumentTypeFilename
fields = ('filename',)
model = DocumentTypeFilename
class DocumentDownloadForm(forms.Form):

View File

@@ -14,8 +14,6 @@ from django.core.exceptions import ValidationError
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
from actstream import registry
from acls.utils import apply_default_acls
from common.settings import TEMPORARY_DIRECTORY
from converter.api import (
@@ -585,5 +583,3 @@ class RecentDocument(models.Model):
# Quick hack to break the DocumentPage and DocumentPageTransformation circular dependency
# Can be remove once the transformations are moved to the converter app
DocumentPage.add_to_class('get_transformation_list', lambda document_page: DocumentPageTransformation.objects.get_for_document_page_as_list(document_page))
registry.register(Document)

View File

@@ -1,11 +1 @@
from __future__ import unicode_literals
from navigation.api import register_links
from rest_api.classes import APIEndPoint
from .links import search, search_advanced, search_again
register_links(['search:search', 'search:search_advanced', 'search:results'], [search, search_advanced], menu_name='form_header')
register_links(['search:results'], [search_again], menu_name='sidebar')
APIEndPoint('search', app_name='dynamic_search')

View File

@@ -0,0 +1,20 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_links
from rest_api.classes import APIEndPoint
from .links import search, search_advanced, search_again
class DynamicSearchApp(apps.AppConfig):
name = 'dynamic_search'
verbose_name = _('Dynamic search')
def ready(self):
register_links(['search:search', 'search:search_advanced', 'search:results'], [search, search_advanced], menu_name='form_header')
register_links(['search:results'], [search_again], menu_name='sidebar')
APIEndPoint('search', app_name='dynamic_search')

View File

@@ -1,8 +1,2 @@
from __future__ import unicode_literals
from project_tools.api import register_tool
from .classes import Event # NOQA
from .links import events_list
register_tool(events_list)

16
mayan/apps/events/apps.py Normal file
View File

@@ -0,0 +1,16 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from project_tools.api import register_tool
from .links import events_list
class EventsApp(apps.AppConfig):
name = 'events'
verbose_name = _('Events')
def ready(self):
register_tool(events_list)

View File

@@ -1,50 +1 @@
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL
from common.utils import encapsulate
from documents.models import Document
from navigation.api import (
register_links, register_model_list_columns, register_top_menu
)
from navigation.links import link_spacer
from rest_api.classes import APIEndPoint
from .links import (
document_folder_list, folder_acl_list, folder_add_document,
folder_add_multiple_documents, folder_create, folder_delete,
folder_document_multiple_remove, folder_edit, folder_list, folder_view,
folders_main_menu_link
)
from .models import Folder
from .permissions import (
PERMISSION_FOLDER_ADD_DOCUMENT, PERMISSION_FOLDER_DELETE,
PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_REMOVE_DOCUMENT,
PERMISSION_FOLDER_VIEW
)
register_links(Folder, [folder_view, folder_edit, folder_acl_list, folder_delete])
register_links([Folder, 'folders:folder_list', 'folders:folder_create'], [folder_list, folder_create], menu_name='secondary_menu')
register_links(['folders:document_folder_list', 'folders:folder_add_document'], [folder_add_document], menu_name="sidebar")
register_links(Document, [document_folder_list], menu_name='form_header')
register_links([Document], [folder_add_multiple_documents, folder_document_multiple_remove, link_spacer], menu_name='multi_item_links')
register_top_menu(name='folders', link=folders_main_menu_link)
class_permissions(Folder, [
ACLS_EDIT_ACL, ACLS_VIEW_ACL, PERMISSION_FOLDER_DELETE,
PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_VIEW
])
class_permissions(Document, [
PERMISSION_FOLDER_ADD_DOCUMENT, PERMISSION_FOLDER_REMOVE_DOCUMENT
])
register_model_list_columns(Folder, [
{'name': _('Created'), 'attribute': 'datetime_created'},
{'name': _('Documents'), 'attribute': encapsulate(lambda x: x.documents.count())},
])
APIEndPoint('folders')

View File

@@ -0,0 +1,57 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL
from common.utils import encapsulate
from documents.models import Document
from navigation.api import (
register_links, register_model_list_columns, register_top_menu
)
from navigation.links import link_spacer
from rest_api.classes import APIEndPoint
from .links import (
document_folder_list, folder_acl_list, folder_add_document,
folder_add_multiple_documents, folder_create, folder_delete,
folder_document_multiple_remove, folder_edit, folder_list, folder_view,
folders_main_menu_link
)
from .models import Folder
from .permissions import (
PERMISSION_FOLDER_ADD_DOCUMENT, PERMISSION_FOLDER_DELETE,
PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_REMOVE_DOCUMENT,
PERMISSION_FOLDER_VIEW
)
class FoldersApp(apps.AppConfig):
name = 'folders'
verbose_name = _('Folders')
def ready(self):
register_links(Folder, [folder_view, folder_edit, folder_acl_list, folder_delete])
register_links([Folder, 'folders:folder_list', 'folders:folder_create'], [folder_list, folder_create], menu_name='secondary_menu')
register_links(['folders:document_folder_list', 'folders:folder_add_document'], [folder_add_document], menu_name="sidebar")
register_links(Document, [document_folder_list], menu_name='form_header')
register_links([Document], [folder_add_multiple_documents, folder_document_multiple_remove, link_spacer], menu_name='multi_item_links')
register_top_menu(name='folders', link=folders_main_menu_link)
class_permissions(Folder, [
ACLS_EDIT_ACL, ACLS_VIEW_ACL, PERMISSION_FOLDER_DELETE,
PERMISSION_FOLDER_EDIT, PERMISSION_FOLDER_VIEW
])
class_permissions(Document, [
PERMISSION_FOLDER_ADD_DOCUMENT, PERMISSION_FOLDER_REMOVE_DOCUMENT
])
register_model_list_columns(Folder, [
{'name': _('Created'), 'attribute': 'datetime_created'},
{'name': _('Documents'), 'attribute': encapsulate(lambda x: x.documents.count())},
])
APIEndPoint('folders')

View File

@@ -1,48 +1 @@
from __future__ import unicode_literals
from django.db.utils import DatabaseError
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from south.signals import post_migrate
from common.utils import encapsulate
from navigation.api import register_links, register_model_list_columns
from project_tools.api import register_tool
from .classes import Property, PropertyNamespace
from .links import link_menu_link, link_namespace_details, link_namespace_list
from .models import Installation
@receiver(post_migrate, dispatch_uid='create_installation_instance')
def create_installation_instance(sender, **kwargs):
if kwargs['app'] == 'installation':
Installation.objects.get_or_create()
register_model_list_columns(PropertyNamespace, [
{
'name': _('Label'),
'attribute': 'label'
},
{
'name': _('Items'),
'attribute': encapsulate(lambda entry: len(entry.get_properties()))
}
])
register_model_list_columns(Property, [
{
'name': _('Label'),
'attribute': 'label'
},
{
'name': _('Value'),
'attribute': 'value'
}
])
register_links(PropertyNamespace, [link_namespace_details])
register_links(['installation:namespace_list', PropertyNamespace], [link_namespace_list], menu_name='secondary_menu')
register_tool(link_menu_link)

View File

@@ -0,0 +1,54 @@
from __future__ import unicode_literals
from django import apps
from django.db.models.signals import post_migrate
from django.db.utils import DatabaseError
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from common.utils import encapsulate
from navigation.api import register_links, register_model_list_columns
from project_tools.api import register_tool
from .classes import Property, PropertyNamespace
from .links import link_menu_link, link_namespace_details, link_namespace_list
from .models import Installation
def create_installation_instance(sender, **kwargs):
if kwargs['app'] == 'installation':
Installation.objects.get_or_create()
class InstallationApp(apps.AppConfig):
name = 'installation'
verbose_name = _('Installation')
def ready(self):
post_migrate.connect(create_installation_instance, dispatch_uid='create_installation_instance')
register_model_list_columns(PropertyNamespace, [
{
'name': _('Label'),
'attribute': 'label'
},
{
'name': _('Items'),
'attribute': encapsulate(lambda entry: len(entry.get_properties()))
}
])
register_model_list_columns(Property, [
{
'name': _('Label'),
'attribute': 'label'
},
{
'name': _('Value'),
'attribute': 'value'
}
])
register_links(PropertyNamespace, [link_namespace_details])
register_links(['installation:namespace_list', PropertyNamespace], [link_namespace_list], menu_name='secondary_menu')
register_tool(link_menu_link)

View File

@@ -1,35 +1 @@
from __future__ import unicode_literals
from acls.api import class_permissions
from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL
from documents.models import Document
from navigation.api import register_links
from project_setup.api import register_setup
from .classes import ResolvedSmartLink
from .links import (
smart_link_acl_list, smart_link_create, smart_link_condition_create,
smart_link_condition_delete, smart_link_condition_edit,
smart_link_condition_list, smart_link_delete, smart_link_document_types,
smart_link_edit, smart_link_instance_view,
smart_link_instances_for_document, smart_link_list, smart_link_setup
)
from .models import SmartLink, SmartLinkCondition
from .permissions import (
PERMISSION_SMART_LINK_DELETE, PERMISSION_SMART_LINK_EDIT,
PERMISSION_SMART_LINK_VIEW
)
register_links(Document, [smart_link_instances_for_document], menu_name='form_header')
register_links(SmartLink, [smart_link_edit, smart_link_document_types, smart_link_condition_list, smart_link_acl_list, smart_link_delete])
register_links([SmartLink, 'linking:smart_link_list', 'linking:smart_link_create'], [smart_link_list, smart_link_create], menu_name='secondary_menu')
register_links(SmartLinkCondition, [smart_link_condition_edit, smart_link_condition_delete])
register_links(ResolvedSmartLink, [smart_link_instance_view])
register_links(['linking:smart_link_condition_list', 'linking:smart_link_condition_create', 'linking:smart_link_condition_edit', 'linking:smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar')
register_setup(smart_link_setup)
class_permissions(SmartLink, [
ACLS_EDIT_ACL, ACLS_VIEW_ACL, PERMISSION_SMART_LINK_DELETE,
PERMISSION_SMART_LINK_EDIT, PERMISSION_SMART_LINK_VIEW
])

View File

@@ -0,0 +1,43 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL
from documents.models import Document
from navigation.api import register_links
from project_setup.api import register_setup
from .classes import ResolvedSmartLink
from .links import (
smart_link_acl_list, smart_link_create, smart_link_condition_create,
smart_link_condition_delete, smart_link_condition_edit,
smart_link_condition_list, smart_link_delete, smart_link_document_types,
smart_link_edit, smart_link_instance_view,
smart_link_instances_for_document, smart_link_list, smart_link_setup
)
from .models import SmartLink, SmartLinkCondition
from .permissions import (
PERMISSION_SMART_LINK_DELETE, PERMISSION_SMART_LINK_EDIT,
PERMISSION_SMART_LINK_VIEW
)
class LinkingApp(apps.AppConfig):
name = 'linking'
verbose_name = _('Linking')
def ready(self):
register_links(Document, [smart_link_instances_for_document], menu_name='form_header')
register_links(SmartLink, [smart_link_edit, smart_link_document_types, smart_link_condition_list, smart_link_acl_list, smart_link_delete])
register_links([SmartLink, 'linking:smart_link_list', 'linking:smart_link_create'], [smart_link_list, smart_link_create], menu_name='secondary_menu')
register_links(SmartLinkCondition, [smart_link_condition_edit, smart_link_condition_delete])
register_links(ResolvedSmartLink, [smart_link_instance_view])
register_links(['linking:smart_link_condition_list', 'linking:smart_link_condition_create', 'linking:smart_link_condition_edit', 'linking:smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar')
register_setup(smart_link_setup)
class_permissions(SmartLink, [
ACLS_EDIT_ACL, ACLS_VIEW_ACL, PERMISSION_SMART_LINK_DELETE,
PERMISSION_SMART_LINK_EDIT, PERMISSION_SMART_LINK_VIEW
])

View File

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from documents.models import Document, DocumentType
@@ -14,7 +13,7 @@ from .managers import SmartLinkManager
class SmartLink(models.Model):
title = models.CharField(max_length=96, verbose_name=_('Title'))
dynamic_title = models.CharField(blank=True, max_length=96, verbose_name=_('Dynamic title'), help_text=ugettext('This expression will be evaluated against the current selected document.'))
dynamic_title = models.CharField(blank=True, max_length=96, verbose_name=_('Dynamic title'), help_text=_('This expression will be evaluated against the current selected document.'))
enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
document_types = models.ManyToManyField(DocumentType, verbose_name=_('Document types'))
@@ -65,7 +64,7 @@ class SmartLinkCondition(models.Model):
inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_('The inclusion is ignored for the first item.'))
foreign_document_data = models.CharField(max_length=128, verbose_name=_('Foreign document attribute'), help_text=_('This represents the metadata of all other documents.'))
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES)
expression = models.TextField(verbose_name=_('Expression'), help_text=ugettext('This expression will be evaluated against the current document.'))
expression = models.TextField(verbose_name=_('Expression'), help_text=_('This expression will be evaluated against the current document.'))
negated = models.BooleanField(default=False, verbose_name=_('Negated'), help_text=_('Inverts the logic of the operator.'))
enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))

View File

@@ -0,0 +1,9 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
class LockManagerApp(apps.AppConfig):
name = 'lock_manager'
verbose_name = _('Lock manager')

View File

@@ -1,14 +1 @@
from acls.api import class_permissions
from documents.models import Document
from navigation.api import register_links
from .links import send_document_link, send_document
from .permissions import (
PERMISSION_MAILING_LINK, PERMISSION_MAILING_SEND_DOCUMENT
)
register_links([Document], [send_document_link, send_document])
class_permissions(Document, [
PERMISSION_MAILING_LINK, PERMISSION_MAILING_SEND_DOCUMENT
])

25
mayan/apps/mailer/apps.py Normal file
View File

@@ -0,0 +1,25 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from documents.models import Document
from navigation.api import register_links
from .links import send_document_link, send_document
from .permissions import (
PERMISSION_MAILING_LINK, PERMISSION_MAILING_SEND_DOCUMENT
)
class MailerApp(apps.AppConfig):
name = 'mailer'
verbose_name = _('Mailer')
def ready(self):
register_links([Document], [send_document_link, send_document])
class_permissions(Document, [
PERMISSION_MAILING_LINK, PERMISSION_MAILING_SEND_DOCUMENT
])

View File

@@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@@ -1,14 +1,2 @@
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
from project_setup.api import register_setup
from project_tools.api import register_tool
from .links import admin_site, maintenance_menu
from .classes import FrontPageButton # NOQA
register_top_menu('home', link={'text': _('Home'), 'view': 'main:home', 'famfam': 'house'}, position=0)
register_setup(admin_site)
register_tool(maintenance_menu)

20
mayan/apps/main/apps.py Normal file
View File

@@ -0,0 +1,20 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
from project_setup.api import register_setup
from project_tools.api import register_tool
from .links import admin_site, maintenance_menu
class MainApp(apps.AppConfig):
name = 'main'
verbose_name = _('Main')
def ready(self):
register_top_menu('home', link={'text': _('Home'), 'view': 'main:home', 'famfam': 'house'}, position=0)
register_setup(admin_site)
register_tool(maintenance_menu)

View File

@@ -1,94 +1 @@
from __future__ import unicode_literals
import logging
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate
from documents.models import Document, DocumentType
from documents.signals import post_document_type_change
from navigation.api import register_links, register_model_list_columns
from navigation.links import link_spacer
from project_setup.api import register_setup
from project_tools.api import register_tool
from rest_api.classes import APIEndPoint
from .api import get_metadata_string
from .classes import DocumentMetadataHelper
from .links import (
metadata_add, metadata_edit, metadata_multiple_add, metadata_multiple_edit,
metadata_multiple_remove, metadata_remove, metadata_view,
setup_document_type_metadata, setup_document_type_metadata_required,
setup_metadata_type_create, setup_metadata_type_delete,
setup_metadata_type_edit, setup_metadata_type_list,
link_documents_missing_required_metadata
)
from .models import DocumentMetadata, DocumentTypeMetadataType, MetadataType
from .permissions import (
PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_EDIT,
PERMISSION_METADATA_DOCUMENT_REMOVE, PERMISSION_METADATA_DOCUMENT_VIEW
)
from .tasks import task_add_required_metadata_type, task_remove_metadata_type
logger = logging.getLogger(__name__)
@receiver(post_save, dispatch_uid='post_document_type_metadata_type_add', sender=DocumentTypeMetadataType)
def post_document_type_metadata_type_add(sender, instance, created, **kwargs):
logger.debug('instance: %s', instance)
if created and instance.required:
task_add_required_metadata_type.apply_async(kwargs={'document_type_id': instance.document_type.pk, 'metadata_type_id': instance.metadata_type.pk}, queue='metadata')
@receiver(post_delete, dispatch_uid='post_document_type_metadata_type_delete', sender=DocumentTypeMetadataType)
def post_document_type_metadata_type_delete(sender, instance, **kwargs):
logger.debug('instance: %s', instance)
task_remove_metadata_type.apply_async(kwargs={'document_type_id': instance.document_type.pk, 'metadata_type_id': instance.metadata_type.pk}, queue='metadata')
@receiver(post_document_type_change, dispatch_uid='post_post_document_type_change_metadata', sender=Document)
def post_post_document_type_change_metadata(sender, instance, **kwargs):
logger.debug('received post_document_type_change')
logger.debug('instance: %s', instance)
# Delete existing document metadata
for metadata in instance.metadata.all():
metadata.delete(enforce_required=False)
# Add new document type metadata types to document
for document_type_metadata_type in instance.document_type.metadata.filter(required=True):
DocumentMetadata.objects.create(document=instance, metadata_type=document_type_metadata_type.metadata_type, value=None)
Document.add_to_class('metadata_value_of', DocumentMetadataHelper.constructor)
register_links(['metadata:metadata_add', 'metadata:metadata_edit', 'metadata:metadata_remove', 'metadata:metadata_view'], [metadata_add, metadata_edit, metadata_remove], menu_name='sidebar')
register_links(Document, [metadata_view], menu_name='form_header')
register_links([Document], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove, link_spacer], menu_name='multi_item_links')
register_links(DocumentType, [setup_document_type_metadata, setup_document_type_metadata_required])
register_links(MetadataType, [setup_metadata_type_edit, setup_metadata_type_delete])
register_links([MetadataType, 'metadata:setup_metadata_type_list', 'metadata:setup_metadata_type_create'], [setup_metadata_type_list, setup_metadata_type_create], menu_name='secondary_menu')
register_setup(setup_metadata_type_list)
register_tool(link_documents_missing_required_metadata)
class_permissions(Document, [
PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_EDIT,
PERMISSION_METADATA_DOCUMENT_REMOVE, PERMISSION_METADATA_DOCUMENT_VIEW,
])
register_model_list_columns(Document, [
{
'name': _('Metadata'), 'attribute': encapsulate(lambda x: get_metadata_string(x))
},
])
APIEndPoint('metadata')
ModelAttribute(Document, 'metadata__metadata_type__name', label=_('Metadata type name'), type_name='query')
ModelAttribute(Document, 'metadata__value', label=_('Metadata type value'), type_name='query')
ModelAttribute(Document, 'metadata', type_name='related', description=_('Queryset containing a MetadataType instance reference and a value for that metadata type'))
ModelAttribute(Document, 'metadata_value_of', label=_('Value of a metadata'), description=_('Return the value of a specific document metadata'), type_name=['property', 'indexing'])

100
mayan/apps/metadata/apps.py Normal file
View File

@@ -0,0 +1,100 @@
from __future__ import unicode_literals
import logging
from django import apps
from django.db.models.signals import post_delete, post_save
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate
from documents.models import Document, DocumentType
from documents.signals import post_document_type_change
from navigation.api import register_links, register_model_list_columns
from navigation.links import link_spacer
from project_setup.api import register_setup
from project_tools.api import register_tool
from rest_api.classes import APIEndPoint
from .api import get_metadata_string
from .classes import DocumentMetadataHelper
from .links import (
metadata_add, metadata_edit, metadata_multiple_add, metadata_multiple_edit,
metadata_multiple_remove, metadata_remove, metadata_view,
setup_document_type_metadata, setup_document_type_metadata_required,
setup_metadata_type_create, setup_metadata_type_delete,
setup_metadata_type_edit, setup_metadata_type_list,
link_documents_missing_required_metadata
)
from .models import DocumentMetadata, DocumentTypeMetadataType, MetadataType
from .permissions import (
PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_EDIT,
PERMISSION_METADATA_DOCUMENT_REMOVE, PERMISSION_METADATA_DOCUMENT_VIEW
)
from .tasks import task_add_required_metadata_type, task_remove_metadata_type
logger = logging.getLogger(__name__)
def post_document_type_metadata_type_add(sender, instance, created, **kwargs):
logger.debug('instance: %s', instance)
if created and instance.required:
task_add_required_metadata_type.apply_async(kwargs={'document_type_id': instance.document_type.pk, 'metadata_type_id': instance.metadata_type.pk}, queue='metadata')
def post_document_type_metadata_type_delete(sender, instance, **kwargs):
logger.debug('instance: %s', instance)
task_remove_metadata_type.apply_async(kwargs={'document_type_id': instance.document_type.pk, 'metadata_type_id': instance.metadata_type.pk}, queue='metadata')
def post_post_document_type_change_metadata(sender, instance, **kwargs):
logger.debug('received post_document_type_change')
logger.debug('instance: %s', instance)
# Delete existing document metadata
for metadata in instance.metadata.all():
metadata.delete(enforce_required=False)
# Add new document type metadata types to document
for document_type_metadata_type in instance.document_type.metadata.filter(required=True):
DocumentMetadata.objects.create(document=instance, metadata_type=document_type_metadata_type.metadata_type, value=None)
class MetadataApp(apps.AppConfig):
name = 'metadata'
verbose_name = _('Metadata')
def ready(self):
post_save.connect(post_document_type_metadata_type_add, dispatch_uid='post_document_type_metadata_type_add', sender=DocumentTypeMetadataType)
post_delete.connect(post_document_type_metadata_type_delete, dispatch_uid='post_document_type_metadata_type_delete', sender=DocumentTypeMetadataType)
post_document_type_change.connect(post_post_document_type_change_metadata, dispatch_uid='post_post_document_type_change_metadata', sender=Document)
Document.add_to_class('metadata_value_of', DocumentMetadataHelper.constructor)
register_links(['metadata:metadata_add', 'metadata:metadata_edit', 'metadata:metadata_remove', 'metadata:metadata_view'], [metadata_add, metadata_edit, metadata_remove], menu_name='sidebar')
register_links(Document, [metadata_view], menu_name='form_header')
register_links([Document], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove, link_spacer], menu_name='multi_item_links')
register_links(DocumentType, [setup_document_type_metadata, setup_document_type_metadata_required])
register_links(MetadataType, [setup_metadata_type_edit, setup_metadata_type_delete])
register_links([MetadataType, 'metadata:setup_metadata_type_list', 'metadata:setup_metadata_type_create'], [setup_metadata_type_list, setup_metadata_type_create], menu_name='secondary_menu')
register_setup(setup_metadata_type_list)
register_tool(link_documents_missing_required_metadata)
class_permissions(Document, [
PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_EDIT,
PERMISSION_METADATA_DOCUMENT_REMOVE, PERMISSION_METADATA_DOCUMENT_VIEW,
])
register_model_list_columns(Document, [
{
'name': _('Metadata'), 'attribute': encapsulate(lambda x: get_metadata_string(x))
},
])
APIEndPoint('metadata')
ModelAttribute(Document, 'metadata__metadata_type__name', label=_('Metadata type name'), type_name='query')
ModelAttribute(Document, 'metadata__value', label=_('Metadata type value'), type_name='query')
ModelAttribute(Document, 'metadata', type_name='related', description=_('Queryset containing a MetadataType instance reference and a value for that metadata type'))
ModelAttribute(Document, 'metadata_value_of', label=_('Value of a metadata'), description=_('Return the value of a specific document metadata'), type_name=['property', 'indexing'])

View File

@@ -1,75 +1 @@
from __future__ import unicode_literals
import logging
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.utils import encapsulate
from documents.models import Document, DocumentVersion
from documents.signals import post_version_upload
from documents.widgets import document_link
from main.api import register_maintenance_links
from navigation.api import register_links, register_model_list_columns
from navigation.links import link_spacer
from project_tools.api import register_tool
from rest_api.classes import APIEndPoint
from .links import (
link_document_all_ocr_cleanup, link_document_submit,
link_document_submit_multiple, link_entry_delete,
link_entry_delete_multiple, link_entry_list, link_entry_re_queue,
link_entry_re_queue_multiple
)
from .models import DocumentVersionOCRError
from .permissions import PERMISSION_OCR_DOCUMENT
from .tasks import task_do_ocr
logger = logging.getLogger(__name__)
register_links(Document, [link_document_submit])
register_links([Document], [link_document_submit_multiple, link_spacer], menu_name='multi_item_links')
register_links([DocumentVersionOCRError], [link_entry_re_queue_multiple, link_entry_delete_multiple], menu_name='multi_item_links')
register_links([DocumentVersionOCRError], [link_entry_re_queue, link_entry_delete])
register_links(['ocr:entry_list', 'ocr:entry_delete_multiple', 'ocr:entry_re_queue_multiple', DocumentVersionOCRError], [link_entry_list], menu_name='secondary_menu')
register_maintenance_links([link_document_all_ocr_cleanup], namespace='ocr', title=_('OCR'))
def document_ocr_submit(self):
task_do_ocr.apply_async(args=[self.latest_version.pk], queue='ocr')
def document_version_ocr_submit(self):
task_do_ocr.apply_async(args=[self.pk], queue='ocr')
@receiver(post_version_upload, dispatch_uid='post_version_upload_ocr', sender=DocumentVersion)
def post_version_upload_ocr(sender, instance, **kwargs):
logger.debug('received post_version_upload')
logger.debug('instance pk: %s', instance.pk)
if instance.document.document_type.ocr:
instance.submit_for_ocr()
Document.add_to_class('submit_for_ocr', document_ocr_submit)
DocumentVersion.add_to_class('submit_for_ocr', document_version_ocr_submit)
class_permissions(Document, [PERMISSION_OCR_DOCUMENT])
register_tool(link_entry_list)
APIEndPoint('ocr')
register_model_list_columns(DocumentVersionOCRError, [
{
'name': _('Document'), 'attribute': encapsulate(lambda entry: document_link(entry.document_version.document))
},
{
'name': _('Added'), 'attribute': 'datetime_submitted'
},
{
'name': _('Result'), 'attribute': 'result'
},
])

81
mayan/apps/ocr/apps.py Normal file
View File

@@ -0,0 +1,81 @@
from __future__ import unicode_literals
import logging
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.utils import encapsulate
from documents.models import Document, DocumentVersion
from documents.signals import post_version_upload
from documents.widgets import document_link
from main.api import register_maintenance_links
from navigation.api import register_links, register_model_list_columns
from navigation.links import link_spacer
from project_tools.api import register_tool
from rest_api.classes import APIEndPoint
from .links import (
link_document_all_ocr_cleanup, link_document_submit,
link_document_submit_multiple, link_entry_delete,
link_entry_delete_multiple, link_entry_list, link_entry_re_queue,
link_entry_re_queue_multiple
)
from .models import DocumentVersionOCRError
from .permissions import PERMISSION_OCR_DOCUMENT
from .tasks import task_do_ocr
logger = logging.getLogger(__name__)
def document_ocr_submit(self):
task_do_ocr.apply_async(args=[self.latest_version.pk], queue='ocr')
def document_version_ocr_submit(self):
task_do_ocr.apply_async(args=[self.pk], queue='ocr')
def post_version_upload_ocr(sender, instance, **kwargs):
logger.debug('received post_version_upload')
logger.debug('instance pk: %s', instance.pk)
if instance.document.document_type.ocr:
instance.submit_for_ocr()
class OCRApp(apps.AppConfig):
name = 'ocr'
verbose_name = _('OCR')
def ready(self):
register_links(Document, [link_document_submit])
register_links([Document], [link_document_submit_multiple, link_spacer], menu_name='multi_item_links')
register_links([DocumentVersionOCRError], [link_entry_re_queue_multiple, link_entry_delete_multiple], menu_name='multi_item_links')
register_links([DocumentVersionOCRError], [link_entry_re_queue, link_entry_delete])
register_links(['ocr:entry_list', 'ocr:entry_delete_multiple', 'ocr:entry_re_queue_multiple', DocumentVersionOCRError], [link_entry_list], menu_name='secondary_menu')
register_maintenance_links([link_document_all_ocr_cleanup], namespace='ocr', title=_('OCR'))
post_version_upload.connect(post_version_upload_ocr, dispatch_uid='post_version_upload_ocr', sender=DocumentVersion)
Document.add_to_class('submit_for_ocr', document_ocr_submit)
DocumentVersion.add_to_class('submit_for_ocr', document_version_ocr_submit)
class_permissions(Document, [PERMISSION_OCR_DOCUMENT])
register_tool(link_entry_list)
APIEndPoint('ocr')
register_model_list_columns(DocumentVersionOCRError, [
{
'name': _('Document'), 'attribute': encapsulate(lambda entry: document_link(entry.document_version.document))
},
{
'name': _('Added'), 'attribute': 'datetime_submitted'
},
{
'name': _('Result'), 'attribute': 'result'
},
])

View File

@@ -1,42 +1 @@
from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.signals import post_save
from navigation.api import register_links
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .models import Permission, Role
from .links import (
permission_grant, permission_revoke, role_create, role_delete, role_edit,
role_list, role_members, role_permissions
)
from .settings import DEFAULT_ROLES
register_links(Role, [role_edit, role_members, role_permissions, role_delete])
register_links([Role, 'permissions:role_create', 'permissions:role_list'], [role_list, role_create], menu_name='secondary_menu')
register_links(['permissions:role_permissions'], [permission_grant, permission_revoke], menu_name='multi_item_links')
def user_post_save(sender, instance, **kwargs):
if kwargs.get('created', False):
for default_role in DEFAULT_ROLES:
if isinstance(default_role, Role):
# If a model is passed, execute method
default_role.add_member(instance)
else:
# If a role name is passed, lookup the corresponding model
try:
role = Role.objects.get(name=default_role)
role.add_member(instance)
except ObjectDoesNotExist:
pass
post_save.connect(user_post_save, sender=User)
register_setup(role_list)
APIEndPoint('permissions')

View File

@@ -0,0 +1,49 @@
from __future__ import unicode_literals
from django import apps
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_links
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .models import Permission, Role
from .links import (
permission_grant, permission_revoke, role_create, role_delete, role_edit,
role_list, role_members, role_permissions
)
from .settings import DEFAULT_ROLES
def user_post_save(sender, instance, **kwargs):
if kwargs.get('created', False):
for default_role in DEFAULT_ROLES:
if isinstance(default_role, Role):
# If a model is passed, execute method
default_role.add_member(instance)
else:
# If a role name is passed, lookup the corresponding model
try:
role = Role.objects.get(name=default_role)
role.add_member(instance)
except ObjectDoesNotExist:
pass
class PermissionsApp(apps.AppConfig):
name = 'permissions'
verbose_name = _('Permissions')
def ready(self):
register_links(Role, [role_edit, role_members, role_permissions, role_delete])
register_links([Role, 'permissions:role_create', 'permissions:role_list'], [role_list, role_create], menu_name='secondary_menu')
register_links(['permissions:role_permissions'], [permission_grant, permission_revoke], menu_name='multi_item_links')
post_save.connect(user_post_save, sender=User)
register_setup(role_list)
APIEndPoint('permissions')

View File

@@ -1,7 +1 @@
from __future__ import unicode_literals
from navigation.api import register_top_menu
from .links import link_setup
setup_link = register_top_menu('setup_menu', link=link_setup, position=-2)

View File

@@ -0,0 +1,16 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
from .links import link_setup
class ProjectSetupApp(apps.AppConfig):
name = 'project_setup'
verbose_name = _('Project setup')
def ready(self):
setup_link = register_top_menu('setup_menu', link=link_setup, position=-2)

View File

@@ -1,7 +1,5 @@
from __future__ import unicode_literals
from navigation.api import register_top_menu
from .links import link_tools
tool_link = register_top_menu('tools', link=link_tools, position=-3)

View File

@@ -0,0 +1,17 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
from .links import link_tools
class ProjectToolsApp(apps.AppConfig):
name = 'project_tools'
verbose_name = _('Project tools')
def ready(self):
tool_link = register_top_menu('tools', link=link_tools, position=-3)

View File

@@ -1,11 +1 @@
from __future__ import unicode_literals
from project_tools.api import register_tool
from .classes import APIEndPoint
from .links import link_api, link_api_documentation
APIEndPoint('rest_api')
register_tool(link_api)
register_tool(link_api_documentation)

View File

@@ -0,0 +1,20 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from project_tools.api import register_tool
from .classes import APIEndPoint
from .links import link_api, link_api_documentation
class RESTAPIApp(apps.AppConfig):
name = 'rest_api'
verbose_name = _('REST API')
def ready(self):
APIEndPoint('rest_api')
register_tool(link_api)
register_tool(link_api_documentation)

View File

@@ -1,5 +1 @@
from project_setup.api import register_setup
from .links import check_settings
register_setup(check_settings)

View File

@@ -0,0 +1,16 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from project_setup.api import register_setup
from .links import check_settings
class SmartSettingsApp(apps.AppConfig):
name = 'smart_settings'
verbose_name = _('Smart settings')
def ready(self):
register_setup(check_settings)

View File

@@ -1,47 +1 @@
from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext_lazy as _
from common.utils import encapsulate
from documents.links import document_list_recent, document_list
from documents.models import Document
from main import FrontPageButton
from navigation.api import register_links, register_model_list_columns
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .classes import StagingFile
from .links import (
document_create_multiple, document_create_siblings, setup_sources,
setup_source_create_imap_email, setup_source_create_pop3_email,
setup_source_create_watch_folder, setup_source_create_webform,
setup_source_create_staging_folder, setup_source_delete, setup_source_edit,
setup_source_transformation_create, setup_source_transformation_delete,
setup_source_transformation_edit, setup_source_transformation_list,
staging_file_delete, upload_version
)
from .models import Source, SourceTransformation
from .widgets import staging_file_thumbnail
register_model_list_columns(StagingFile, [
{
'name': _('Thumbnail'), 'attribute':
encapsulate(lambda x: staging_file_thumbnail(x, gallery_name='sources:staging_list', title=x.filename, size='100'))
},
])
register_links([StagingFile], [staging_file_delete])
register_links([Source, 'sources:setup_source_list', 'sources:setup_source_create'], [setup_sources, setup_source_create_webform, setup_source_create_staging_folder, setup_source_create_pop3_email, setup_source_create_imap_email, setup_source_create_watch_folder], menu_name='secondary_menu')
register_links([Source], [setup_source_edit, setup_source_transformation_list, setup_source_delete])
register_links(SourceTransformation, [setup_source_transformation_edit, setup_source_transformation_delete])
register_links([SourceTransformation, 'sources:setup_source_transformation_create', 'sources:setup_source_transformation_list'], [setup_source_transformation_create], menu_name='sidebar')
register_links(['documents:document_version_list', 'documents:upload_version', 'documents:document_version_revert'], [upload_version], menu_name='sidebar')
register_links([Document, 'documents:document_list_recent', 'documents:document_list', 'sources:document_create', 'sources:document_create_multiple', 'sources:upload_interactive', 'sources:staging_file_delete'], [document_create_multiple], menu_name='secondary_menu')
register_links(Document, [document_create_siblings])
register_links(['sources:document_create', 'sources:document_create_multiple', 'sources:upload_interactive', 'sources:staging_file_delete'], [document_list_recent, document_list], menu_name='secondary_menu')
register_setup(setup_sources)
APIEndPoint('sources')
FrontPageButton(link=document_create_multiple)

View File

@@ -0,0 +1,54 @@
from __future__ import absolute_import, unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from common.utils import encapsulate
from documents.links import document_list_recent, document_list
from documents.models import Document
from main import FrontPageButton
from navigation.api import register_links, register_model_list_columns
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .classes import StagingFile
from .links import (
document_create_multiple, document_create_siblings, setup_sources,
setup_source_create_imap_email, setup_source_create_pop3_email,
setup_source_create_watch_folder, setup_source_create_webform,
setup_source_create_staging_folder, setup_source_delete, setup_source_edit,
setup_source_transformation_create, setup_source_transformation_delete,
setup_source_transformation_edit, setup_source_transformation_list,
staging_file_delete, upload_version
)
from .models import Source, SourceTransformation
from .widgets import staging_file_thumbnail
class SourcesApp(apps.AppConfig):
name = 'sources'
verbose_name = _('Sources')
def ready(self):
register_model_list_columns(StagingFile, [
{
'name': _('Thumbnail'), 'attribute':
encapsulate(lambda x: staging_file_thumbnail(x, gallery_name='sources:staging_list', title=x.filename, size='100'))
},
])
register_links([StagingFile], [staging_file_delete])
register_links([Source, 'sources:setup_source_list', 'sources:setup_source_create'], [setup_sources, setup_source_create_webform, setup_source_create_staging_folder, setup_source_create_pop3_email, setup_source_create_imap_email, setup_source_create_watch_folder], menu_name='secondary_menu')
register_links([Source], [setup_source_edit, setup_source_transformation_list, setup_source_delete])
register_links(SourceTransformation, [setup_source_transformation_edit, setup_source_transformation_delete])
register_links([SourceTransformation, 'sources:setup_source_transformation_create', 'sources:setup_source_transformation_list'], [setup_source_transformation_create], menu_name='sidebar')
register_links(['documents:document_version_list', 'documents:upload_version', 'documents:document_version_revert'], [upload_version], menu_name='sidebar')
register_links([Document, 'documents:document_list_recent', 'documents:document_list', 'sources:document_create', 'sources:document_create_multiple', 'sources:upload_interactive', 'sources:staging_file_delete'], [document_create_multiple], menu_name='secondary_menu')
register_links(Document, [document_create_siblings])
register_links(['sources:document_create', 'sources:document_create_multiple', 'sources:upload_interactive', 'sources:staging_file_delete'], [document_list_recent, document_list], menu_name='secondary_menu')
register_setup(setup_sources)
APIEndPoint('sources')
FrontPageButton(link=document_create_multiple)

View File

@@ -76,11 +76,13 @@ class WebFormUploadForm(UploadBaseForm):
class WebFormSetupForm(forms.ModelForm):
class Meta:
fields = ('title', 'enabled', 'uncompress')
model = WebFormSource
class StagingFolderSetupForm(forms.ModelForm):
class Meta:
fields = ('title', 'enabled', 'folder_path', 'preview_width', 'preview_height', 'uncompress', 'delete_after_upload')
model = StagingFolderSource
@@ -93,21 +95,25 @@ class EmailSetupBaseForm(forms.ModelForm):
class POP3EmailSetupForm(EmailSetupBaseForm):
class Meta(EmailSetupBaseForm.Meta):
fields = ('title', 'enabled', 'interval', 'document_type', 'uncompress', 'host', 'ssl', 'port', 'username', 'password', 'timeout')
model = POP3Email
class IMAPEmailSetupForm(EmailSetupBaseForm):
class Meta(EmailSetupBaseForm.Meta):
fields = ('title', 'enabled', 'interval', 'document_type', 'uncompress', 'host', 'ssl', 'port', 'username', 'password', 'mailbox')
model = IMAPEmail
class WatchFolderSetupForm(forms.ModelForm):
class Meta:
fields = ('title', 'enabled', 'interval', 'document_type', 'uncompress', 'folder_path')
model = WatchFolderSource
class SourceTransformationForm(forms.ModelForm):
class Meta:
fields = ('order', 'transformation', 'arguments')
model = SourceTransformation
def __init__(self, *args, **kwargs):

View File

@@ -210,7 +210,7 @@ class IntervalBaseModel(OutOfProcessSource):
class EmailBaseModel(IntervalBaseModel):
host = models.CharField(max_length=128, verbose_name=_('Host'))
ssl = models.BooleanField(verbose_name=_('SSL'))
ssl = models.BooleanField(default=True, verbose_name=_('SSL'))
port = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('Port'), help_text=_('Typical choices are 110 for POP3, 995 for POP3 over SSL, 143 for IMAP, 993 for IMAP over SSL.'))
username = models.CharField(max_length=96, verbose_name=_('Username'))
password = models.CharField(max_length=96, verbose_name=_('Password'))
@@ -384,7 +384,7 @@ class SourceTransformation(models.Model):
content_object = generic.GenericForeignKey('content_type', 'object_id')
order = models.PositiveIntegerField(default=0, blank=True, null=True, verbose_name=_('Order'), db_index=True)
transformation = models.CharField(choices=get_available_transformations_choices(), max_length=128, verbose_name=_('Transformation'))
arguments = models.TextField(blank=True, null=True, verbose_name=_('Arguments'), help_text=_('Use dictionaries to indentify arguments, example: %s') % '{\'degrees\':90}', validators=[ArgumentsValidator()])
arguments = models.TextField(blank=True, null=True, verbose_name=_('Arguments'), help_text=_('Use dictionaries to indentify arguments, example: {\'degrees\':90}'), validators=[ArgumentsValidator()])
objects = models.Manager()
transformations = SourceTransformationManager()

View File

@@ -1,16 +1 @@
from __future__ import unicode_literals
from navigation.api import register_links
from project_tools.api import register_tool
from .classes import Statistic, StatisticNamespace
from .links import (
link_execute, link_namespace_details, link_namespace_list,
link_statistics
)
register_links(StatisticNamespace, [link_namespace_details])
register_links([StatisticNamespace, 'statistics:namespace_list', 'statistics:execute'], [link_namespace_list], menu_name='secondary_menu')
register_links(Statistic, [link_execute])
register_tool(link_statistics)

View File

@@ -0,0 +1,25 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_links
from project_tools.api import register_tool
from .classes import Statistic, StatisticNamespace
from .links import (
link_execute, link_namespace_details, link_namespace_list,
link_statistics
)
class StatisticsApp(apps.AppConfig):
name = 'statistics'
verbose_name = _('Statistics')
def ready(self):
register_links(StatisticNamespace, [link_namespace_details])
register_links([StatisticNamespace, 'statistics:namespace_list', 'statistics:execute'], [link_namespace_list], menu_name='secondary_menu')
register_links(Statistic, [link_execute])
register_tool(link_statistics)

View File

@@ -1,63 +1 @@
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.utils import encapsulate
from documents.models import Document
from navigation.api import (
register_links, register_model_list_columns, register_top_menu
)
from navigation.links import link_spacer
from rest_api.classes import APIEndPoint
from .links import (
multiple_documents_selection_tag_remove,
single_document_multiple_tag_remove, tag_acl_list, tag_attach, tag_create,
tag_delete, tag_document_list, tag_edit, tag_list, tag_multiple_attach,
tag_multiple_delete, tag_tagged_item_list
)
from .models import Tag
from .permissions import (
PERMISSION_TAG_ATTACH, PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT,
PERMISSION_TAG_REMOVE, PERMISSION_TAG_VIEW
)
from .widgets import get_tags_inline_widget_simple, single_tag_widget
class_permissions(Document, [
PERMISSION_TAG_ATTACH, PERMISSION_TAG_REMOVE,
])
class_permissions(Tag, [
PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT, PERMISSION_TAG_VIEW,
])
APIEndPoint('tags')
register_model_list_columns(Tag, [
{
'name': _('Preview'),
'attribute': encapsulate(lambda x: single_tag_widget(x))
},
{
'name': _('Tagged items'),
'attribute': encapsulate(lambda x: x.documents.count())
}
])
register_model_list_columns(Document, [
{
'name': _('Tags'), 'attribute':
encapsulate(lambda x: get_tags_inline_widget_simple(x))
},
])
register_top_menu('tags', link={'text': _('Tags'), 'view': 'tags:tag_list', 'famfam': 'tag_blue'})
register_links(Tag, [tag_tagged_item_list, tag_edit, tag_acl_list, tag_delete])
register_links([Tag], [tag_multiple_delete], menu_name='multi_item_links')
register_links([Tag, 'tags:tag_list', 'tags:tag_create'], [tag_list, tag_create], menu_name='secondary_menu')
register_links(Document, [tag_document_list], menu_name='form_header')
register_links(['tags:document_tags', 'tags:tag_remove', 'tags:tag_multiple_remove', 'tags:tag_attach'], [tag_attach], menu_name='sidebar')
register_links(['tags:document_tags'], [single_document_multiple_tag_remove], menu_name='multi_item_links')
register_links([Document], [tag_multiple_attach, multiple_documents_selection_tag_remove, link_spacer], menu_name='multi_item_links')

70
mayan/apps/tags/apps.py Normal file
View File

@@ -0,0 +1,70 @@
from __future__ import unicode_literals
from django import apps
from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions
from common.utils import encapsulate
from documents.models import Document
from navigation.api import (
register_links, register_model_list_columns, register_top_menu
)
from navigation.links import link_spacer
from rest_api.classes import APIEndPoint
from .links import (
multiple_documents_selection_tag_remove,
single_document_multiple_tag_remove, tag_acl_list, tag_attach, tag_create,
tag_delete, tag_document_list, tag_edit, tag_list, tag_multiple_attach,
tag_multiple_delete, tag_tagged_item_list
)
from .models import Tag
from .permissions import (
PERMISSION_TAG_ATTACH, PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT,
PERMISSION_TAG_REMOVE, PERMISSION_TAG_VIEW
)
from .widgets import get_tags_inline_widget_simple, single_tag_widget
class TagsApp(apps.AppConfig):
name = 'tags'
verbose_name = _('Tags')
def ready(self):
class_permissions(Document, [
PERMISSION_TAG_ATTACH, PERMISSION_TAG_REMOVE,
])
class_permissions(Tag, [
PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT, PERMISSION_TAG_VIEW,
])
APIEndPoint('tags')
register_model_list_columns(Tag, [
{
'name': _('Preview'),
'attribute': encapsulate(lambda x: single_tag_widget(x))
},
{
'name': _('Tagged items'),
'attribute': encapsulate(lambda x: x.documents.count())
}
])
register_model_list_columns(Document, [
{
'name': _('Tags'), 'attribute':
encapsulate(lambda x: get_tags_inline_widget_simple(x))
},
])
register_top_menu('tags', link={'text': _('Tags'), 'view': 'tags:tag_list', 'famfam': 'tag_blue'})
register_links(Tag, [tag_tagged_item_list, tag_edit, tag_acl_list, tag_delete])
register_links([Tag], [tag_multiple_delete], menu_name='multi_item_links')
register_links([Tag, 'tags:tag_list', 'tags:tag_create'], [tag_list, tag_create], menu_name='secondary_menu')
register_links(Document, [tag_document_list], menu_name='form_header')
register_links(['tags:document_tags', 'tags:tag_remove', 'tags:tag_multiple_remove', 'tags:tag_attach'], [tag_attach], menu_name='sidebar')
register_links(['tags:document_tags'], [single_document_multiple_tag_remove], menu_name='multi_item_links')
register_links([Document], [tag_multiple_attach, multiple_documents_selection_tag_remove, link_spacer], menu_name='multi_item_links')

View File

@@ -1,27 +1 @@
from __future__ import unicode_literals
from django.contrib.auth.models import User, Group
from navigation.api import register_links
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .links import (
group_add, group_delete, group_edit, group_list, group_members,
group_multiple_delete, group_setup, user_add, user_delete, user_edit,
user_groups, user_list, user_multiple_delete, user_multiple_set_password,
user_set_password, user_setup
)
register_links(User, [user_edit, user_set_password, user_groups, user_delete])
register_links([User, 'user_management:user_multiple_set_password', 'user_management:user_multiple_delete', 'user_management:user_list', 'user_management:user_add'], [user_list, user_add], menu_name='secondary_menu')
register_links(['user_management:user_list'], [user_multiple_set_password, user_multiple_delete], menu_name='multi_item_links')
register_links(Group, [group_edit, group_members, group_delete])
register_links(['user_management:group_multiple_delete', 'user_management:group_delete', 'user_management:group_edit', 'user_management:group_list', 'user_management:group_add', 'user_management:group_members'], [group_list, group_add], menu_name='secondary_menu')
register_links(['user_management:group_list'], [group_multiple_delete], menu_name='multi_item_links')
register_setup(user_setup)
register_setup(group_setup)
APIEndPoint('users', app_name='user_management')

View File

@@ -0,0 +1,40 @@
from __future__ import unicode_literals
from django import apps
from django.contrib.auth.models import User, Group
from django.utils.translation import ugettext_lazy as _
from actstream import registry
from navigation.api import register_links
from project_setup.api import register_setup
from rest_api.classes import APIEndPoint
from .links import (
group_add, group_delete, group_edit, group_list, group_members,
group_multiple_delete, group_setup, user_add, user_delete, user_edit,
user_groups, user_list, user_multiple_delete, user_multiple_set_password,
user_set_password, user_setup
)
class UserManagementApp(apps.AppConfig):
name = 'user_management'
verbose_name = _('User management')
def ready(self):
register_links(User, [user_edit, user_set_password, user_groups, user_delete])
register_links([User, 'user_management:user_multiple_set_password', 'user_management:user_multiple_delete', 'user_management:user_list', 'user_management:user_add'], [user_list, user_add], menu_name='secondary_menu')
register_links(['user_management:user_list'], [user_multiple_set_password, user_multiple_delete], menu_name='multi_item_links')
register_links(Group, [group_edit, group_members, group_delete])
register_links(['user_management:group_multiple_delete', 'user_management:group_delete', 'user_management:group_edit', 'user_management:group_list', 'user_management:group_add', 'user_management:group_members'], [group_list, group_add], menu_name='secondary_menu')
register_links(['user_management:group_list'], [group_multiple_delete], menu_name='multi_item_links')
register_setup(user_setup)
register_setup(group_setup)
APIEndPoint('users', app_name='user_management')
registry.register(User)
registry.register(Group)

View File

@@ -1,7 +0,0 @@
from django.db import models
from django.contrib.auth.models import User, Group
from actstream import registry
registry.register(User)
registry.register(Group)

View File

@@ -50,6 +50,7 @@ INSTALLED_APPS = (
'django.contrib.sites',
'django.contrib.staticfiles',
# 3rd party
'actstream',
'compressor',
'corsheaders',
'djcelery',
@@ -58,48 +59,44 @@ INSTALLED_APPS = (
'rest_framework',
'rest_framework.authtoken',
'solo',
'south',
# Base generic
'acls',
'common',
'acls.apps.ACLsApp',
'common.apps.CommonApp',
'converter',
'django_gpg',
'dynamic_search',
'lock_manager',
'django_gpg.apps.DjangoGPGApp',
'dynamic_search.apps.DynamicSearchApp',
'lock_manager.apps.LockManagerApp',
'mimetype',
'navigation',
'permissions',
'project_setup',
'project_tools',
'smart_settings',
'user_management',
'permissions.apps.PermissionsApp',
'project_setup.apps.ProjectSetupApp',
'project_tools.apps.ProjectToolsApp',
'smart_settings.apps.SmartSettingsApp',
'user_management.apps.UserManagementApp',
# Mayan EDMS
'appearance',
'checkouts',
'document_acls',
'document_comments',
'document_indexing',
'document_signatures',
'document_states',
'documents',
'events',
'folders',
'installation',
'linking',
'mailer',
'main',
'metadata',
'ocr',
'rest_api',
'sources',
'statistics',
'checkouts.apps.CheckoutsApp',
'document_acls.apps.DocumentACLsApp',
'document_comments.apps.DocumentCommentsApp',
'document_indexing.apps.DocumentIndexingApp',
'document_signatures.apps.DocumentSignaturesApp',
'document_states.apps.DocumentStatesApp',
'documents.apps.DocumentsApp',
'events.apps.EventsApp',
'folders.apps.FoldersApp',
'installation.apps.InstallationApp',
'linking.apps.LinkingApp',
'mailer.apps.MailerApp',
'main.apps.MainApp',
'metadata.apps.MetadataApp',
'ocr.apps.OCRApp',
'rest_api.apps.RESTAPIApp',
'sources.apps.SourcesApp',
'statistics.apps.StatisticsApp',
'storage',
'tags',
'tags.apps.TagsApp',
# Placed after rest_api to allow template overriding
'rest_framework_swagger',
# Must be last on Django < 1.7 as per documentation
# https://django-activity-stream.readthedocs.org/en/latest/installation.html
'actstream',
# Pagination app must go after the main app so that the main app can
# override the default pagination template
'pagination',

View File

@@ -1,7 +1,7 @@
celery==3.1.17
cssmin==0.2.0
Django==1.6.8
Django==1.7.7
django-activity-stream==0.5.1
django-celery==3.1.16
django-compressor==1.4
@@ -32,7 +32,6 @@ requests==2.4.3
sh==1.09
slate==0.3
South==1.0.2
unicode-slugify==0.1.1