contrib.iparapheur: create file endpoint
Inserts new file into iParapheur workflow
This commit is contained in:
parent
51adec0b18
commit
8d16ea4e15
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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('',
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -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>
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue