Projet

Général

Profil

0001-cmis-add-cmis-connector-to-upload-file-12876.patch

Jean-Baptiste Jaillet, 01 septembre 2016 16:42

Télécharger (8,43 ko)

Voir les différences:

Subject: [PATCH] cmis: add cmis connector to upload file (#12876)

 passerelle/apps/cmis/__init__.py                |  0
 passerelle/apps/cmis/migrations/0001_initial.py | 31 ++++++++++
 passerelle/apps/cmis/migrations/__init__.py     |  0
 passerelle/apps/cmis/models.py                  | 66 ++++++++++++++++++++
 passerelle/settings.py                          |  1 +
 tests/test_cmis.py                              | 80 +++++++++++++++++++++++++
 6 files changed, 178 insertions(+)
 create mode 100644 passerelle/apps/cmis/__init__.py
 create mode 100644 passerelle/apps/cmis/migrations/0001_initial.py
 create mode 100644 passerelle/apps/cmis/migrations/__init__.py
 create mode 100644 passerelle/apps/cmis/models.py
 create mode 100644 tests/test_cmis.py
passerelle/apps/cmis/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import models, migrations
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('base', '0002_auto_20151009_0326'),
11
    ]
12

  
13
    operations = [
14
        migrations.CreateModel(
15
            name='CmisConnector',
16
            fields=[
17
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
                ('title', models.CharField(max_length=50)),
19
                ('slug', models.SlugField()),
20
                ('description', models.TextField()),
21
                ('log_level', models.CharField(default=b'NOTSET', max_length=10, verbose_name='Log Level', choices=[(b'NOTSET', b'NOTSET'), (b'DEBUG', b'DEBUG'), (b'INFO', b'INFO'), (b'WARNING', b'WARNING'), (b'ERROR', b'ERROR'), (b'CRITICAL', b'CRITICAL'), (b'FATAL', b'FATAL')])),
22
                ('cmis_endpoint', models.CharField(help_text='URL of the CMIS endpoint', max_length=250, verbose_name='CMIS endpoint')),
23
                ('username', models.CharField(help_text='Username on DMS platform', max_length=128, verbose_name='Service username')),
24
                ('password', models.CharField(help_text='Password on DMS platform', max_length=128, verbose_name='Password')),
25
                ('users', models.ManyToManyField(to='base.ApiUser', blank=True)),
26
            ],
27
            options={
28
                'abstract': False,
29
            },
30
        ),
31
    ]
passerelle/apps/cmis/models.py
1
from cmislib import CmisClient
2
from cmislib.model import PermissionDeniedException, ObjectNotFoundException, UpdateConflictException, CmisException as CmisLibException
3
import json
4
import base64
5
import logging
6

  
7
from django.db import models
8
from passerelle.base.models import BaseResource
9
from passerelle.utils.api import endpoint
10
from django.utils.translation import ugettext_lazy as _
11
from django.http import HttpResponse
12

  
13

  
14
class CmisException(Exception):
15
    http_status = 200
16
    log_error = False
17

  
18

  
19
class CmisConnector(BaseResource):
20
    cmis_endpoint = models.CharField(max_length=250, verbose_name=_('CMIS endpoint'),
21
                                     help_text=_('URL of the CMIS endpoint'))
22
    username = models.CharField(max_length=128, verbose_name=_('Service username'), help_text=_('Username on DMS platform'))
23
    password = models.CharField(max_length=128,
24
                                verbose_name=_('Password'), help_text=_('Password on DMS platform'))
25

  
26
    category = _('Business Process Connectors')
27

  
28
    @classmethod
29
    def get_icon_class(cls):
30
        return 'ressources'
31

  
32
    @endpoint(serializer_type='json-api', methods=['post'])
33
    def upload_file(self, request, **kwargs):
34
        data = json.loads(request.body)
35

  
36
        title = data['filename']
37
        path = data['path'].encode('utf-8')
38
        content = base64.b64decode(data['content'])
39
        content_type = data['contentType']
40

  
41
        repo = self.cmis_connection()
42
        try:
43
            folder = repo.getObjectByPath(path)
