Merge branch 'feature/local_scanner_support' into development

This commit is contained in:
Roberto Rosario
2012-08-09 04:56:10 -04:00
16 changed files with 458 additions and 30 deletions

View File

@@ -190,14 +190,18 @@ class Document(models.Model):
serial=serial,
comment=comment,
)
logger.debug('pre new_version.save() in version_update')
new_version.save()
logger.debug('post new_version.save() in version_update')
else:
new_version_dict = {}
new_version = DocumentVersion(
document=self,
file=file,
)
logger.debug('pre new_version.save() not in version_update')
new_version.save()
logger.debug('post new_version.save() not in version_update')
logger.debug('new_version saved')
return new_version
@@ -399,7 +403,9 @@ class DocumentVersion(models.Model):
#Only do this for new documents
transformations = kwargs.pop('transformations', None)
logger.debug('pre save in DocumentVersion.save()')
super(DocumentVersion, self).save(*args, **kwargs)
logger.debug('post save in DocumentVersion.save()')
for key in sorted(DocumentVersion._post_save_hooks):
DocumentVersion._post_save_hooks[key](self)

View File

@@ -1 +0,0 @@

View File

@@ -2,8 +2,8 @@ from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
from navigation.api import (bind_links,
register_model_list_columns)
from navigation.api import (bind_links, register_model_list_columns,
register_sidebar_template)
from common.utils import encapsulate
from project_setup.api import register_setup
from scheduler.api import LocalScheduler
@@ -11,7 +11,7 @@ from documents.models import Document
from .staging import StagingFile
from .models import (WebForm, StagingFolder, SourceTransformation,
WatchFolder, POP3Email, IMAPEmail)
WatchFolder, POP3Email, IMAPEmail, LocalScanner)
from .widgets import staging_file_thumbnail
from .tasks import task_fetch_pop3_emails, task_fetch_imap_emails
from .conf.settings import EMAIL_PROCESSING_INTERVAL
@@ -21,32 +21,38 @@ from .links import (staging_file_delete, setup_sources,
setup_source_delete, setup_source_create, setup_source_log_list,
setup_source_transformation_list, setup_source_transformation_create,
setup_source_transformation_edit, setup_source_transformation_delete,
upload_version, document_create_multiple)
upload_version, document_create_multiple, setup_local_scanner_list,
setup_local_scanners_refresh)
bind_links([StagingFile], [staging_file_delete])
bind_links([SourceTransformation], [setup_source_transformation_edit, setup_source_transformation_delete])
bind_links(['setup_imap_email_list', 'setup_pop3_email_list', 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create'], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header')
bind_links([WebForm, StagingFolder, POP3Email, IMAPEmail, 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create', 'setup_pop3_email_list', 'setup_imap_email_list'], [setup_source_create], menu_name='secondary_menu')
bind_links([LocalScanner, 'setup_local_scanner_list'], [setup_local_scanners_refresh], menu_name='secondary_menu')
register_sidebar_template([LocalScanner, 'setup_local_scanner_list'], 'scanner_list.html')
bind_links(['setup_imap_email_list', 'setup_pop3_email_list', 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create', 'setup_local_scanner_list'], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([WebForm, StagingFolder, POP3Email, IMAPEmail, LocalScanner, 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create', 'setup_pop3_email_list', 'setup_imap_email_list', 'setup_local_scanner_list'], [setup_source_create], menu_name='secondary_menu')
bind_links([WebForm], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header')
bind_links([WebForm], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([WebForm], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
bind_links([StagingFolder], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header')
bind_links([StagingFolder], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([StagingFolder], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
bind_links([POP3Email], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header')
bind_links([POP3Email], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([POP3Email], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
bind_links([POP3Email], [setup_source_log_list])
bind_links([IMAPEmail], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header')
bind_links([IMAPEmail], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([IMAPEmail], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
bind_links([IMAPEmail], [setup_source_log_list])
bind_links([WatchFolder], [setup_web_form_list, setup_staging_folder_list, setup_watch_folder_list, setup_imap_email_list], menu_name='form_header')
bind_links([WatchFolder], [setup_web_form_list, setup_staging_folder_list, setup_watch_folder_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([WatchFolder], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
bind_links([LocalScanner], [setup_web_form_list, setup_staging_folder_list, setup_watch_folder_list, setup_imap_email_list, setup_local_scanner_list], menu_name='form_header')
bind_links([LocalScanner], [setup_source_transformation_list, setup_source_edit, setup_source_delete])
# Document version
bind_links(['document_version_list', 'upload_version', 'document_version_revert', 'document_version_text_compare', 'document_version_show_diff_text'], [upload_version], menu_name='sidebar')

View File

@@ -7,7 +7,7 @@ from django.utils.translation import ugettext
from documents.forms import DocumentForm
from .models import (WebForm, StagingFolder, SourceTransformation,
WatchFolder, POP3Email, IMAPEmail)
WatchFolder, POP3Email, IMAPEmail, LocalScanner)
from .widgets import FamFamRadioSelect
from .utils import validate_whitelist_blacklist
@@ -100,6 +100,52 @@ class WatchFolderSetupForm(forms.ModelForm):
model = WatchFolder
class LocalScannerSetupForm(forms.ModelForm):
class Meta:
model = LocalScanner
scanner = forms.ChoiceField(required=False, label=_(u'Active scanners'), help_text=_(u'List of scanners found connected to this node. Choose one to have its device and description automatically saved in the fields above.'))
scanner_device = forms.CharField(required=False, label=_(u'Scanner device'))
scanner_description = forms.CharField(required=False, label=_(u'Scanner description'))
def __init__(self, *args, **kwargs):
super(LocalScannerSetupForm, self).__init__(*args, **kwargs)
self.fields['icon'].widget = FamFamRadioSelect(
attrs=self.fields['icon'].widget.attrs,
choices=self.fields['icon'].widget.choices,
)
self.scanner_choices = LocalScanner.get_scanner_choices()
self.fields['scanner'].choices = self.scanner_choices
def clean(self):
try:
scanner = LocalScanner.get_scanner(self.cleaned_data.get('scanner'))
except LocalScanner.NoSuchScanner:
device_name = u''
description = u''
else:
device_name = scanner['scanner']._device
description = scanner['description']
self.cleaned_data['scanner_device'] = device_name
self.cleaned_data['scanner_description'] = description
return self.cleaned_data
class LocalScannerForm(DocumentForm):
def __init__(self, *args, **kwargs):
show_expand = kwargs.pop('show_expand', False)
self.source = kwargs.pop('source')
super(LocalScannerForm, self).__init__(*args, **kwargs)
self.fields['new_filename'].help_text=_(u'If left blank a date time stamp will be used.')
def clean_file(self):
data = self.cleaned_data['file']
validate_whitelist_blacklist(data.name, self.source.whitelist.split(','), self.source.blacklist.split(','))
return data
class SourceTransformationForm(forms.ModelForm):
class Meta:
model = SourceTransformation

View File

@@ -8,18 +8,18 @@ from documents.permissions import (PERMISSION_DOCUMENT_NEW_VERSION,
from .permissions import (PERMISSION_SOURCES_SETUP_VIEW,
PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE,
PERMISSION_SOURCES_SETUP_CREATE)
from .models import (WebForm, StagingFolder, SourceTransformation,
WatchFolder, POP3Email, IMAPEmail)
staging_file_preview = Link(text=_(u'preview'), klass='fancybox-noscaling', view='staging_file_preview', args=['source.source_type', 'source.pk', 'object.pk'], sprite='zoom', permissions=[PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_CREATE])
staging_file_delete = Link(text=_(u'delete'), view='staging_file_delete', args=['source.source_type', 'source.pk', 'object.pk'], sprite='delete', keep_query=True, permissions=[PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_CREATE])
setup_sources = Link(text=_(u'sources'), view='setup_web_form_list', sprite='application_form', icon='application_form.png', children_classes=[WebForm], permissions=[PERMISSION_SOURCES_SETUP_VIEW], children_view_regex=[r'setup_web_form', r'setup_staging_folder', r'setup_source_', r'setup_pop3', r'setup_imap'])
setup_web_form_list = Link(text=_(u'web forms'), view='setup_web_form_list', sprite='application_form', icon='application_form.png', children_classes=[WebForm], permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_staging_folder_list = Link(text=_(u'staging folders'), view='setup_staging_folder_list', sprite='folder_camera', children_classes=[StagingFolder], permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_watch_folder_list = Link(text=_(u'watch folders'), view='setup_watch_folder_list', sprite='folder_magnify', children_classes=[WatchFolder], permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_pop3_email_list = Link(text=_(u'POP3 email'), view='setup_pop3_email_list', sprite='email', children_classes=[POP3Email], permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_imap_email_list = Link(text=_(u'IMAP email'), view='setup_imap_email_list', sprite='email', children_classes=[IMAPEmail], permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_sources = Link(text=_(u'sources'), view='setup_web_form_list', sprite='application_form', icon='application_form.png', permissions=[PERMISSION_SOURCES_SETUP_VIEW], children_view_regex=[r'setup_web_form', r'setup_staging_folder', r'setup_source_', r'setup_pop3', r'setup_imap'])
setup_web_form_list = Link(text=_(u'web forms'), view='setup_web_form_list', sprite='application_form', icon='application_form.png', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_staging_folder_list = Link(text=_(u'staging folders'), view='setup_staging_folder_list', sprite='folder_camera', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_watch_folder_list = Link(text=_(u'watch folders'), view='setup_watch_folder_list', sprite='folder_magnify', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_pop3_email_list = Link(text=_(u'POP3 email'), view='setup_pop3_email_list', sprite='email', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_imap_email_list = Link(text=_(u'IMAP email'), view='setup_imap_email_list', sprite='email', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_local_scanner_list = Link(text=_(u'Local scanner'), view='setup_local_scanner_list', sprite='image', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_local_scanners_refresh = Link(text=_(u'Refresh scanner list'), view='scanners_refresh', sprite='images', permissions=[PERMISSION_SOURCES_SETUP_VIEW])
setup_source_edit = Link(text=_(u'edit'), view='setup_source_edit', args=['source.source_type', 'source.pk'], sprite='application_form_edit', permissions=[PERMISSION_SOURCES_SETUP_EDIT])
setup_source_delete = Link(text=_(u'delete'), view='setup_source_delete', args=['source.source_type', 'source.pk'], sprite='application_form_delete', permissions=[PERMISSION_SOURCES_SETUP_DELETE])

View File

@@ -35,6 +35,7 @@ SOURCE_ICON_FOLDER = 'folder'
SOURCE_ICON_WORLD = 'world'
SOURCE_ICON_PRINTER = 'printer'
SOURCE_ICON_PRINTER_EMPTY = 'printer_empty'
SOURCE_ICON_IMAGES = 'images'
SOURCE_ICON_CHOICES = (
(SOURCE_ICON_DISK, _(u'Disk')),
@@ -44,6 +45,7 @@ SOURCE_ICON_CHOICES = (
(SOURCE_ICON_DRIVE_USER, _(u'User drive')),
(SOURCE_ICON_EMAIL, _(u'Envelope')),
(SOURCE_ICON_FOLDER, _(u'Folder')),
(SOURCE_ICON_IMAGES, _(u'Images')),
(SOURCE_ICON_WORLD, _(u'World')),
(SOURCE_ICON_PRINTER, _(u'Printer')),
(SOURCE_ICON_PRINTER_EMPTY, _(u'Empty printer')),
@@ -54,6 +56,7 @@ SOURCE_CHOICE_STAGING = 'staging'
SOURCE_CHOICE_WATCH = 'watch'
SOURCE_CHOICE_POP3_EMAIL = 'pop3'
SOURCE_CHOICE_IMAP_EMAIL = 'imap'
SOURCE_CHOICE_LOCAL_SCANNER = 'local_scanner'
SOURCE_CHOICES = (
(SOURCE_CHOICE_WEB_FORM, _(u'web form')),
@@ -61,6 +64,7 @@ SOURCE_CHOICES = (
(SOURCE_CHOICE_WATCH, _(u'server watch folder')),
(SOURCE_CHOICE_POP3_EMAIL, _(u'POP3 email')),
(SOURCE_CHOICE_IMAP_EMAIL, _(u'IMAP email')),
(SOURCE_CHOICE_LOCAL_SCANNER, _(u'local scanner')),
)
SOURCE_CHOICES_PLURAL = (
@@ -69,4 +73,7 @@ SOURCE_CHOICES_PLURAL = (
(SOURCE_CHOICE_WATCH, _(u'server watch folders')),
(SOURCE_CHOICE_POP3_EMAIL, _(u'POP3 emails')),
(SOURCE_CHOICE_IMAP_EMAIL, _(u'IMAP emails')),
(SOURCE_CHOICE_LOCAL_SCANNER, _(u'local scanners')),
)
DEFAULT_LOCAL_SCANNER_FILE_FORMAT = 'JPEG'

View File

@@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'LocalScanner'
db.create_table('sources_localscanner', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=64)),
('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
('whitelist', self.gf('django.db.models.fields.TextField')(blank=True)),
('blacklist', self.gf('django.db.models.fields.TextField')(blank=True)),
('icon', self.gf('django.db.models.fields.CharField')(max_length=24, null=True, blank=True)),
('scanner_device', self.gf('django.db.models.fields.CharField')(max_length=255)),
('scanner_description', self.gf('django.db.models.fields.CharField')(max_length=255)),
))
db.send_create_signal('sources', ['LocalScanner'])
def backwards(self, orm):
# Deleting model 'LocalScanner'
db.delete_table('sources_localscanner')
models = {
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'documents.documenttype': {
'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '32'})
},
'sources.imapemail': {
'Meta': {'ordering': "('title',)", 'object_name': 'IMAPEmail'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'host': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.PositiveIntegerField', [], {'default': '900'}),
'mailbox': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'port': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'ssl': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'sources.localscanner': {
'Meta': {'ordering': "('title',)", 'object_name': 'LocalScanner'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'scanner_description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'scanner_device': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'sources.outofprocess': {
'Meta': {'ordering': "('title',)", 'object_name': 'OutOfProcess'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'sources.pop3email': {
'Meta': {'ordering': "('title',)", 'object_name': 'POP3Email'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'host': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.PositiveIntegerField', [], {'default': '900'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'port': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'ssl': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'sources.sourcelog': {
'Meta': {'ordering': "('creation_datetime',)", 'object_name': 'SourceLog'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'creation_datetime': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'status': ('django.db.models.fields.TextField', [], {})
},
'sources.sourcetransformation': {
'Meta': {'ordering': "('order',)", 'object_name': 'SourceTransformation'},
'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'})
},
'sources.stagingfolder': {
'Meta': {'ordering': "('title',)", 'object_name': 'StagingFolder'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'delete_after_upload': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'folder_path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'preview_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'preview_width': ('django.db.models.fields.IntegerField', [], {}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'sources.watchfolder': {
'Meta': {'ordering': "('title',)", 'object_name': 'WatchFolder'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'delete_after_upload': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'folder_path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interval': ('django.db.models.fields.PositiveIntegerField', [], {}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'sources.webform': {
'Meta': {'ordering': "('title',)", 'object_name': 'WebForm'},
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'icon': ('django.db.models.fields.CharField', [], {'max_length': '24', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'uncompress': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
}
}
complete_apps = ['sources']

View File

@@ -14,6 +14,8 @@ try:
except ImportError:
from StringIO import StringIO
import imagescanner
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
@@ -39,7 +41,9 @@ from .literals import (SOURCE_CHOICES, SOURCE_CHOICES_PLURAL,
SOURCE_CHOICE_POP3_EMAIL, DEFAULT_POP3_INTERVAL,
IMAP_PORT, IMAP_SSL_PORT,
SOURCE_CHOICE_IMAP_EMAIL, DEFAULT_IMAP_INTERVAL,
IMAP_DEFAULT_MAILBOX)
IMAP_DEFAULT_MAILBOX,
SOURCE_CHOICE_LOCAL_SCANNER, SOURCE_ICON_IMAGES,
DEFAULT_LOCAL_SCANNER_FILE_FORMAT)
from .compressed_file import CompressedFile, NotACompressedFile
from .conf.settings import POP3_TIMEOUT
#from . import sources_scheduler
@@ -378,6 +382,83 @@ class IMAPEmail(EmailBaseModel):
verbose_name_plural = _(u'IMAP email')
class LocalScanner(InteractiveBaseModel):
# scanner device string to scanner instance cache dict
_scanner_cache = {}
class NoSuchScanner(Exception):
pass
is_interactive = True
source_type = SOURCE_CHOICE_LOCAL_SCANNER
default_icon = SOURCE_ICON_IMAGES
scanner_device = models.CharField(max_length=255, verbose_name=_(u'scanner device'))
scanner_description = models.CharField(max_length=255, verbose_name=_(u'scanner description'))
@classmethod
def get_scanners(cls):
iscanner = imagescanner.ImageScanner(remote_search=False)
scanners = iscanner.list_scanners()
imagescanner.settings.LOGGING_LEVEL = logging.FATAL
imagescanner.settings.ENABLE_NET_BACKEND = False
imagescanner.settings.ENABLE_TEST_BACKEND = False
for scanner in scanners:
LocalScanner._scanner_cache[unicode(scanner._device)] = {
'scanner': scanner,
'description': u'%s: %s - %s - %s <%s>' % (scanner.id, scanner.manufacturer, scanner.name, scanner.description, scanner._device)
}
return scanners
@classmethod
def get_scanner(cls, device):
try:
return cls._scanner_cache[device]
except KeyError:
raise cls.NoSuchScanner
@classmethod
def get_scanner_choices(cls, description_only=False):
if description_only:
template_func = lambda scanner: (scanner['description'])
else:
template_func = lambda scanner: (scanner['scanner']._device, scanner['description'])
return [template_func(scanner) for scanner in LocalScanner._scanner_cache.values()]
def scanner(self, _fail=False):
try:
return LocalScanner._scanner_cache[self.scanner_device]['scanner']
except KeyError:
if _fail == False:
# Refresh the cache before trying one last time
LocalScanner.get_scanners()
return self.scanner(_fail=True)
else:
raise self.__class__.NoSuchScanner
def scan(self, as_image=False):
image = self.scanner().scan()
if as_image:
return image
else:
buf = StringIO()
image.save(buf, DEFAULT_LOCAL_SCANNER_FILE_FORMAT)
return PseudoFile(buf, name=unicode(datetime.datetime.now()).replace(u'.', u'_').replace(u' ', u'_'))
# This code make new_version upload fail, use it for debugging
#buf = StringIO()
#buf.write(image.tostring())
#buf.seek(0)
#return buf
class Meta(InteractiveBaseModel.Meta):
verbose_name = _(u'local scanner')
verbose_name_plural = _(u'local scanners')
class StagingFolder(InteractiveBaseModel):
is_interactive = True
source_type = SOURCE_CHOICE_STAGING

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,10 @@
{% load i18n %}
{% load scanner_tags %}
{% trans 'Scanner list' as title %}
{% scanner_list as paragraphs %}
{% with 'true' as side_bar %}
{% include 'generic_subtemplate.html' %}
{% endwith %}

View File

View File

@@ -0,0 +1,16 @@
from django.template import Library
from django.utils.translation import ugettext_lazy as _
from sources.models import LocalScanner
register = Library()
@register.assignment_tag
def scanner_list():
list_of_scanners = LocalScanner.get_scanner_choices(description_only=True)
if list_of_scanners:
return list_of_scanners
else:
return [_(u'No scanners found.')]

View File

@@ -3,7 +3,8 @@ from __future__ import absolute_import
from django.conf.urls.defaults import patterns, url
from .literals import (SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING,
SOURCE_CHOICE_WATCH, SOURCE_CHOICE_POP3_EMAIL, SOURCE_CHOICE_IMAP_EMAIL)
SOURCE_CHOICE_WATCH, SOURCE_CHOICE_POP3_EMAIL, SOURCE_CHOICE_IMAP_EMAIL,
SOURCE_CHOICE_LOCAL_SCANNER)
urlpatterns = patterns('sources.views',
url(r'^create/from/local/multiple/$', 'document_create', (), 'document_create_multiple'),
@@ -25,6 +26,8 @@ urlpatterns = patterns('sources.views',
url(r'^setup/interactive/%s/list/$' % SOURCE_CHOICE_WATCH, 'setup_source_list', {'source_type': SOURCE_CHOICE_WATCH}, 'setup_watch_folder_list'),
url(r'^setup/interactive/%s/list/$' % SOURCE_CHOICE_POP3_EMAIL, 'setup_source_list', {'source_type': SOURCE_CHOICE_POP3_EMAIL}, 'setup_pop3_email_list'),
url(r'^setup/interactive/%s/list/$' % SOURCE_CHOICE_IMAP_EMAIL, 'setup_source_list', {'source_type': SOURCE_CHOICE_IMAP_EMAIL}, 'setup_imap_email_list'),
url(r'^setup/interactive/%s/list/$' % SOURCE_CHOICE_LOCAL_SCANNER, 'setup_source_list', {'source_type': SOURCE_CHOICE_LOCAL_SCANNER}, 'setup_local_scanner_list'),
url(r'^setup/interactive/%s/refresh/$' % SOURCE_CHOICE_LOCAL_SCANNER, 'scanners_refresh', (), 'scanners_refresh'),
url(r'^setup/interactive/(?P<source_type>\w+)/list/$', 'setup_source_list', (), 'setup_source_list'),
url(r'^setup/interactive/(?P<source_type>\w+)/(?P<source_id>\d+)/edit/$', 'setup_source_edit', (), 'setup_source_edit'),

View File

@@ -29,16 +29,17 @@ from acls.models import AccessEntry
from navigation.api import Link
from .models import (WebForm, StagingFolder, SourceTransformation,
WatchFolder, POP3Email, SourceLog, IMAPEmail)
WatchFolder, POP3Email, SourceLog, IMAPEmail, LocalScanner)
from .literals import (SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING,
SOURCE_CHOICE_WATCH, SOURCE_CHOICE_POP3_EMAIL, SOURCE_CHOICE_IMAP_EMAIL)
SOURCE_CHOICE_WATCH, SOURCE_CHOICE_POP3_EMAIL, SOURCE_CHOICE_IMAP_EMAIL,
SOURCE_CHOICE_LOCAL_SCANNER)
from .literals import (SOURCE_UNCOMPRESS_CHOICE_Y,
SOURCE_UNCOMPRESS_CHOICE_ASK)
from .staging import create_staging_file_class
from .forms import (StagingDocumentForm, WebFormForm,
WatchFolderSetupForm)
from .forms import (WebFormSetupForm, StagingFolderSetupForm,
POP3EmailSetupForm, IMAPEmailSetupForm)
WatchFolderSetupForm, WebFormSetupForm, StagingFolderSetupForm,
POP3EmailSetupForm, IMAPEmailSetupForm, LocalScannerSetupForm,
LocalScannerForm)
from .forms import SourceTransformationForm, SourceTransformationForm_create
from .permissions import (PERMISSION_SOURCES_SETUP_VIEW,
PERMISSION_SOURCES_SETUP_EDIT, PERMISSION_SOURCES_SETUP_DELETE,
@@ -74,10 +75,15 @@ def get_active_tab_links(document=None):
for staging_folder in staging_folders:
tab_links.append(get_tab_link_for_source(staging_folder, document))
local_scanners = LocalScanner.objects.filter(enabled=True)
for local_scanner in local_scanners:
tab_links.append(get_tab_link_for_source(local_scanner, document))
return {
'tab_links': tab_links,
SOURCE_CHOICE_WEB_FORM: web_forms,
SOURCE_CHOICE_STAGING: staging_folders,
SOURCE_CHOICE_LOCAL_SCANNER: local_scanners,
}
@@ -99,7 +105,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
context = {}
if results[SOURCE_CHOICE_WEB_FORM].count() == 0 and results[SOURCE_CHOICE_STAGING].count() == 0:
if results[SOURCE_CHOICE_WEB_FORM].count() == 0 and results[SOURCE_CHOICE_STAGING].count() == 0 and results[SOURCE_CHOICE_LOCAL_SCANNER].count() == 0:
source_setup_link = mark_safe('<a href="%s">%s</a>' % (reverse('setup_web_form_list'), ugettext(u'here')))
subtemplates_list.append(
{
@@ -128,6 +134,9 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
elif results[SOURCE_CHOICE_STAGING].count():
source_type = results[SOURCE_CHOICE_STAGING][0].source_type
source_id = results[SOURCE_CHOICE_STAGING][0].pk
elif results[SOURCE_CHOICE_LOCAL_SCANNER].count():
source_type = results[SOURCE_CHOICE_LOCAL_SCANNER][0].source_type
source_id = results[SOURCE_CHOICE_LOCAL_SCANNER][0].pk
if source_type and source_id:
if source_type == SOURCE_CHOICE_WEB_FORM:
@@ -300,6 +309,65 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No
}
},
]
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
local_scanner = get_object_or_404(LocalScanner, pk=source_id)
context['source'] = local_scanner
if request.method == 'POST':
form = LocalScannerForm(request.POST, request.FILES,
document_type=document_type,
source=local_scanner,
instance=document
)
if form.is_valid():
try:
expand = False
new_filename = get_form_filename(form)
image = local_scanner.scan()
result = local_scanner.upload_file(image,
new_filename, use_file_name=form.cleaned_data.get('use_file_name', False),
document_type=document_type,
expand=expand,
metadata_dict_list=decode_metadata_from_url(request.GET),
user=request.user,
document=document,
new_version_data=form.cleaned_data.get('new_version_data')
)
if document:
messages.success(request, _(u'New document version uploaded successfully.'))
return HttpResponseRedirect(reverse('document_view_simple', args=[document.pk]))
else:
messages.success(request, _(u'File uploaded successfully.'))
return HttpResponseRedirect(request.get_full_path())
except NewDocumentVersionNotAllowed:
messages.error(request, _(u'New version uploads are not allowed for this document.'))
except Exception, e:
if settings.DEBUG:
raise
messages.error(request, _(u'Unhandled exception: %s') % e)
else:
form = LocalScannerForm(
document_type=document_type,
source=local_scanner,
instance=document
)
if document:
title = _(u'upload a new version scanned from source: %s') % local_scanner.title
else:
title = _(u'upload a document scanned from source: %s') % local_scanner.title
subtemplates_list.append({
'name': 'generic_form_subtemplate.html',
'context': {
'form': form,
'title': title,
'submit_label': _(u'Scan'),
'submit_icon_famfam': 'image',
},
})
if document:
context['object'] = document
@@ -446,6 +514,8 @@ def setup_source_list(request, source_type):
cls = POP3Email
elif source_type == SOURCE_CHOICE_IMAP_EMAIL:
cls = IMAPEmail
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
context = {
'object_list': cls.objects.all(),
@@ -480,6 +550,9 @@ def setup_source_edit(request, source_type, source_id):
elif source_type == SOURCE_CHOICE_IMAP_EMAIL:
cls = IMAPEmail
form_class = IMAPEmailSetupForm
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
form_class = LocalScannerSetupForm
source = get_object_or_404(cls, pk=source_id)
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/')))
@@ -530,6 +603,10 @@ def setup_source_delete(request, source_type, source_id):
cls = IMAPEmail
form_icon = u'email_delete.png'
redirect_view = 'setup_imap_email_list'
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
form_icon = u'image_delete.png'
redirect_view = 'setup_local_scanner_list'
redirect_view = reverse('setup_source_list', args=[source_type])
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_view)))
@@ -588,7 +665,11 @@ def setup_source_create(request, source_type):
cls = IMAPEmail
form_class = IMAPEmailSetupForm
redirect_view = 'setup_imap_email_list'
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
form_class = LocalScannerSetupForm
redirect_view = 'setup_local_scanner_list'
if request.method == 'POST':
form = form_class(data=request.POST)
if form.is_valid():
@@ -623,6 +704,8 @@ def setup_source_log_list(request, source_type, source_pk):
cls = POP3Email
elif source_type == SOURCE_CHOICE_IMAP_EMAIL:
cls = IMAPEmail
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
source = get_object_or_404(cls, pk=source_pk)
@@ -659,6 +742,8 @@ def setup_source_transformation_list(request, source_type, source_id):
cls = POP3Email
elif source_type == SOURCE_CHOICE_IMAP_EMAIL:
cls = IMAPEmail
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
source = get_object_or_404(cls, pk=source_id)
@@ -765,6 +850,8 @@ def setup_source_transformation_create(request, source_type, source_id):
cls = POP3Email
elif source_type == SOURCE_CHOICE_IMAP_EMAIL:
cls = IMAPEmail
elif source_type == SOURCE_CHOICE_LOCAL_SCANNER:
cls = LocalScanner
source = get_object_or_404(cls, pk=source_id)
@@ -800,3 +887,15 @@ def document_create(request):
wizard = DocumentCreateWizard(form_list=[DocumentTypeSelectForm, MetadataSelectionForm, MetadataFormSet])
return wizard(request)
def scanners_refresh(request):
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
try:
LocalScanner.get_scanners()
messages.success(request, _(u'Scanner list refreshed successfully.'))
except:
messages.error(request, _(u'Scanner list refreshed error.'))
return HttpResponseRedirect(previous)

View File

@@ -88,6 +88,7 @@ Afterwards migrate existing database schema with::
$ ./manage.py migrate job_processor
$ ./manage.py migrate clustering
$ ./manage.py migrate trash
$ ./manage.py migrate sources
Issue the following command to index existing documents in the new full text search database::

View File

@@ -68,6 +68,10 @@ pbs==0.105
psutil==0.5.1
GitPython==0.3.2.RC1
# Sources
-e git+https://github.com/rosarior/imagescanner.git#egg=imagescanner
# Misc
elementtree==1.2.7-20070827-preview