cmis: add view to list available object types (#39416)

This commit is contained in:
Valentin Deniaud 2020-02-05 16:42:06 +01:00
parent 45428e944a
commit b2fe74db2f
6 changed files with 211 additions and 0 deletions

View File

@ -0,0 +1,49 @@
{% extends "passerelle/manage/service_view.html" %}
{% load i18n passerelle %}
{% block breadcrumb %}
{{ block.super }}
<a href="{% url "cmis-type" object.slug %}">{% trans "CMIS Types" %}</a>
{% endblock %}
{% block content %}
{% if current_type %}
<a href={% url "cmis-type" object.slug %}>
{% trans "Back to base types list" %}
</a>
{% endif %}
<p>
{% if current_type %}
<h3>{% trans "Current type" %} :</h3>
<span class="cmis-id">{{ current_type.id }}</span> : {{ current_type.description }}</span>
</p>
<p>
<h4>Properties :</h4>
<ul>
{% for prop in current_properties %}
<li>
<span class="cmis-id">{{ prop.id }}</span>
({{ prop.propertyType }}{% if prop.required %}, {% trans "required" %}{% endif %}) :
{{ prop.description }}
</li>
{% endfor %}
</ul>
</p>
<p>
<h3>{% trans "Children" %} :</h3>
{% endif %}
{% if children_types %}
<ul>
{% for type in children_types %}
<li><a href={% url "cmis-type" object.slug %}?id={{ type.id }}>{{ type.id }}</a> : {{ type.description }}</li>
{% endfor %}
</ul>
{% else %}
{% trans "No more children." %}
{% endif %}
</p>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "passerelle/manage/service_view.html" %}
{% load i18n passerelle %}
{% block description %}
{{ block.super }}
<p>
<a href="{% url "cmis-type" object.slug %}?type={{ object.root_type }}">{% trans 'Explore available object types' %}</a>
</p>
{% endblock %}

View File

@ -0,0 +1,24 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2020 Entr'ouvert
#
# 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 <http://www.gnu.org/licenses/>.
from django.conf.urls import include, url
from .views import CmisTypeView
management_urlpatterns = [
url(r'^(?P<connector_slug>[\w,-]+)/type/$',
CmisTypeView.as_view(), name='cmis-type'),
]

View File

@ -0,0 +1,58 @@
# passerelle - uniform access to multiple data sources and services
# Copyright (C) 2020 Entr'ouvert
#
# 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 <http://www.gnu.org/licenses/>.
from cmislib import CmisClient
from cmislib.exceptions import ObjectNotFoundException
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
from django.views.generic import TemplateView
from .models import CmisConnector
class CmisTypeView(TemplateView):
model = CmisConnector
template_name = 'cmis/cmis_type.html'
def get(self, request, *args, **kwargs):
self.connector = CmisConnector.objects.get(slug=kwargs['connector_slug'])
client = CmisClient(self.connector.cmis_endpoint, self.connector.username,
self.connector.password)
self.repo = client.getDefaultRepository()
type_id = request.GET.get('id')
if type_id:
try:
self.current_type = self.repo.getTypeDefinition(type_id)
except ObjectNotFoundException:
raise Http404(_('Cmis type not found.'))
else:
self.current_type = None
return super(CmisTypeView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
ctx = super(CmisTypeView, self).get_context_data(**kwargs)
ctx['object'] = self.connector
if self.current_type:
ctx['current_type'] = self.current_type
properties = self.current_type.properties.values()
ctx['current_properties'] = sorted(properties, key=lambda x: x.id)
ctx['children_types'] = self.repo.getTypeChildren(self.current_type.id)
else:
ctx['children_types'] = self.repo.getTypeDefinitions()
return ctx

View File

@ -320,6 +320,7 @@ div.section > div > ul.endpoints {
font-weight: bold;
}
.cmis-id,
.endpoints .params .param-name {
font-family: Monospace;
}

View File

@ -18,6 +18,8 @@ import pytest
from passerelle.base.models import ApiUser, AccessRight
from passerelle.apps.cmis.models import CmisConnector
from test_manager import login, admin_user
def b64encode(content):
return force_text(base64.b64encode(force_bytes(content)))
@ -396,3 +398,71 @@ def test_re_file_name():
RE_FILE_NAME = re.compile(FILE_NAME_PATTERN)
assert RE_FILE_NAME.match('toto.tata')
assert RE_FILE_NAME.match('TOTO.TATA')
def test_cmis_types_view(setup, app, admin_user, monkeypatch):
class FakeCmisType:
class FakeCmisProperty:
def __init__(self, id):
self.id = id
self.description = 'cmis:prop'
self.propertyType = 'string'
self.required = True
def __init__(self, id, children=None):
self.id = id
self.description = 'hop'
prop = self.FakeCmisProperty('cmis:prop')
prop2 = self.FakeCmisProperty('cmis:prop2')
self.properties = {prop.id: prop, prop2.id: prop2}
self.children = children or []
class FakeCmisRepo:
def __init__(self, root_types):
self.root_types = root_types
def getTypeDefinition(self, id):
if id in self.root_types:
return self.root_types[id]
for type in self.root_types.values():
for child in type.children:
if child.id == id:
return child
raise ObjectNotFoundException
def getTypeDefinitions(self):
return self.root_types.values()
def getTypeChildren(self, id):
return self.getTypeDefinition(id).children
children = [FakeCmisType('cmis:child1'), FakeCmisType('cmis:child2')]
root_type1 = FakeCmisType('cmis:root1', children=children)
root_type2 = FakeCmisType('cmis:root2')
root_types = {root_type1.id: root_type1, root_type2.id: root_type2}
repo = FakeCmisRepo(root_types)
from cmislib import CmisClient
monkeypatch.setattr(CmisClient, 'getDefaultRepository', lambda self: repo)
app = login(app)
resp = app.get('/cmis/slug-cmis/')
resp = resp.click('Explore available object types')
assert all(id in resp.text for id in root_types)
assert not 'Back to' in resp.text
assert not 'Children' in resp.text
assert not 'Properties' in resp.text
resp = resp.click(root_type1.id)
assert all(id in resp.text for id in root_type1.properties)
assert all(child.id in resp.text for child in root_type1.children)
resp = resp.click(children[0].id)
assert "No more children." in resp.text
resp = resp.click("Back to base types list")
resp = resp.click(root_type2.id)
assert "No more children." in resp.text
resp = app.get('/manage/cmis/slug-cmis/type?id=wrong', status=404)