44
        except ObjectNotFoundException:
45
            raise CmisException('Path not found on platform.')
46
        except Exception as e:
47
            raise CmisException(str(e))
48

  
49
        try:
50
            doc = folder.createDocumentFromString(title, contentString=content, contentType=content_type)
51
        except UpdateConflictException:
52
            raise CmisException('The document already exists on platform.')
53
        except Exception as e:
54
            raise CmisException(str(e))
55

  
56
        return doc.properties
57

  
58
    def cmis_connection(self):
59
        try:
60
            cmis_client = CmisClient(self.cmis_endpoint, self.username, self.password)
61
        except PermissionDeniedException:
62
            raise CmisException('Wrong username or password to connect to platform.')
63
        except ObjectNotFoundException:
64
            raise CmisException('Platform endpoint not found.')
65

  
66
        return cmis_client.defaultRepository
passerelle/settings.py
112 112
    'base_adresse',
113 113
    'csvdatasource',
114 114
    'orange',
115
    'cmis',
115 116
    # backoffice templates and static
116 117
    'gadjo',
117 118
)
tests/test_cmis.py
1
import pytest
2
import mock
3
import base64
4
import ast
5

  
6
from cmis.models import CmisConnector
7
from django.contrib.contenttypes.models import ContentType
8
from passerelle.base.models import ApiUser, AccessRight
9
from django.core.urlresolvers import reverse
10

  
11

  
12
@pytest.fixture()
13
def setup(db):
14
    api = ApiUser.objects.create(username='all', keytype='', key='')
15

  
16
    conn = CmisConnector.objects.create(cmis_endpoint='http://cmis_endpoint.com/cmis', username='admin', password='admin', slug='cmis')
17
    obj_type = ContentType.objects.get_for_model(conn)
18

  
19
    AccessRight.objects.create(codename='can_access', apiuser=api,
20
                               resource_type=obj_type, resource_pk=conn.pk)
21

  
22
    return conn
23

  
24
@pytest.fixture()
25
def url():
26
    return reverse('generic-endpoint', kwargs={
27
                  'connector': 'cmis', 'slug': 'cmis', 'endpoint': 'upload_file'})
28

  
29

  
30
fake_file = {
31
    'filename': 'test.txt',
32
    'path': '/a/path',
33
    'content': base64.b64encode('fake file content.'),
34
    'contentType': 'text/plain'
35
}
36

  
37

  
38
class MockedCmisDocument(mock.Mock):
39

  
40
    @property
41
    def properties(self):
42
        return {
43
            'cmis:baseTypeId': 'cmis:document',
44
            'cmis:contentStreamFileName': self.title,
45
            'cmis:contentStreamMimeType': self.contentType,
46
        }
47

  
48

  
49
class MockedCmisFolder(mock.Mock):
50

  
51
    def createDocumentFromString(self, title, contentString, contentType):
52
        return MockedCmisDocument(title=title, contentString=contentString, contentType=contentType)
53

  
54

  
55
class MockedCmisRepository(mock.Mock):
56

  
57
    def getObjectByPath(self, path):
58
        return MockedCmisFolder()
59

  
60

  
61
class MockedCmisClient(mock.Mock):
62

  
63
    @property
64
    def defaultRepository(self):
65
        return MockedCmisRepository()
66

  
67
@mock.patch('cmis.models.CmisClient')
68
def test_cmis_upload(mock_connection, app, setup, url):
69
    mock_connection.return_value = MockedCmisClient()
70
    response = app.post_json(url, fake_file, status=200)
71
    body = ast.literal_eval(response.body)
72
    assert 'data' in body
73
    assert body['err'] == 0
74
    data = body['data']
75
    assert 'cmis:baseTypeId' in data
76
    assert 'cmis:contentStreamFileName' in data
77
    assert 'cmis:contentStreamMimeType' in data
78
    assert data['cmis:baseTypeId'] == 'cmis:document'
79
    assert data['cmis:contentStreamFileName'] == fake_file['filename']
80
    assert data['cmis:contentStreamMimeType'] == fake_file['contentType']
0
-