diff --git a/mayan/apps/appearance/templates/appearance/generic_form_instance.html b/mayan/apps/appearance/templates/appearance/generic_form_instance.html
index 72e631d7cf..9eeef9aa9b 100644
--- a/mayan/apps/appearance/templates/appearance/generic_form_instance.html
+++ b/mayan/apps/appearance/templates/appearance/generic_form_instance.html
@@ -63,6 +63,12 @@
{% render_field field %}
+ {% elif field|widget_type == 'checkboxselectmultiple' %}
+ {% for option in field %}
+
+ {{ option.render }}
+
+ {% endfor %}
{% else %}
{% render_field field class+="form-control" %}
{% endif %}
diff --git a/mayan/apps/sources/literals.py b/mayan/apps/sources/literals.py
index 0c10517073..6605994b2c 100644
--- a/mayan/apps/sources/literals.py
+++ b/mayan/apps/sources/literals.py
@@ -36,3 +36,8 @@ DEFAULT_METADATA_ATTACHMENT_NAME = 'metadata.yaml'
DEFAULT_POP3_TIMEOUT = 60
DEFAULT_IMAP_MAILBOX = 'INBOX'
DEFAULT_SOURCE_TASK_RETRY_DELAY = 10
+
+# Upload wizard steps
+STEP_DOCUMENT_TYPE = '0'
+STEP_METADATA = '1'
+STEP_TAGS = '2'
diff --git a/mayan/apps/sources/models.py b/mayan/apps/sources/models.py
index 1df74b26e1..22ad807261 100644
--- a/mayan/apps/sources/models.py
+++ b/mayan/apps/sources/models.py
@@ -28,6 +28,7 @@ from documents.models import Document, DocumentType
from documents.settings import setting_language
from metadata.api import save_metadata_list, set_bulk_metadata
from metadata.models import MetadataType
+from tags.models import Tag
from .classes import Attachment, SourceUploadedFile, StagingFile
from .literals import (
@@ -59,7 +60,7 @@ class Source(models.Model):
def fullname(self):
return ' '.join([self.class_fullname(), '"%s"' % self.label])
- def upload_document(self, file_object, document_type, description=None, label=None, language=None, metadata_dict_list=None, metadata_dictionary=None, user=None):
+ def upload_document(self, file_object, document_type, description=None, label=None, language=None, metadata_dict_list=None, metadata_dictionary=None, tag_ids=None, user=None):
try:
with transaction.atomic():
document = Document.objects.create(
@@ -88,6 +89,10 @@ class Source(models.Model):
metadata_dictionary=metadata_dictionary
)
+ if tag_ids:
+ for tag in Tag.objects.filter(pk__in=tag_ids):
+ tag.documents.add(document)
+
except Exception as exception:
logger.critical(
'Unexpected exception while trying to create new document '
diff --git a/mayan/apps/sources/tasks.py b/mayan/apps/sources/tasks.py
index 5d75516dec..6d26b7fa8d 100644
--- a/mayan/apps/sources/tasks.py
+++ b/mayan/apps/sources/tasks.py
@@ -35,7 +35,7 @@ def task_check_interval_source(source_id):
@app.task(bind=True, default_retry_delay=DEFAULT_SOURCE_TASK_RETRY_DELAY, ignore_result=True)
-def task_upload_document(self, source_id, document_type_id, shared_uploaded_file_id, description=None, label=None, language=None, metadata_dict_list=None, user_id=None):
+def task_upload_document(self, source_id, document_type_id, shared_uploaded_file_id, description=None, label=None, language=None, metadata_dict_list=None, tag_ids=None, user_id=None):
SharedUploadedFile = apps.get_model(
app_label='common', model_name='SharedUploadedFile'
)
@@ -64,7 +64,8 @@ def task_upload_document(self, source_id, document_type_id, shared_uploaded_file
source.upload_document(
file_object=file_object, document_type=document_type,
description=description, label=label, language=language,
- metadata_dict_list=metadata_dict_list, user=user
+ metadata_dict_list=metadata_dict_list, user=user,
+ tag_ids=tag_ids
)
except OperationalError as exception:
@@ -85,7 +86,7 @@ def task_upload_document(self, source_id, document_type_id, shared_uploaded_file
@app.task(bind=True, default_retry_delay=DEFAULT_SOURCE_TASK_RETRY_DELAY, ignore_result=True)
-def task_source_handle_upload(self, document_type_id, shared_uploaded_file_id, source_id, description=None, expand=False, label=None, language=None, metadata_dict_list=None, skip_list=None, user_id=None):
+def task_source_handle_upload(self, document_type_id, shared_uploaded_file_id, source_id, description=None, expand=False, label=None, language=None, metadata_dict_list=None, skip_list=None, tag_ids=None, user_id=None):
SharedUploadedFile = apps.get_model(
app_label='common', model_name='SharedUploadedFile'
)
@@ -114,7 +115,7 @@ def task_source_handle_upload(self, document_type_id, shared_uploaded_file_id, s
'description': description, 'document_type_id': document_type.pk,
'label': label, 'language': language,
'metadata_dict_list': metadata_dict_list,
- 'source_id': source_id, 'user_id': user_id
+ 'source_id': source_id, 'tag_ids': tag_ids, 'user_id': user_id
}
if not skip_list:
@@ -147,7 +148,8 @@ def task_source_handle_upload(self, document_type_id, shared_uploaded_file_id, s
expand=expand, label=label,
language=language,
metadata_dict_list=metadata_dict_list,
- skip_list=skip_list, user_id=user_id
+ skip_list=skip_list, tag_ids=tag_ids,
+ user_id=user_id
)
return
else:
diff --git a/mayan/apps/sources/views.py b/mayan/apps/sources/views.py
index 5d5afdbaa1..ef75f158a7 100644
--- a/mayan/apps/sources/views.py
+++ b/mayan/apps/sources/views.py
@@ -264,6 +264,7 @@ class UploadInteractiveView(UploadBaseView):
metadata_dict_list=decode_metadata_from_url(self.request.GET),
shared_uploaded_file_id=shared_uploaded_file.pk,
source_id=self.source.pk,
+ tag_ids=self.request.GET.getlist('tags'),
user_id=user_id,
))
messages.success(
diff --git a/mayan/apps/sources/wizards.py b/mayan/apps/sources/wizards.py
index 7f510f60d2..97f00befda 100644
--- a/mayan/apps/sources/wizards.py
+++ b/mayan/apps/sources/wizards.py
@@ -12,26 +12,39 @@ from common.mixins import ViewPermissionCheckMixin
from documents.forms import DocumentTypeSelectForm
from documents.permissions import permission_document_create
from metadata.forms import MetadataFormSet
+from tags.forms import TagMultipleSelectionForm
+from .literals import STEP_DOCUMENT_TYPE, STEP_METADATA, STEP_TAGS
from .models import InteractiveSource
+def has_metadata_types(wizard):
+ """
+ Skip the 2nd step if document type has no associated metadata
+ """
+
+ cleaned_data = wizard.get_cleaned_data_for_step(STEP_DOCUMENT_TYPE) or {}
+
+ document_type = cleaned_data.get('document_type')
+
+ if document_type:
+ return document_type.metadata.exists()
+
+
class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
- form_list = (DocumentTypeSelectForm, MetadataFormSet)
- template_name = 'appearance/generic_wizard.html'
+ condition_dict = {STEP_METADATA: has_metadata_types}
extra_context = {}
+ form_list = (DocumentTypeSelectForm, MetadataFormSet, TagMultipleSelectionForm)
+ form_titles = {
+ DocumentTypeSelectForm: _('Step 1 of 3: Select document type'),
+ MetadataFormSet: _('Step 2 of 3: Enter document metadata'),
+ TagMultipleSelectionForm: _('Step 3 of 3: Select tags'),
+ }
+ template_name = 'appearance/generic_wizard.html'
view_permission = permission_document_create
- @staticmethod
- def _has_metadata_types(wizard):
- # Skip the 2nd step if document type has no associated metadata
- try:
- return wizard.get_cleaned_data_for_step('0')['document_type'].metadata.all().count()
- except TypeError:
- return False
-
def dispatch(self, request, *args, **kwargs):
- if InteractiveSource.objects.filter(enabled=True).count() == 0:
+ if not InteractiveSource.objects.filter(enabled=True).exists():
messages.error(
request,
_(
@@ -40,59 +53,67 @@ class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
)
)
return HttpResponseRedirect(reverse('sources:setup_source_list'))
+
return super(
DocumentCreateWizard, self
).dispatch(request, *args, **kwargs)
- def __init__(self, *args, **kwargs):
- super(DocumentCreateWizard, self).__init__(*args, **kwargs)
-
- self.condition_dict = {'1': DocumentCreateWizard._has_metadata_types}
-
- self.step_titles = [
- _('Step 1 of 2: Select document type'),
- _('Step 2 of 2: Enter document metadata'),
- ]
-
- def get_form_initial(self, step):
- if step == '1':
- initial = []
-
- for document_type_metadata_type in self.get_cleaned_data_for_step('0')['document_type'].metadata.all():
- initial.append({
- 'document_type': self.get_cleaned_data_for_step('0')['document_type'],
- 'metadata_type': document_type_metadata_type.metadata_type,
- })
-
- return initial
- return self.initial_dict.get(step, {})
-
def get_context_data(self, form, **kwargs):
context = super(
DocumentCreateWizard, self
).get_context_data(form=form, **kwargs)
+
context.update({
- 'step_title': self.step_titles[self.steps.step0],
+ 'step_title': self.form_titles[form.__class__],
'submit_label': _('Next step'),
'submit_icon': 'fa fa-arrow-right',
'title': _('Document upload wizard'),
})
return context
+ def get_form_initial(self, step):
+ if step == STEP_METADATA:
+ initial = []
+
+ for document_type_metadata_type in self.get_cleaned_data_for_step(STEP_DOCUMENT_TYPE)['document_type'].metadata.all():
+ initial.append(
+ {
+ 'document_type': self.get_cleaned_data_for_step(STEP_DOCUMENT_TYPE)['document_type'],
+ 'metadata_type': document_type_metadata_type.metadata_type,
+ }
+ )
+
+ return initial
+ return self.initial_dict.get(step, {})
+
+ def get_form_kwargs(self, step):
+ # Tags form needs the user instance to determine which tags to
+ # display
+ if step == STEP_TAGS:
+ return {'user': self.request.user}
+
+ return {}
+
def done(self, *args, **kwargs):
query_dict = {}
+
try:
- query_dict['document_type_id'] = self.get_cleaned_data_for_step('0')['document_type'].pk
+ query_dict['document_type_id'] = self.get_cleaned_data_for_step(STEP_DOCUMENT_TYPE)['document_type'].pk
except AttributeError:
pass
try:
- for identifier, metadata in enumerate(self.get_cleaned_data_for_step('1')):
+ for identifier, metadata in enumerate(self.get_cleaned_data_for_step(STEP_METADATA)):
query_dict['metadata%s_id' % identifier] = metadata['id']
query_dict['metadata%s_value' % identifier] = metadata['value']
except TypeError:
pass
+ try:
+ query_dict['tags'] = self.get_cleaned_data_for_step(STEP_TAGS)['tags']
+ except AttributeError:
+ pass
+
url = '?'.join(
[
reverse('sources:upload_interactive'),
diff --git a/mayan/apps/tags/forms.py b/mayan/apps/tags/forms.py
index e8b70b496f..711b29620b 100644
--- a/mayan/apps/tags/forms.py
+++ b/mayan/apps/tags/forms.py
@@ -32,3 +32,24 @@ class TagListForm(forms.Form):
self.fields['tag'] = forms.ModelChoiceField(
queryset=queryset,
label=_('Tags'))
+
+
+class TagMultipleSelectionForm(forms.Form):
+ def __init__(self, *args, **kwargs):
+ user = kwargs.pop('user', None)
+ logger.debug('user: %s', user)
+ super(TagMultipleSelectionForm, self).__init__(*args, **kwargs)
+
+ queryset = Tag.objects.all()
+ try:
+ Permission.check_permissions(user, (permission_tag_view,))
+ except PermissionDenied:
+ queryset = AccessControlList.objects.filter_by_access(
+ permission_tag_view, user, queryset
+ )
+
+ self.fields['tags'] = forms.MultipleChoiceField(
+ label=_('Tags'), choices=queryset.values_list('id', 'label'),
+ help_text=_('Tags to attach to the document.'),required=False,
+ widget=forms.CheckboxSelectMultiple
+ )