Add new WizardStep class to decouple the wizard step configuration.

Signed-off-by: Michael Price <loneviking72@gmail.com>
This commit is contained in:
Michael Price
2018-03-19 04:34:00 -04:00
committed by Roberto Rosario
parent a23f26f4f4
commit 460d747424
4 changed files with 175 additions and 82 deletions

View File

@@ -51,6 +51,7 @@ Next (2018-XX-XX)
- Move the page count display to the top of the image. - Move the page count display to the top of the image.
- Unify the way to gather the project's metadata. Use mayan.__XX__ and a new common tag named {% project_information '' %} - Unify the way to gather the project's metadata. Use mayan.__XX__ and a new common tag named {% project_information '' %}
- Return to the same source view after uploading a document. - Return to the same source view after uploading a document.
- Add new WizardStep class to decouple the wizard step configuration.
2.8 (2018-02-27) 2.8 (2018-02-27)
================ ================

View File

@@ -64,8 +64,3 @@ DEFAULT_METADATA_ATTACHMENT_NAME = 'metadata.yaml'
DEFAULT_POP3_TIMEOUT = 60 DEFAULT_POP3_TIMEOUT = 60
DEFAULT_IMAP_MAILBOX = 'INBOX' DEFAULT_IMAP_MAILBOX = 'INBOX'
DEFAULT_SOURCE_TASK_RETRY_DELAY = 10 DEFAULT_SOURCE_TASK_RETRY_DELAY = 10
# Upload wizard steps
STEP_DOCUMENT_TYPE = '0'
STEP_METADATA = '1'
STEP_TAGS = '2'

View File

