cmis: add view to list available object types (#39416)
This commit is contained in:
parent
45428e944a
commit
b2fe74db2f
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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'),
|
||||
]
|
|
@ -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
|
|
@ -320,6 +320,7 @@ div.section > div > ul.endpoints {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cmis-id,
|
||||
.endpoints .params .param-name {
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue