# Officeshots.org - Test your office documents in different applications # Copyright (C) 2009 Stichting Lone Wolves # Written by Sander Marechal # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """ The core backend class """ import os import base64 import logging class BackendException: """ A base Backend exception class. Backends should derive their own exceptions from this. When the Factory catches this exception and recoverable is False, then the backend will be unloaded. """ def __init__(self, message, recoverable = False): self.message = message self.recoverable = recoverable def __str__(self): if self.recoverable: return self.message + ' (Recoverable)' return self.message + ' (Not recoverable)' class Backend: """ The base backend class. Backends shoudl derive from this """ def __init__(self, options, config, section): self.options = options self.config = config self.section = section self.application = config.get(section, 'application').lower() self.version = config.get(section, 'version').lower() self.doctype = [s.strip() for s in config.get(section, 'doctype').split(',')] self.formats = [s.strip() for s in config.get(section, 'formats').split(',')] def initialize(self): """ This is called right after instanciating the backend. """ pass def can_process(self, job): """ Return True if this backend is eligable to process this Job, False otherwise """ eligable = ( job['application'].lower() == self.application and job['version'].lower() == self.version and job['doctype'] in self.doctype and (job['format'] == '' or job['format'] in self.formats) ) return eligable def process(self, job): """ Process a job. Backends must override this method. """ raise NotImplementedError def save_document(self, job): """ Save the file in a job to a temporary location and return the full path. Note that the job ID is used to form the name rather than the original filename to help avoid collisions. """ if not 'job' in job or not 'filename' in job or not 'doctype' in job or not 'document' in job: raise BackendException('Could not save job document to temporary file. Invalid job.', True) (root, ext) = os.path.splitext(job['filename']) tmp_dir = os.path.normpath(self.config.get('global', 'tmp_files')) if not os.path.exists(tmp_dir): logging.info('Temporary storage %s does not exist. Attempting to create', tmp_dir) try: os.makedirs(tmp_dir) except OSError: raise BackendException('Could not create temporary storage location %s' % tmp_dir) filename = os.path.join(tmp_dir, job['job'] + ext) logging.debug('Temporary filename: %s' % filename) try: file = open(filename, 'wb') file.write(base64.b64decode(job['document'])) file.close() except IOError, e: raise BackendException('Could not write temporary file %s (%s)' % (filename, e)) except TypeError, e: raise BackendException('Document is not base64 encoded (%s)' % e, True) return filename def load_document(self, path, encode=True): try: file = open(path, 'rb') contents = file.read() file.close() except (IOError): raise BackendException('Could not read file %s' % path, True) if contents == '': raise BackendException('File %s is empty' % path, True) if encode: contents = base64.b64encode(contents) return contents