@@ -242,18 +242,20 @@ class UploadInteractiveView(UploadBaseView):
except Exception as exception: except Exception as exception:
messages.error(self.request, exception) messages.error(self.request, exception)
task_source_handle_upload.apply_async(kwargs=dict( task_source_handle_upload.apply_async(
description=forms['document_form'].cleaned_data.get('description'), kwargs=dict(
document_type_id=self.document_type.pk, description=forms['document_form'].cleaned_data.get('description'),
expand=expand, document_type_id=self.document_type.pk,
label=label, expand=expand,
language=forms['document_form'].cleaned_data.get('language'), label=label,
metadata_dict_list=decode_metadata_from_url(self.request.GET), language=forms['document_form'].cleaned_data.get('language'),
shared_uploaded_file_id=shared_uploaded_file.pk, metadata_dict_list=decode_metadata_from_url(self.request.GET),
source_id=self.source.pk, shared_uploaded_file_id=shared_uploaded_file.pk,
tag_ids=self.request.GET.getlist('tags'), source_id=self.source.pk,
user_id=user_id, tag_ids=self.request.GET.getlist('tags'),
)) user_id=user_id,
)
)
messages.success( messages.success(
self.request, self.request,
_( _(

View File

@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.contrib import messages from django.contrib import messages
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.urls import reverse from django.urls import reverse
from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import urlencode from django.utils.http import urlencode
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -13,37 +14,163 @@ from common.mixins import ViewPermissionCheckMixin
from documents.forms import DocumentTypeSelectForm from documents.forms import DocumentTypeSelectForm
from metadata.forms import DocumentMetadataFormSet from metadata.forms import DocumentMetadataFormSet
from tags.forms import TagMultipleSelectionForm from tags.forms import TagMultipleSelectionForm
from tags.models import Tag
from .literals import STEP_DOCUMENT_TYPE, STEP_METADATA, STEP_TAGS
from .models import InteractiveSource from .models import InteractiveSource
def has_metadata_types(wizard): class WizardStep(object):
""" _registry = {}
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') @classmethod
def done(cls, wizard):
return {}
if document_type: @classmethod
return document_type.metadata.exists() def get(cls, name):
return cls._registry[name]
@classmethod
def get_all(cls):
return sorted(
cls._registry.values(), key=lambda x: x.number
)
@classmethod
def get_choices(cls, attribute_name):
return sorted(
[
(step.name, getattr(step, attribute_name)) for step in cls.get_all()
]
)
@classmethod
def get_form_initial(cls, wizard):
return {}
@classmethod
def get_form_kwargs(cls, wizard):
return {}
@classmethod
def register(cls, step):
cls._registry[step.name] = step
class WizardStepDocumentType(WizardStep):
form_class = DocumentTypeSelectForm
label = _('Select document type')
name = 'document_type_selection'
number = 0
@classmethod
def condition(cls, wizard):
return True
@classmethod
def done(cls, wizard):
cleaned_data = wizard.get_cleaned_data_for_step(cls.name)
if cleaned_data:
return {
'document_type_id': cleaned_data['document_type'].pk
}
@classmethod
def get_form_kwargs(cls, wizard):
return {'user': wizard.request.user}
class WizardStepMetadata(WizardStep):
form_class = DocumentMetadataFormSet
label = _('Enter document metadata')
name = 'metadata_entry'
number = 1
@classmethod
def condition(cls, wizard):
"""
Skip step if document type has no associated metadata
"""
cleaned_data = wizard.get_cleaned_data_for_step(WizardStepDocumentType.name) or {}
document_type = cleaned_data.get('document_type')
if document_type:
return document_type.metadata.exists()
@classmethod
def get_form_initial(cls, wizard):
initial = []
step_data = wizard.get_cleaned_data_for_step(WizardStepDocumentType.name)
if step_data:
document_type = step_data['document_type']
for document_type_metadata_type in document_type.metadata.all():
initial.append(
{
'document_type': document_type,
'metadata_type': document_type_metadata_type.metadata_type,
}
)
return initial
@classmethod
def done(cls, wizard):
result = {}
cleaned_data = wizard.get_cleaned_data_for_step(cls.name)
if cleaned_data:
for identifier, metadata in enumerate(wizard.get_cleaned_data_for_step(cls.name)):
if metadata.get('update'):
result['metadata%s_id' % identifier] = metadata['id']
result['metadata%s_value' % identifier] = metadata['value']
return result
class WizardStepTags(WizardStep):
form_class = TagMultipleSelectionForm
label = _('Select tags')
name = 'tag_selection'
number = 2
@classmethod
def condition(cls, wizard):
return Tag.objects.exists()
@classmethod
def get_form_kwargs(self, wizard):
return {
'help_text': _('Tags to be attached.'),
'user': wizard.request.user
}
@classmethod
def done(cls, wizard):
result = {}
cleaned_data = wizard.get_cleaned_data_for_step(cls.name)
if cleaned_data:
result['tags'] = [
force_text(tag.pk) for tag in cleaned_data['tags']
]
return result
WizardStep.register(WizardStepDocumentType)
WizardStep.register(WizardStepMetadata)
WizardStep.register(WizardStepTags)
class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView): class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
condition_dict = {STEP_METADATA: has_metadata_types}
extra_context = {}
form_list = (
DocumentTypeSelectForm, DocumentMetadataFormSet,
TagMultipleSelectionForm
)
form_titles = {
DocumentTypeSelectForm: _('Step 1 of 3: Select document type'),
DocumentMetadataFormSet: _('Step 2 of 3: Enter document metadata'),
TagMultipleSelectionForm: _('Step 3 of 3: Select tags'),
}
template_name = 'appearance/generic_wizard.html' template_name = 'appearance/generic_wizard.html'
@classonlymethod
def as_view(cls, *args, **kwargs):
cls.form_list = WizardStep.get_choices(attribute_name='form_class')
cls.condition_dict = dict(WizardStep.get_choices(attribute_name='condition'))
return super(DocumentCreateWizard, cls).as_view(*args, **kwargs)
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not InteractiveSource.objects.filter(enabled=True).exists(): if not InteractiveSource.objects.filter(enabled=True).exists():
messages.error( messages.error(
@@ -64,8 +191,15 @@ class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
DocumentCreateWizard, self DocumentCreateWizard, self
).get_context_data(form=form, **kwargs) ).get_context_data(form=form, **kwargs)
wizard_step = WizardStep.get(name=self.steps.current)
context.update({ context.update({
'step_title': self.form_titles[form.__class__], 'step_title': _(
'Step %(step)d of %(total_steps)d: %(step_label)s'
) % {
'step': self.steps.step1, 'total_steps': len(self.form_list),
'step_label': wizard_step.label,
},
'submit_label': _('Next step'), 'submit_label': _('Next step'),
'submit_icon': 'fa fa-arrow-right', 'submit_icon': 'fa fa-arrow-right',
'title': _('Document upload wizard'), 'title': _('Document upload wizard'),
@@ -73,55 +207,16 @@ class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
return context return context
def get_form_initial(self, step): def get_form_initial(self, step):
if step == STEP_METADATA: return WizardStep.get(name=step).get_form_initial(wizard=self) or {}
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): def get_form_kwargs(self, step):
# Tags form needs the user instance to determine which tags to return WizardStep.get(name=step).get_form_kwargs(wizard=self) or {}
# display
if step == STEP_DOCUMENT_TYPE:
return {'user': self.request.user}
if step == STEP_TAGS: def done(self, form_list, **kwargs):
return {
'help_text': _('Tags to be attached.'),
'user': self.request.user
}
return {}
def done(self, *args, **kwargs):
query_dict = {} query_dict = {}
try: for step in WizardStep.get_all():
query_dict['document_type_id'] = self.get_cleaned_data_for_step(STEP_DOCUMENT_TYPE)['document_type'].pk query_dict.update(step.done(wizard=self) or {})
except AttributeError:
pass
try:
for identifier, metadata in enumerate(self.get_cleaned_data_for_step(STEP_METADATA)):
if metadata.get('update'):
query_dict['metadata%s_id' % identifier] = metadata['id']
query_dict['metadata%s_value' % identifier] = metadata['value']
except TypeError:
pass
try:
query_dict['tags'] = ([force_text(tag.pk) for tag in self.get_cleaned_data_for_step(STEP_TAGS)['tags']])
except AttributeError:
pass
url = '?'.join( url = '?'.join(
[ [