[Checkins] SVN: zopyx.smartprintng.server/trunk/ holiday work
Andreas Jung
andreas at andreas-jung.com
Sat Aug 1 16:07:30 EDT 2009
Log message for revision 102414:
holiday work
Changed:
U zopyx.smartprintng.server/trunk/README.txt
U zopyx.smartprintng.server/trunk/docs/HISTORY.txt
U zopyx.smartprintng.server/trunk/setup.py
D zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/base.py
U zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/models.py
U zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/run.py
U zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/index.pt
U zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/static/default.css
U zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py
U zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/views.py
-=-
Modified: zopyx.smartprintng.server/trunk/README.txt
===================================================================
--- zopyx.smartprintng.server/trunk/README.txt 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/README.txt 2009-08-01 20:07:30 UTC (rev 102414)
@@ -14,10 +14,15 @@
Installation
============
-- create an virtualenv environment (Python 2,4, 2.5 or 2.6)::
+- create an virtualenv environment (Python 2,4, 2.5 or 2.6) - either within your
+ current (empty) directory or by letting virtualenv create one for you::
virtualenv --no-site-packages .
+ or::
+
+ virtualenv --no-site-packages smartprintng
+
- install ``repoze.bfg`` (by installing ``repoze.bfg.xmlrpc`` having ``repoze.bfg``
as a dependency) ::
Modified: zopyx.smartprintng.server/trunk/docs/HISTORY.txt
===================================================================
--- zopyx.smartprintng.server/trunk/docs/HISTORY.txt 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/docs/HISTORY.txt 2009-08-01 20:07:30 UTC (rev 102414)
@@ -5,6 +5,11 @@
------------------
* now requires Python 2.6
+* added convertZIPandRedirect() method
+* added deliver() method
+* moved base.ServerCore to models.py
+* delivered files must be younger than 'delivery_max_age' seconds
+* more tests
0.4.3 (2009/07/22)
Modified: zopyx.smartprintng.server/trunk/setup.py
===================================================================
--- zopyx.smartprintng.server/trunk/setup.py 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/setup.py 2009-08-01 20:07:30 UTC (rev 102414)
@@ -1,3 +1,7 @@
+##########################################################################
+# zopyx.smartprintng.server
+# (C) 2008, 2009, ZOPYX Ltd & Co. KG, Tuebingen, Germany
+##########################################################################
import sys
import os
@@ -21,7 +25,7 @@
keywords='SmartPrintNG Conversion repoze.bfg',
author='Andreas Jung',
author_email='info at zopyx.com',
- url='',
+ url='http://www.zopyx.com/projects/smartprintng',
license='ZPL',
packages=find_packages(exclude=['ez_setup']),
namespace_packages=['zopyx', 'zopyx.smartprintng'],
Deleted: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/base.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/base.py 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/base.py 2009-08-01 20:07:30 UTC (rev 102414)
@@ -1,113 +0,0 @@
-##########################################################################
-# zopyx.smartprintng.server
-# (C) 2008, 2009, ZOPYX Ltd & Co. KG, Tuebingen, Germany
-##########################################################################
-
-import base64
-import glob
-import os
-import shutil
-import tempfile
-from datetime import datetime
-import time
-import uuid
-import zipfile
-from logger import LOG
-import mail_util
-from zopyx.convert2.convert import Converter
-
-temp_directory = os.path.join(tempfile.gettempdir(),
- 'zopyx.smartprintng.server')
-if not os.path.exists(temp_directory):
- os.makedirs(temp_directory)
-
-
-class ServerCore(object):
- """ SmartPrintNG Server Core Implementation """
-
- def _inject_base_tag(self, html_filename):
- """ All input HTML files contain relative urls (relative
- to the path of the main HTML file (the "working dir").
- So we must inject a BASE tag in order to call the external
- converters properly with the full path of the html input file
- since we do not want to change the process working dir (not
- acceptable in a multi-threaded environment).
- ATT: this should perhaps handled within zopyx.convert2
- """
- html = file(html_filename).read()
- pos = html.lower().find('<head>')
- html = html[:pos] + '<head><base href="%s"/>' % html_filename + html[pos+6:]
- file(html_filename, 'wb').write(html)
-
- def _convert(self, html_filename, converter_name='pdf-prince'):
- """ Process a single HTML file """
- return Converter(html_filename)(converter_name)
-
- def _processZIP(self, zip_archive, converter_name):
-
- # temp direcotry handling
- now = datetime.now().strftime('%Y%m%d%Z%H%M%S')
- ident = '%s-%s' % (now, uuid.uuid4())
- tempdir = os.path.join(temp_directory, ident)
- os.makedirs(tempdir)
-
- # store zip archive first
- zip_temp = os.path.join(tempdir, 'input.zip')
- file(zip_temp, 'wb').write(base64.decodestring(zip_archive))
- ZF = zipfile.ZipFile(zip_temp, 'r')
- for name in ZF.namelist():
- destfile = os.path.join(tempdir, name)
- if not os.path.exists(os.path.dirname(destfile)):
- os.makedirs(os.path.dirname(destfile))
- file(destfile, 'wb').write(ZF.read(name))
- ZF.close()
-
- # find HTML file
- html_files = glob.glob(os.path.join(tempdir, '*.htm*'))
- if not html_files:
- raise IOError('Archive does not contain any html files')
- if len(html_files) > 1:
- raise RuntimeError('Archive contains more than one html file')
- html_filename = html_files[0]
- # inject BASE tag containing the full local path (required by PrinceXML)
- self._inject_base_tag(html_filename)
- result = self._convert(html_filename,
- converter_name=converter_name)
- basename, ext = os.path.splitext(os.path.basename(result))
-
- # Generate result ZIP archive with base64-encoded result
- zip_out = os.path.join(tempdir, 'output.zip')
- ZF = zipfile.ZipFile(zip_out, 'w')
- ZF.writestr('output%s' % ext, file(result, 'rb').read())
- ZF.close()
- return zip_out, result
-
- def convertZIP(self, zip_archive, converter_name='pdf-prince'):
- """ Process html-file + images within a ZIP archive """
-
- LOG.info('Incoming request (%s, %d bytes)' % (converter_name, len(zip_archive)))
- ts = time.time()
- zip_out, output_filename = self._processZIP(zip_archive, converter_name)
- encoded_result = base64.encodestring(file(zip_out, 'rb').read())
- shutil.rmtree(os.path.dirname(zip_out))
- LOG.info('Request end (%3.2lf seconds)' % (time.time() - ts))
- return encoded_result
-
- def convertZIPEmail(self, zip_archive, converter_name='pdf-prince', sender=None, recipient=None, subject=None, body=None):
- """ Process zip archive and send conversion result as mail """
-
- LOG.info('Incoming request (%s, %d bytes)' % (converter_name, len(zip_archive)))
- ts = time.time()
- zip_out, output_filename = self._processZIP(zip_archive, converter_name)
- mail_util.send_email(sender, recipient, subject, body, [output_filename])
- shutil.rmtree(os.path.dirname(zip_out))
- LOG.info('Request end (%3.2lf seconds)' % (time.time() - ts))
- return True
-
- def availableConverters(self):
- from zopyx.convert2.registry import availableConverters
- return availableConverters()
-
-if __name__ == '__main__':
- s = ServerCore()
- print s.availableConverters()
Modified: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/models.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/models.py 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/models.py 2009-08-01 20:07:30 UTC (rev 102414)
@@ -3,11 +3,172 @@
# (C) 2008, 2009, ZOPYX Ltd & Co. KG, Tuebingen, Germany
##########################################################################
+import threading
+import base64
+import glob
+import os
+import shutil
+import tempfile
+from stat import ST_CTIME
+import shutil
+from datetime import datetime
+import time
+import uuid
+import zipfile
+from logger import LOG
+import mail_util
+from zopyx.convert2.convert import Converter
+
class Server(object):
- pass
+ """ SmartPrintNG Server Core Implementation """
+ def __init__(self):
+ self.num_requests = 0
+ self.start_time = datetime.now()
+ self.delivery_max_age = 1800 # deliver files only younger than xx seconds
+ self.cleanup_after = 3600
+ self.cleanup_last = time.time()
+ self.keep_files_for = 3600 # keep files for no longer than xx seconds
+ self._lock = threading.Lock()
+ self.temp_directory = os.path.join(tempfile.gettempdir(),
+ 'zopyx.smartprintng.server')
+ if not os.path.exists(self.temp_directory):
+ os.makedirs(self.temp_directory)
+
+ def countRequest(self):
+ self._lock.acquire()
+ self.num_requests += 1
+ self._lock.release()
+
+ @property
+ def start_time_as_str(self):
+ return self.start_time.strftime('%d.%m.%Y %H:%M:%S')
+
+ def _cleanup(self):
+ """ Remove old and outdated files from the temporary and
+ spool directory.
+ """
+
+ if time.time() - self.cleanup_last > self.cleanup_after:
+ self._lock.acquire()
+ try:
+ self.__cleanup()
+ self.cleanup_last = time.time()
+ except Exception, e:
+ LOG.error(e, exc_info=True)
+ finally:
+ self._lock.release()
+
+ def __cleanup(self):
+ for dir in os.listdir(self.temp_directory):
+ destdir = os.path.join(self.temp_directory, dir)
+ age = time.time() - os.stat(destdir)[ST_CTIME]
+ if age > self.keep_files_for:
+ shutil.rmtree(destdir)
+
+ for dir in os.listdir(self.spool_directory):
+ destdir = os.path.join(self.spool_directory, dir)
+ age = time.time() - os.stat(destdir)[ST_CTIME]
+ if age > self.keep_files_for:
+ shutil.rmtree(destdir)
+
+ def _inject_base_tag(self, html_filename):
+ """ All input HTML files contain relative urls (relative
+ to the path of the main HTML file (the "working dir").
+ So we must inject a BASE tag in order to call the external
+ converters properly with the full path of the html input file
+ since we do not want to change the process working dir (not
+ acceptable in a multi-threaded environment).
+ ATT: this should perhaps handled within zopyx.convert2
+ """
+ html = file(html_filename).read()
+ pos = html.lower().find('<head>')
+ if pos == -1:
+ raise RuntimeError('HTML does not contain a HEAD tag')
+ html = html[:pos] + '<head><base href="%s"/>' % html_filename + html[pos+6:]
+ file(html_filename, 'wb').write(html)
+
+ def _convert(self, html_filename, converter_name='pdf-prince'):
+ """ Process a single HTML file """
+ self._cleanup()
+ return Converter(html_filename)(converter_name)
+
+ def _processZIP(self, zip_archive, converter_name):
+
+ LOG.info('Incoming request (%s, %d bytes)' % (converter_name, len(zip_archive)))
+ ts = time.time()
+
+ # temp directory handling
+ now = datetime.now().strftime('%Y%m%d%Z%H%M%S')
+ ident = '%s-%s' % (now, uuid.uuid4())
+ tempdir = os.path.join(self.temp_directory, ident)
+ os.makedirs(tempdir)
+
+ # store zip archive first
+ zip_temp = os.path.join(tempdir, 'input.zip')
+ file(zip_temp, 'wb').write(base64.decodestring(zip_archive))
+ ZF = zipfile.ZipFile(zip_temp, 'r')
+ for name in ZF.namelist():
+ destfile = os.path.join(tempdir, name)
+ if not os.path.exists(os.path.dirname(destfile)):
+ os.makedirs(os.path.dirname(destfile))
+ file(destfile, 'wb').write(ZF.read(name))
+ ZF.close()
+
+ # find HTML file
+ html_files = glob.glob(os.path.join(tempdir, '*.htm*'))
+ if not html_files:
+ raise IOError('Archive does not contain any html files')
+ if len(html_files) > 1:
+ raise RuntimeError('Archive contains more than one html file')
+ html_filename = html_files[0]
+ # inject BASE tag containing the full local path (required by PrinceXML)
+ self._inject_base_tag(html_filename)
+ result = self._convert(html_filename,
+ converter_name=converter_name)
+ basename, ext = os.path.splitext(os.path.basename(result))
+
+ # Generate result ZIP archive with base64-encoded result
+ zip_out = os.path.join(tempdir, '%s.zip' % ident)
+ ZF = zipfile.ZipFile(zip_out, 'w')
+ ZF.writestr('output%s' % ext, file(result, 'rb').read())
+ ZF.close()
+
+ LOG.info('Request end (%3.2lf seconds)' % (time.time() - ts))
+ return zip_out, result
+
+ def convertZIP(self, zip_archive, converter_name='pdf-prince'):
+ """ Process html-file + images within a ZIP archive """
+
+ self.countRequest()
+ zip_out, output_filename = self._processZIP(zip_archive, converter_name)
+ encoded_result = base64.encodestring(file(zip_out, 'rb').read())
+ shutil.rmtree(os.path.dirname(zip_out))
+ return encoded_result
+
+ def convertZIPEmail(self, zip_archive, converter_name='pdf-prince', sender=None, recipient=None, subject=None, body=None):
+ """ Process zip archive and send conversion result as mail """
+
+ self.countRequest()
+
+ zip_out, output_filename = self._processZIP(zip_archive, converter_name)
+ mail_util.send_email(sender, recipient, subject, body, [output_filename])
+ shutil.rmtree(os.path.dirname(zip_out))
+ return True
+
+ def availableConverters(self):
+ """ Return a list of available converter names """
+ from zopyx.convert2.registry import availableConverters
+ self.countRequest()
+ return availableConverters()
+
root = Server()
def get_root(environ):
return root
+
+if __name__ == '__main__':
+ s = Server()
+ print s.availableConverters()
+
Modified: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/run.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/run.py 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/run.py 2009-08-01 20:07:30 UTC (rev 102414)
@@ -15,7 +15,10 @@
# paster app config callback
from zopyx.smartprintng.server.models import get_root
import zopyx.smartprintng.server
+ from models import root
from logger import LOG
+ from views import spool_directory
+
if 'mail_config' in global_config:
mail_config = os.path.abspath(global_config['mail_config'])
os.environ['EMAIL_CONFIG'] = mail_config
@@ -23,5 +26,7 @@
LOG.info('Using email configuration at %s' % mail_config)
LOG.info(config)
LOG.info('SmartPrintNG server started')
+ LOG.info('Temp directory: %s' % root.temp_directory)
+ LOG.info('Spool directory: %s' % spool_directory)
return make_app(get_root, zopyx.smartprintng.server, options=kw)
Modified: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/index.pt
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/index.pt 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/index.pt 2009-08-01 20:07:30 UTC (rev 102414)
@@ -2,29 +2,29 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
-<meta http-equiv="content-type" content="text/html; charset=utf-8" />
-<title>${project} Application</title>
-<meta name="keywords" content="python web application" />
-<meta name="description" content="repoze.bfg web application" />
-<link href="${request.application_url}/static/default.css" rel="stylesheet" type="text/css" />
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>${project} Application</title>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="repoze.bfg web application" />
+ <link href="${request.application_url}/static/default.css" rel="stylesheet" type="text/css" />
</head>
<body>
- <div id="logo">
+ <div id="header">
<img src="${request.application_url}/static/zopyx_logo.png" />
- <h2>ZOPYX SmartPrintNG Server</h2>
- <div id="version">Version: ${version}</div>
+ <h2>ZOPYX SmartPrintNG Server - version ${version} </h2>
</div>
<br/>
<div>
- Available converters:
- <ul>
- <li tal:repeat="c converters" tal:content="c" />
- </ul>
+ <span class="label">Start time:</span> ${context.start_time_as_str}
+ <br/>
+ <span class="label"># requests:</span> ${context.num_requests}
+ <br/>
+ <span class="label">Available converters:</span>
+ <span tal:content="python: ', '.join(converters)" />
</div>
<div id="footer">
(C) 2009, ZOPYX Ltd. & Co. KG, <a href="http://www.zopyx.com">www.zopyx.com</a>, <a href="mailto:info at zopyx.com">info at zopyx.com</a>
</div>
-
</body>
</html>
Modified: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/static/default.css
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/static/default.css 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/templates/static/default.css 2009-08-01 20:07:30 UTC (rev 102414)
@@ -2,12 +2,10 @@
font-family: "Arial";
}
-#logo h2 {
+.label {
+ font-weight: bold;
}
-#logo img {
-}
-
#footer {
clear: both;
margin-top: 1em;
@@ -20,9 +18,6 @@
font-weight: bold;
}
-a {
-}
-
a,
a:active,
a:visited {
Modified: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/tests.py 2009-08-01 20:07:30 UTC (rev 102414)
@@ -10,6 +10,7 @@
import zipfile
import tempfile
from repoze.bfg import testing
+from models import Server
xml = """<?xml version="1.0"?>
<methodCall>
@@ -23,6 +24,13 @@
</methodCall>
"""
+xml3 = """<?xml version="1.0"?>
+<methodCall>
+ <methodName>convertZIPandRedirect</methodName>
+ %s
+</methodCall>
+"""
+
class ViewTests(unittest.TestCase):
""" These tests are unit tests for the view. They test the
@@ -44,7 +52,7 @@
def test_index(self):
from zopyx.smartprintng.server.views import index
- context = testing.DummyModel()
+ context = Server()
request = testing.DummyRequest()
renderer = testing.registerDummyRenderer('templates/index.pt')
response = index(context, request)
@@ -64,6 +72,7 @@
provided by bfg and only the registrations you need, as in the
above ViewTests.
"""
+
def setUp(self):
""" This sets up the application registry with the
registrations your application declares in its configure.zcml
@@ -81,7 +90,7 @@
def test_index(self):
from zopyx.smartprintng.server.views import index
- context = testing.DummyModel()
+ context = Server()
request = testing.DummyRequest()
result = index(context, request)
self.assertEqual(result.status, '200 OK')
@@ -94,7 +103,7 @@
def test_xmlrpc_ping(self):
from zopyx.smartprintng.server.views import ping
- context = testing.DummyModel()
+ context = Server()
headers = dict()
headers['content-type'] = 'text/xml'
request = testing.DummyRequest(headers=headers, post=True)
@@ -107,7 +116,7 @@
def test_xmlrpc_convertZIP(self):
from zopyx.smartprintng.server.views import convertZIP
- context = testing.DummyModel()
+ context = Server()
headers = dict()
headers['content-type'] = 'text/xml'
request = testing.DummyRequest(headers=headers, post=True)
@@ -125,3 +134,47 @@
ZIP = zipfile.ZipFile(output_zip_filename, 'r')
self.assertEqual('output.pdf' in ZIP.namelist(), True)
+ def test_xmlrpc_convertZIPandRedirect(self):
+ from zopyx.smartprintng.server.views import convertZIPandRedirect
+ context = Server()
+ headers = dict()
+ headers['content-type'] = 'text/xml'
+ request = testing.DummyRequest(headers=headers, post=True)
+ zip_archive = os.path.join(os.path.dirname(__file__), 'test_data', 'test.zip')
+ zip_data = file(zip_archive, 'rb').read()
+ params = xmlrpclib.dumps((base64.encodestring(zip_data), 'pdf-prince'))
+ request.body = xml3 % params
+ result = convertZIPandRedirect(context, request)
+ self.assertEqual(result.status, '200 OK')
+ body = result.app_iter[0]
+ params, methodname = xmlrpclib.loads(result.body)
+ location = params[0]
+ self.assertEqual('deliver?' in location, True)
+
+ def test_deliver_non_existing_filename(self):
+ from zopyx.smartprintng.server.views import deliver
+ context = Server()
+ request = testing.DummyRequest(params=dict(filename='does-not-exist.pdf'))
+ result = deliver(context, request)
+ self.assertEqual(result.status, '404 Not Found')
+
+ def test_deliver_existing_filename(self):
+ from zopyx.smartprintng.server.views import deliver
+ from views import spool_directory
+ file(os.path.join(spool_directory, 'foo.pdf'), 'wb').write('foo')
+ context = Server()
+ request = testing.DummyRequest(params=dict(filename='foo.pdf'))
+ result = deliver(context, request)
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(('content-type', 'application/pdf') in result.headerlist, True)
+ self.assertEqual(('content-disposition', 'attachment; filename=foo.pdf') in result.headerlist, True)
+
+ def test_deliver_existing_filename_with_prefix(self):
+ from zopyx.smartprintng.server.views import deliver
+ from views import spool_directory
+ file(os.path.join(spool_directory, 'foo.pdf'), 'wb').write('foo')
+ context = Server()
+ request = testing.DummyRequest(params=dict(filename='foo.pdf', prefix='bar'))
+ result = deliver(context, request)
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(('content-disposition', 'attachment; filename=bar.pdf') in result.headerlist, True)
Modified: zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/views.py
===================================================================
--- zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/views.py 2009-08-01 20:07:18 UTC (rev 102413)
+++ zopyx.smartprintng.server/trunk/zopyx/smartprintng/server/views.py 2009-08-01 20:07:30 UTC (rev 102414)
@@ -3,49 +3,92 @@
# (C) 2008, 2009, ZOPYX Ltd & Co. KG, Tuebingen, Germany
##########################################################################
+import os
+import time
+import tempfile
+import shutil
+import mimetypes
+import xmlrpclib
import pkg_resources
+from stat import ST_CTIME
from repoze.bfg.chameleon_zpt import render_template_to_response
from repoze.bfg.view import static
from repoze.bfg.view import bfg_view
-from zopyx.smartprintng.server.base import ServerCore
+from repoze.bfg.xmlrpc import xmlrpc_view
+from webob import Response
from models import Server
from logger import LOG
static_view = static('templates/static')
+spool_directory = os.path.join(tempfile.gettempdir(),
+ 'zopyx.smartprintng.server-spool')
+if not os.path.exists(spool_directory):
+ os.makedirs(spool_directory)
+
##################
# HTTP views
##################
@bfg_view(for_=Server, request_type='GET', permission='read')
class index(object):
+ """ The default view providing some system information """
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self):
- converters = ServerCore().availableConverters()
+ converters = self.context.availableConverters()
version = pkg_resources.require('zopyx.smartprintng.server')[0].version
return render_template_to_response('templates/index.pt',
+ context=self.context,
converters=converters,
request=self.request,
version=version,
project='zopyx.smartprintng.server')
+
+ at bfg_view(for_=Server, name='deliver')
+def deliver(context, request):
+ """ Send out a generated output file """
+
+ filename = request.params['filename']
+ prefix = request.params.get('prefix')
+ dest_filename = os.path.abspath(os.path.join(spool_directory, filename))
+
+ # various (security) checks
+ if not os.path.exists(dest_filename):
+ return Response(status=404)
+
+ if not dest_filename.startswith(spool_directory):
+ return Response(status=404)
+
+ if time.time() - os.stat(dest_filename)[ST_CTIME] >= context.delivery_max_age:
+ return Response(status=404)
+
+ ct, dummy = mimetypes.guess_type(dest_filename)
+ filename = os.path.basename(filename)
+ if prefix:
+ filename = prefix + os.path.splitext(filename)[1]
+ headers = [('content-disposition','attachment; filename=%s' % filename),
+ ('content-type', ct)]
+ return Response(body=file(dest_filename, 'rb').read(),
+ content_type=ct,
+ headerlist=headers
+ )
+
+
##################
# XMLRPC views
##################
-from repoze.bfg.xmlrpc import xmlrpc_view
-import xmlrpclib
@bfg_view(name='convertZIP', for_=Server)
@xmlrpc_view
def convertZIP(context, zip_archive, converter_name='pdf-prince'):
- core = ServerCore()
try:
- return core.convertZIP(zip_archive, converter_name)
+ return context.convertZIP(zip_archive, converter_name)
except Exception, e:
msg = 'Conversion failed (%s)' % e
LOG.error(msg, exc_info=True)
@@ -55,19 +98,53 @@
@bfg_view(name='convertZIPEmail', for_=Server)
@xmlrpc_view
def convertZIPEmail(context, zip_archive, converter_name='pdf-prince', sender=None, recipient=None, subject=None, body=None):
- core = ServerCore()
try:
- return core.convertZIPEmail(zip_archive, converter_name, sender, recipient, subject, body)
+ return context.convertZIPEmail(zip_archive, converter_name, sender, recipient, subject, body)
except Exception, e:
msg = 'Conversion failed (%s)' % e
LOG.error(msg, exc_info=True)
return xmlrpclib.Fault(123, msg)
+ at bfg_view(name='convertZIPandRedirect', for_=Server)
+ at xmlrpc_view
+def convertZIPandRedirect(context, zip_archive, converter_name='prince-pdf', prefix=None):
+ """ This view appects a ZIP archive through a POST request containing all
+ relevant information (similar to the XMLRPC API). However the converted
+ output file is not returned to the caller but delivered "directly" through
+ the SmartPrintNG server (through an URL redirection). The 'prefix'
+ parameter can be used to override the basename of filename used within the
+ content-disposition header.
+ (This class is only a base class for the related http_ and xmlrpc_
+ view (in order to avoid redudant code).)
+ """
+
+ try:
+ output_archivename, output_filename = context._processZIP(zip_archive, converter_name)
+ output_ext = os.path.splitext(output_filename)[1]
+
+ # take ident from archive name
+ ident = os.path.splitext(os.path.basename(output_archivename))[0]
+
+ # move output file to spool directory
+ dest_filename = os.path.join(spool_directory, '%s%s' % (ident, output_ext))
+ rel_output_filename = dest_filename.replace(spool_directory + os.sep, '')
+ shutil.move(output_filename, dest_filename)
+ host = 'localhost'
+ port = 6543
+ prefix = prefix or ''
+ location = 'http://%s:%s/deliver?filename=%s&prefix=%s' % (host, port, rel_output_filename, prefix)
+ return location
+ except Exception, e:
+ msg = 'Conversion failed (%s)' % e
+ LOG.error(msg, exc_info=True)
+ return xmlrpclib.Fault(123, msg)
+
+
@bfg_view(name='availableConverters', for_=Server)
@xmlrpc_view
def availableConverters(context):
- return ServerCore().availableConverters()
+ return context.availableConverters()
@bfg_view(name='ping', for_=Server)
More information about the Checkins
mailing list