contrib.iparapheur: create file endpoint

Inserts new file into iParapheur workflow
This commit is contained in:
Serghei Mihai 2015-10-29 17:03:16 +01:00
parent 51adec0b18
commit 8d16ea4e15
8 changed files with 1443 additions and 1 deletions

View File

@ -25,6 +25,10 @@ from passerelle.base.models import BaseResource
from .soap import get_client
class FileError(Exception):
pass
class Management(BaseResource):
wsdl_url = models.CharField(max_length=128, blank=False,
verbose_name=_('WSDL URL'),
@ -78,3 +82,24 @@ class Management(BaseResource):
if status:
return c.service.RechercherDossiers(Status=status)
return c.service.RechercherDossiers()
def create_file(self, typ, subtyp, title, visibility, data, email=None):
c = get_client(self)
if visibility not in ['PUBLIC', 'SERVICE', 'CONFIDENTIEL']:
raise FileError('Unknown value for "visibility". Should be "PUBLIC", "SERVICE" or "CONFIDENTIEL"')
doc = c.factory.create("TypeDoc")
doc['value'] = data
doc['_contentType'] = 'application/pdf'
d = {'TypeTechnique': typ,
'DossierTitre': title,
'SousType': subtyp,
'Visibilite': visibility,
'DocumentPrincipal' : doc,
}
if email:
d['EmailEmetteur'] = email
r = c.service.CreerDossier(**d)
if r.MessageRetour.codeRetour == 'KO':
raise FileError(r.MessageRetour.message)
return {'RecordId': r.DossierID,
'message': r.MessageRetour.message}

View File

@ -34,6 +34,21 @@
{% trans 'List files by status:' %} <a href="{{ files_url }}"
>{{ site_base_uri }}{{ files_url }}</a>[?status=status]</li>
<li>
{% url 'iparapheur-create-file' slug=object.slug as create_file_url %}
{% trans 'Create file:' %} <a href="{{ create_file_url }}"
>{{ site_base_uri }}{{ create_file_url }}</a> [POST]
<p>{% trans "In the payload" %}
<ul>
<li><em>type</em> - {% trans "file type" %}</li>
<li><em>subtype</em> - {% trans "file subtype" %}</li>
<li><em>title</em> - {% trans "file title" %}</li>
<li><em>visibility</em> - {% trans "file visibility" %}</li>
<li><em>data</em> - {% trans "base64 encoded data" %}</li>
<li><em>email</em> - {% trans "optional issuer's email" %}</li>
</ul>
</p>
</li>
</ul>
</div>

View File

@ -31,6 +31,8 @@ public_urlpatterns = patterns('',
name='iparapheur-subtypes'),
url(r'^(?P<slug>[\w,-]+)/files/$', ListFiles.as_view(),
name='iparapheur-list-files'),
url(r'^(?P<slug>[\w,-]+)/create-file/$', CreateFile.as_view(),
name='iparapheur-create-file'),
)
management_urlpatterns = patterns('',

View File

@ -14,11 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import json
import urlparse
import requests
from subprocess import Popen
import base64
import tempfile
import logging
import shutil
from django.core.urlresolvers import reverse
from django.views.generic import DetailView as GenericDetailView, View
@ -31,6 +35,8 @@ from passerelle import utils
from .models import Management
from .forms import ManagementForm, ManagementUpdateForm
log = logging.getLogger(__name__)
class ManagementDetailView(GenericDetailView):
model = Management
@ -93,3 +99,40 @@ class ListFiles(DetailView):
status = request.GET.get('status')
return [{'status': r.status, 'id': r.nom, 'timestamp': r.timestamp} \
for r in self.get_object().get_files_list(status)]
class CreateFile(GenericDetailView):
model = Management
@csrf_exempt
def dispatch(self, request, *args, **kwargs):
return super(CreateFile, self).dispatch(request, *args, **kwargs)
@utils.to_json('api')
def post(self, request, *args, **kwargs):
data = json.loads(request.body)
title = data['title']
typ = data['type']
subtype = data['subtype']
email = data.get('email')
visibility = data['visibility']
data = data['data']
try:
temp_dir = tempfile.mkdtemp(__name__)
temp_filename = tempfile.mktemp(dir=temp_dir)
dest_temp_filename = temp_filename + '.pdf'
with open(temp_filename, 'w') as temp:
temp.write(base64.b64decode(data))
p = Popen(['libreoffice', '--headless', '--convert-to', 'pdf',
temp.name, '--outdir', temp_dir])
p.wait()
data = base64.b64encode(file(dest_temp_filename).read())
res = self.get_object().create_file(typ, subtype, title,
visibility, data, email)
except Exception, e:
res = False
log.error('error occured: %r', e)
finally:
shutil.rmtree(temp_dir)
return res

1255
tests/data/iparapheur.wsdl Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

49
tests/data/xmlmime.xml Normal file
View File

@ -0,0 +1,49 @@
<?xml version="1.0" ?>
<!--
W3C XML Schema defined in the Describing Media Content of Binary Data in XML
specification
http://www.w3.org/TR/xml-media-types
Copyright © 2005 World Wide Web Consortium,
(Massachusetts Institute of Technology, European Research Consortium for
Informatics and Mathematics, Keio University). All Rights Reserved. This
work is distributed under the W3C® Software License [1] 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.
[1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
$Id: xmlmime.xsd,v 1.1 2005/04/25 17:08:35 hugo Exp $
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
targetNamespace="http://www.w3.org/2005/05/xmlmime" >
<xs:attribute name="contentType">
<xs:simpleType>
<xs:restriction base="xs:string" >
<xs:minLength value="3" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="expectedContentTypes" type="xs:string" />
<xs:complexType name="base64Binary" >
<xs:simpleContent>
<xs:extension base="xs:base64Binary" >
<xs:attribute ref="xmime:contentType" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="hexBinary" >
<xs:simpleContent>
<xs:extension base="xs:hexBinary" >
<xs:attribute ref="xmime:contentType" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>

View File

@ -1,5 +1,9 @@
import pytest
import mock
import uuid
import os
import base64
import xml.etree.ElementTree as ET
from django.core.wsgi import get_wsgi_application
from django.core.urlresolvers import reverse
@ -10,8 +14,13 @@ from passerelle.contrib.iparapheur.models import Management
pytestmark = pytest.mark.django_db
WSDL_URL = 'https://secure-iparapheur.demonstrations.adullact.org:443/ws-iparapheur?wsdl'
BASE_URL = 'https://secure-iparapheur.demonstrations.adullact.org:443/ws-iparapheur'
WSDL_URL = '%s?wsdl' % BASE_URL
API_KEY = 'iparapheur'
SOAP_NAMESPACES = {'soap': 'http://schemas.xmlsoap.org/soap/envelope/',
'ns1': 'http://www.adullact.org/spring-ws/iparapheur/1.0',
'xmlmime': 'http://www.w3.org/2005/05/xmlmime'
}
@pytest.fixture
def setup():
@ -39,3 +48,47 @@ def test_call_ping(client, setup):
resp = app.get(reverse('iparapheur-ping', kwargs={'slug': conn.slug}),
params={'apikey': API_KEY}, status=200)
assert resp.json['data'] == 'pong'
@mock.patch('passerelle.contrib.iparapheur.soap.requests.get')
@mock.patch('passerelle.contrib.iparapheur.soap.requests.post')
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open')
def test_create_file(http_open, mocked_post, mocked_get, setup):
app, conn = setup
file_id = str(uuid.uuid4())
file_title = "TestDocument"
typ = 'Courrier'
subtyp = 'maire'
visibility = 'SERVICE'
wsdl_file = os.path.join(os.path.dirname(__file__), 'data',
'iparapheur.wsdl')
xmlmime = os.path.join(os.path.dirname(__file__), 'data',
'xmlmime.xml')
soap_response = """
<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><CreerDossierResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"><MessageRetour><codeRetour>OK</codeRetour><message>Dossier %s soumis dans le circuit</message><severite>INFO</severite></MessageRetour><DossierID>%s</DossierID></CreerDossierResponse></S:Body></S:Envelope>
""" % (file_title, file_id)
file_data = file(os.path.join(os.path.dirname(__file__), 'data',
'iparapheur_test.odt'))
base64_data = base64.b64encode(file_data.read())
data = {'type': typ, 'subtype': subtyp, 'visibility': visibility,
'title': file_title, 'data': base64_data}
http_open.return_value = file(xmlmime)
mocked_get.return_value = mock.Mock(content = file(wsdl_file).read(),
status_code=200)
mocked_post.return_value = mock.Mock(status_code=200,
content=soap_response)
url = reverse('iparapheur-create-file', kwargs={'slug': conn.slug})
url += '?apikey=%s' % API_KEY
resp = app.post_json(url, data, status=200)
# check output call args
assert (BASE_URL,) == mocked_post.call_args[0]
xml = ET.fromstring(mocked_post.call_args[1].get('data'))
req = xml.find('soap:Body', SOAP_NAMESPACES).find('ns1:CreerDossierRequest', SOAP_NAMESPACES)
assert req.find('ns1:DossierTitre', SOAP_NAMESPACES).text == file_title
assert req.find('ns1:TypeTechnique', SOAP_NAMESPACES).text == typ
assert req.find('ns1:SousType', SOAP_NAMESPACES).text == subtyp
assert req.find('ns1:Visibilite', SOAP_NAMESPACES).text == visibility
assert resp.json['data']['RecordId'] == file_id