Add source and adf-mode fields to the sane scanner source. Make all fields optional.
Improve error handling.
This commit is contained in:
8
mayan/apps/sources/exceptions.py
Normal file
8
mayan/apps/sources/exceptions.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
class SourceException(Exception):
|
||||||
|
"""
|
||||||
|
Base sources warning
|
||||||
|
"""
|
||||||
|
pass
|
||||||
@@ -85,7 +85,10 @@ class SaneScannerUploadForm(UploadBaseForm):
|
|||||||
|
|
||||||
class SaneScannerSetupForm(forms.ModelForm):
|
class SaneScannerSetupForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = ('label', 'device_name', 'mode', 'resolution', 'enabled')
|
fields = (
|
||||||
|
'label', 'device_name', 'mode', 'resolution', 'source',
|
||||||
|
'adf_mode', 'enabled'
|
||||||
|
)
|
||||||
model = SaneScanner
|
model = SaneScanner
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,22 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
SCANNER_SOURCE_FLATBED = 'flatbed'
|
||||||
|
SCANNER_SOURCE_ADF = 'Automatic Document Feeder'
|
||||||
|
|
||||||
|
SCANNER_SOURCE_CHOICES = (
|
||||||
|
(SCANNER_SOURCE_FLATBED, _('Flatbed')),
|
||||||
|
(SCANNER_SOURCE_ADF, _('Document feeder')),
|
||||||
|
)
|
||||||
|
|
||||||
|
SCANNER_ADF_MODE_SIMPLEX = 'simplex'
|
||||||
|
SCANNER_ADF_MODE_DUPLEX = 'duplex'
|
||||||
|
|
||||||
|
SCANNER_ADF_MODE_CHOICES = (
|
||||||
|
(SCANNER_ADF_MODE_SIMPLEX, _('Simplex')),
|
||||||
|
(SCANNER_ADF_MODE_DUPLEX, _('Duplex')),
|
||||||
|
)
|
||||||
|
|
||||||
SCANNER_MODE_LINEART = 'lineart'
|
SCANNER_MODE_LINEART = 'lineart'
|
||||||
SCANNER_MODE_MONOCHROME = 'monochrome'
|
SCANNER_MODE_MONOCHROME = 'monochrome'
|
||||||
SCANNER_MODE_COLOR = 'color'
|
SCANNER_MODE_COLOR = 'color'
|
||||||
|
|||||||
35
mayan/apps/sources/migrations/0013_auto_20170206_0710.py
Normal file
35
mayan/apps/sources/migrations/0013_auto_20170206_0710.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.5 on 2017-02-06 07:10
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sources', '0012_auto_20170205_0743'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='adf_mode',
|
||||||
|
field=models.CharField(blank=True, choices=[('simplex', 'Simples'), ('duplex', 'Duplex')], default='simplex', help_text='Selects the document feeder mode (simplex/duplex). If this option is not supported by your scanner, leave it blank.', max_length=16, verbose_name='ADF mode'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='source',
|
||||||
|
field=models.CharField(blank=True, choices=[('flatbed', 'Flatbed'), ('document-feeder', 'Document feeder')], default='flatbed', help_text='Selects the scan source (such as a document-feeder). If this option is not supported by your scanner, leave it blank.', max_length=16, verbose_name='Paper source'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='mode',
|
||||||
|
field=models.CharField(blank=True, choices=[('lineart', 'Lineart'), ('monochrome', 'Monochrome'), ('color', 'Color')], default='color', help_text='Selects the scan mode (e.g., lineart, monochrome, or color). If this option is not supported by your scanner, leave it blank.', max_length=16, verbose_name='Mode'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='resolution',
|
||||||
|
field=models.PositiveIntegerField(blank=True, help_text='Sets the resolution of the scanned image in DPI (dots per inch). Typical value is 200. If this option is not supported by your scanner, leave it blank.', verbose_name='Resolution'),
|
||||||
|
),
|
||||||
|
]
|
||||||
25
mayan/apps/sources/migrations/0014_auto_20170206_0722.py
Normal file
25
mayan/apps/sources/migrations/0014_auto_20170206_0722.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.5 on 2017-02-06 07:22
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sources', '0013_auto_20170206_0710'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='adf_mode',
|
||||||
|
field=models.CharField(blank=True, choices=[('simplex', 'Simplex'), ('duplex', 'Duplex')], default='simplex', help_text='Selects the document feeder mode (simplex/duplex). If this option is not supported by your scanner, leave it blank.', max_length=16, verbose_name='ADF mode'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='source',
|
||||||
|
field=models.CharField(blank=True, choices=[('flatbed', 'Flatbed'), ('"Automatic Document Feeder"', 'Document feeder')], default='flatbed', help_text='Selects the scan source (such as a document-feeder). If this option is not supported by your scanner, leave it blank.', max_length=32, verbose_name='Paper source'),
|
||||||
|
),
|
||||||
|
]
|
||||||
20
mayan/apps/sources/migrations/0015_auto_20170206_0835.py
Normal file
20
mayan/apps/sources/migrations/0015_auto_20170206_0835.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.5 on 2017-02-06 08:35
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sources', '0014_auto_20170206_0722'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sanescanner',
|
||||||
|
name='source',
|
||||||
|
field=models.CharField(blank=True, choices=[('flatbed', 'Flatbed'), ('Automatic Document Feeder', 'Document feeder')], default='flatbed', help_text='Selects the scan source (such as a document-feeder). If this option is not supported by your scanner, leave it blank.', max_length=32, verbose_name='Paper source'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -40,14 +40,17 @@ from metadata.models import MetadataType
|
|||||||
from tags.models import Tag
|
from tags.models import Tag
|
||||||
|
|
||||||
from .classes import Attachment, PseudoFile, SourceUploadedFile, StagingFile
|
from .classes import Attachment, PseudoFile, SourceUploadedFile, StagingFile
|
||||||
|
from .exceptions import SourceException
|
||||||
from .literals import (
|
from .literals import (
|
||||||
DEFAULT_INTERVAL, DEFAULT_POP3_TIMEOUT, DEFAULT_IMAP_MAILBOX,
|
DEFAULT_INTERVAL, DEFAULT_POP3_TIMEOUT, DEFAULT_IMAP_MAILBOX,
|
||||||
DEFAULT_METADATA_ATTACHMENT_NAME, SCANNER_MODE_COLOR, SCANNER_MODE_CHOICES,
|
DEFAULT_METADATA_ATTACHMENT_NAME, SCANNER_ADF_MODE_CHOICES,
|
||||||
|
SCANNER_ADF_MODE_SIMPLEX, SCANNER_MODE_COLOR, SCANNER_MODE_CHOICES,
|
||||||
|
SCANNER_SOURCE_CHOICES, SCANNER_SOURCE_FLATBED,
|
||||||
SOURCE_CHOICES, SOURCE_CHOICE_STAGING, SOURCE_CHOICE_WATCH,
|
SOURCE_CHOICES, SOURCE_CHOICE_STAGING, SOURCE_CHOICE_WATCH,
|
||||||
SOURCE_CHOICE_WEB_FORM, SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES,
|
SOURCE_CHOICE_WEB_FORM, SOURCE_INTERACTIVE_UNCOMPRESS_CHOICES,
|
||||||
SOURCE_UNCOMPRESS_CHOICES, SOURCE_UNCOMPRESS_CHOICE_N,
|
SOURCE_UNCOMPRESS_CHOICES, SOURCE_UNCOMPRESS_CHOICE_N,
|
||||||
SOURCE_UNCOMPRESS_CHOICE_Y, SOURCE_CHOICE_EMAIL_IMAP,
|
SOURCE_UNCOMPRESS_CHOICE_Y, SOURCE_CHOICE_EMAIL_IMAP,
|
||||||
SOURCE_CHOICE_EMAIL_POP3, SOURCE_CHOICE_SANE_SCANNER
|
SOURCE_CHOICE_EMAIL_POP3, SOURCE_CHOICE_SANE_SCANNER,
|
||||||
)
|
)
|
||||||
from .settings import setting_scanimage_path
|
from .settings import setting_scanimage_path
|
||||||
|
|
||||||
@@ -175,14 +178,34 @@ class SaneScanner(InteractiveSource):
|
|||||||
verbose_name=_('Device name')
|
verbose_name=_('Device name')
|
||||||
)
|
)
|
||||||
mode = models.CharField(
|
mode = models.CharField(
|
||||||
choices=SCANNER_MODE_CHOICES, default=SCANNER_MODE_COLOR,
|
blank=True, choices=SCANNER_MODE_CHOICES, default=SCANNER_MODE_COLOR,
|
||||||
max_length=16, verbose_name=_('Mode')
|
help_text=_(
|
||||||
|
'Selects the scan mode (e.g., lineart, monochrome, or color). '
|
||||||
|
'If this option is not supported by your scanner, leave it blank.'
|
||||||
|
), max_length=16, verbose_name=_('Mode')
|
||||||
)
|
)
|
||||||
resolution = models.PositiveIntegerField(
|
resolution = models.PositiveIntegerField(
|
||||||
default=300, help_text=_(
|
blank=True, help_text=_(
|
||||||
'Sets the resolution of the scanned image in DPI (dots per inch). '
|
'Sets the resolution of the scanned image in DPI (dots per inch). '
|
||||||
|
'Typical value is 200. If this option is not supported by your '
|
||||||
|
'scanner, leave it blank.'
|
||||||
), verbose_name=_('Resolution')
|
), verbose_name=_('Resolution')
|
||||||
)
|
)
|
||||||
|
source = models.CharField(
|
||||||
|
blank=True, choices=SCANNER_SOURCE_CHOICES,
|
||||||
|
default=SCANNER_SOURCE_FLATBED, help_text=_(
|
||||||
|
'Selects the scan source (such as a document-feeder). If this '
|
||||||
|
'option is not supported by your scanner, leave it blank.'
|
||||||
|
), max_length=32,
|
||||||
|
verbose_name=_('Paper source')
|
||||||
|
)
|
||||||
|
adf_mode = models.CharField(
|
||||||
|
blank=True, choices=SCANNER_ADF_MODE_CHOICES,
|
||||||
|
default=SCANNER_ADF_MODE_SIMPLEX, help_text=_(
|
||||||
|
'Selects the document feeder mode (simplex/duplex). If this '
|
||||||
|
'option is not supported by your scanner, leave it blank.'
|
||||||
|
), max_length=16, verbose_name=_('ADF mode')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('SANE Scanner')
|
verbose_name = _('SANE Scanner')
|
||||||
@@ -193,26 +216,50 @@ class SaneScanner(InteractiveSource):
|
|||||||
|
|
||||||
def get_upload_file_object(self, form_data):
|
def get_upload_file_object(self, form_data):
|
||||||
temporary_file_object = TemporaryFile()
|
temporary_file_object = TemporaryFile()
|
||||||
|
|
||||||
try:
|
|
||||||
command_line = [
|
command_line = [
|
||||||
setting_scanimage_path.value, '-d', self.device_name,
|
setting_scanimage_path.value, '-d', self.device_name,
|
||||||
'--resolution', '{}'.format(self.resolution), '--mode',
|
'--format', 'tiff',
|
||||||
self.mode, '--format', 'tiff'
|
|
||||||
]
|
]
|
||||||
logger.debug('Scan command line: %s', command_line)
|
|
||||||
result = subprocess.check_call(
|
if self.resolution:
|
||||||
command_line, stdout=temporary_file_object
|
command_line.extend(
|
||||||
)
|
['--resolution', '{}'.format(self.resolution)]
|
||||||
except subprocess.CalledProcessError as exception:
|
|
||||||
logger.error(
|
|
||||||
'Exception while scanning from source:%s ; %s', self,
|
|
||||||
exception
|
|
||||||
)
|
|
||||||
self.logs.create(
|
|
||||||
message=_('Error while scanning; %s') % exception
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.mode:
|
||||||
|
command_line.extend(
|
||||||
|
['--mode', self.mode]
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.source:
|
||||||
|
command_line.extend(
|
||||||
|
['--source', self.source]
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.adf_mode:
|
||||||
|
command_line.extend(
|
||||||
|
['--adf-mode', self.adf_mode]
|
||||||
|
)
|
||||||
|
|
||||||
|
filestderr = TemporaryFile()
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.debug('Scan command line: %s', command_line)
|
||||||
|
subprocess.check_call(
|
||||||
|
command_line, stdout=temporary_file_object, stderr=filestderr
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
filestderr.seek(0)
|
||||||
|
error_message = filestderr.read()
|
||||||
|
logger.error(
|
||||||
|
'Exception while scanning from source:%s ; %s', self,
|
||||||
|
error_message
|
||||||
|
)
|
||||||
|
|
||||||
|
message = _('Error while scanning; %s') % error_message
|
||||||
|
self.logs.create(message=message)
|
||||||
|
raise SourceException(message)
|
||||||
|
else:
|
||||||
return SourceUploadedFile(
|
return SourceUploadedFile(
|
||||||
source=self, file=PseudoFile(
|
source=self, file=PseudoFile(
|
||||||
file=temporary_file_object, name='scan {}'.format(now())
|
file=temporary_file_object, name='scan {}'.format(now())
|
||||||
|
|||||||
@@ -24,18 +24,13 @@ from documents.tasks import task_upload_new_version
|
|||||||
from metadata.api import decode_metadata_from_url
|
from metadata.api import decode_metadata_from_url
|
||||||
from navigation import Link
|
from navigation import Link
|
||||||
|
|
||||||
|
from .exceptions import SourceException
|
||||||
from .forms import (
|
from .forms import (
|
||||||
NewDocumentForm, NewVersionForm, SaneScannerUploadForm, WebFormUploadForm,
|
NewDocumentForm, NewVersionForm, WebFormUploadForm, WebFormUploadFormHTML5
|
||||||
WebFormUploadFormHTML5
|
|
||||||
)
|
|
||||||
from .literals import (
|
|
||||||
SOURCE_CHOICE_STAGING, SOURCE_CHOICE_SANE_SCANNER, SOURCE_CHOICE_WEB_FORM,
|
|
||||||
SOURCE_UNCOMPRESS_CHOICE_ASK,
|
|
||||||
SOURCE_UNCOMPRESS_CHOICE_Y
|
|
||||||
)
|
)
|
||||||
|
from .literals import SOURCE_UNCOMPRESS_CHOICE_ASK, SOURCE_UNCOMPRESS_CHOICE_Y
|
||||||
from .models import (
|
from .models import (
|
||||||
InteractiveSource, Source, SaneScanner, StagingFolderSource,
|
InteractiveSource, Source, SaneScanner, StagingFolderSource
|
||||||
WebFormSource
|
|
||||||
)
|
)
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_sources_setup_create, permission_sources_setup_delete,
|
permission_sources_setup_create, permission_sources_setup_delete,
|
||||||
@@ -211,10 +206,13 @@ class UploadInteractiveView(UploadBaseView):
|
|||||||
else:
|
else:
|
||||||
expand = False
|
expand = False
|
||||||
|
|
||||||
|
try:
|
||||||
uploaded_file = self.source.get_upload_file_object(
|
uploaded_file = self.source.get_upload_file_object(
|
||||||
forms['source_form'].cleaned_data
|
forms['source_form'].cleaned_data
|
||||||
)
|
)
|
||||||
|
except SourceException as exception:
|
||||||
|
messages.error(self.request, exception)
|
||||||
|
else:
|
||||||
shared_uploaded_file = SharedUploadedFile.objects.create(
|
shared_uploaded_file = SharedUploadedFile.objects.create(
|
||||||
file=uploaded_file.file
|
file=uploaded_file.file
|
||||||
)
|
)
|
||||||
@@ -254,6 +252,7 @@ class UploadInteractiveView(UploadBaseView):
|
|||||||
'shortly.'
|
'shortly.'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return HttpResponseRedirect(self.request.get_full_path())
|
return HttpResponseRedirect(self.request.get_full_path())
|
||||||
|
|
||||||
def create_source_form_form(self, **kwargs):
|
def create_source_form_form(self, **kwargs):
|
||||||
@@ -339,10 +338,13 @@ class UploadInteractiveVersionView(UploadBaseView):
|
|||||||
).dispatch(request, *args, **kwargs)
|
).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def forms_valid(self, forms):
|
def forms_valid(self, forms):
|
||||||
|
try:
|
||||||
uploaded_file = self.source.get_upload_file_object(
|
uploaded_file = self.source.get_upload_file_object(
|
||||||
forms['source_form'].cleaned_data
|
forms['source_form'].cleaned_data
|
||||||
)
|
)
|
||||||
|
except SourceException as exception:
|
||||||
|
messages.error(self.request, exception)
|
||||||
|
else:
|
||||||
shared_uploaded_file = SharedUploadedFile.objects.create(
|
shared_uploaded_file = SharedUploadedFile.objects.create(
|
||||||
file=uploaded_file.file
|
file=uploaded_file.file
|
||||||
)
|
)
|
||||||
@@ -371,6 +373,7 @@ class UploadInteractiveVersionView(UploadBaseView):
|
|||||||
'available shortly.'
|
'available shortly.'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
reverse(
|
reverse(
|
||||||
'documents:document_version_list', args=(self.document.pk,)
|
'documents:document_version_list', args=(self.document.pk,)
|
||||||
|
|||||||
Reference in New Issue
Block a user