Merge pull request #1143 from normanjaeckel/PluginAPI
Change API for plugins, esp. for names and versions of plugins. Also enh...
This commit is contained in:
commit
399ab5a96c
@ -14,6 +14,7 @@ Files:
|
|||||||
- Enabled update and delete view for uploader refering to his own files.
|
- Enabled update and delete view for uploader refering to his own files.
|
||||||
Other:
|
Other:
|
||||||
- Changed widget api. Used new metaclass.
|
- Changed widget api. Used new metaclass.
|
||||||
|
- Changed api for plugins.
|
||||||
|
|
||||||
|
|
||||||
Version 1.5.1 (unreleased)
|
Version 1.5.1 (unreleased)
|
||||||
|
@ -7,8 +7,14 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans 'Version' %}</h1>
|
<h1>{% trans 'Version' %}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
{% for version in versions %}
|
{% for module in modules %}
|
||||||
<li>{{ version.0 }} – {% trans 'Version' %} {{ version.1 }}</li>
|
<li>
|
||||||
|
{{ module.verbose_name }}
|
||||||
|
{% if module.description %}
|
||||||
|
({{ module.description }})
|
||||||
|
{% endif %}
|
||||||
|
– {% trans 'Version' %} {{ module.version }}
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -5,8 +5,10 @@ from django.core.exceptions import PermissionDenied
|
|||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from haystack.views import SearchView as _SearchView
|
from haystack.views import SearchView as _SearchView
|
||||||
|
|
||||||
from openslides import get_git_commit_id, get_version, RELEASE
|
from openslides import get_version as get_openslides_version
|
||||||
|
from openslides import get_git_commit_id, RELEASE
|
||||||
from openslides.config.api import config
|
from openslides.config.api import config
|
||||||
|
from openslides.utils.plugins import get_plugin_description, get_plugin_verbose_name, get_plugin_version
|
||||||
from openslides.utils.signals import template_manipulation
|
from openslides.utils.signals import template_manipulation
|
||||||
from openslides.utils.views import TemplateView
|
from openslides.utils.views import TemplateView
|
||||||
|
|
||||||
@ -22,41 +24,19 @@ class VersionView(TemplateView):
|
|||||||
Adds version strings to the context.
|
Adds version strings to the context.
|
||||||
"""
|
"""
|
||||||
context = super(VersionView, self).get_context_data(**kwargs)
|
context = super(VersionView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
# OpenSlides version. During development the git commit id is added.
|
# OpenSlides version. During development the git commit id is added.
|
||||||
openslides_version_string = get_version()
|
if RELEASE:
|
||||||
if not RELEASE:
|
description = ''
|
||||||
openslides_version_string += ' – Commit %s' % get_git_commit_id()
|
else:
|
||||||
context['versions'] = [('OpenSlides', openslides_version_string)]
|
description = 'Commit %s' % get_git_commit_id()
|
||||||
|
context['modules'] = [{'verbose_name': 'OpenSlides',
|
||||||
|
'description': description,
|
||||||
|
'version': get_openslides_version()}]
|
||||||
# Versions of plugins.
|
# Versions of plugins.
|
||||||
for plugin in settings.INSTALLED_PLUGINS:
|
for plugin in settings.INSTALLED_PLUGINS:
|
||||||
# Get plugin
|
context['modules'].append({'verbose_name': get_plugin_verbose_name(plugin),
|
||||||
try:
|
'description': get_plugin_description(plugin),
|
||||||
mod = import_module(plugin)
|
'version': get_plugin_version(plugin)})
|
||||||
except ImportError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Get version.
|
|
||||||
try:
|
|
||||||
plugin_version = mod.get_version()
|
|
||||||
except AttributeError:
|
|
||||||
try:
|
|
||||||
plugin_version = mod.VERSION
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Get name.
|
|
||||||
try:
|
|
||||||
plugin_name = mod.get_name()
|
|
||||||
except AttributeError:
|
|
||||||
try:
|
|
||||||
plugin_name = mod.NAME
|
|
||||||
except AttributeError:
|
|
||||||
plugin_name = mod.__name__.split('.')[0]
|
|
||||||
|
|
||||||
context['versions'].append((plugin_name, plugin_version))
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,11 +2,22 @@
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import include, patterns, url
|
from django.conf.urls import include, patterns, url
|
||||||
from django.utils.importlib import import_module
|
|
||||||
|
from openslides.utils.plugins import get_urlpatterns
|
||||||
|
|
||||||
handler500 = 'openslides.utils.views.server_error'
|
handler500 = 'openslides.utils.views.server_error'
|
||||||
|
|
||||||
urlpatterns = patterns(
|
urlpatterns = []
|
||||||
|
|
||||||
|
js_info_dict = {'packages': []}
|
||||||
|
|
||||||
|
for plugin in settings.INSTALLED_PLUGINS:
|
||||||
|
plugin_urlpatterns = get_urlpatterns(plugin)
|
||||||
|
if plugin_urlpatterns:
|
||||||
|
urlpatterns += plugin_urlpatterns
|
||||||
|
js_info_dict['packages'].append(plugin)
|
||||||
|
|
||||||
|
urlpatterns += patterns(
|
||||||
'',
|
'',
|
||||||
(r'^agenda/', include('openslides.agenda.urls')),
|
(r'^agenda/', include('openslides.agenda.urls')),
|
||||||
(r'^motion/', include('openslides.motion.urls')),
|
(r'^motion/', include('openslides.motion.urls')),
|
||||||
@ -18,19 +29,6 @@ urlpatterns = patterns(
|
|||||||
(r'^i18n/', include('django.conf.urls.i18n')),
|
(r'^i18n/', include('django.conf.urls.i18n')),
|
||||||
)
|
)
|
||||||
|
|
||||||
js_info_dict = {'packages': []}
|
|
||||||
|
|
||||||
for plugin in settings.INSTALLED_PLUGINS:
|
|
||||||
try:
|
|
||||||
mod = import_module(plugin + '.urls')
|
|
||||||
except ImportError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
plugin_name = mod.__name__.split('.')[0]
|
|
||||||
urlpatterns += patterns('', (r'^%s/' % plugin_name, include('%s.urls'
|
|
||||||
% plugin)))
|
|
||||||
js_info_dict['packages'].append(plugin)
|
|
||||||
|
|
||||||
# TODO: move this patterns into core or the participant app
|
# TODO: move this patterns into core or the participant app
|
||||||
urlpatterns += patterns(
|
urlpatterns += patterns(
|
||||||
'',
|
'',
|
||||||
|
82
openslides/utils/plugins.py
Normal file
82
openslides/utils/plugins.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
plugins = {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin(plugin):
|
||||||
|
"""
|
||||||
|
Returns the imported module. The plugin argument must be a python dotted
|
||||||
|
module path.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
plugin = plugins[plugin]
|
||||||
|
except KeyError:
|
||||||
|
plugins[plugin] = import_module(plugin)
|
||||||
|
plugin = get_plugin(plugin)
|
||||||
|
return plugin
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_verbose_name(plugin):
|
||||||
|
"""
|
||||||
|
Returns the verbose name of a plugin. The plugin argument must be a python
|
||||||
|
dotted module path.
|
||||||
|
"""
|
||||||
|
plugin = get_plugin(plugin)
|
||||||
|
try:
|
||||||
|
verbose_name = plugin.get_verbose_name()
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
verbose_name = plugin.__verbose_name__
|
||||||
|
except AttributeError:
|
||||||
|
verbose_name = plugin.__name__
|
||||||
|
return verbose_name
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_description(plugin):
|
||||||
|
"""
|
||||||
|
Returns the short descrption of a plugin. The plugin argument must be a
|
||||||
|
python dotted module path.
|
||||||
|
"""
|
||||||
|
plugin = get_plugin(plugin)
|
||||||
|
try:
|
||||||
|
description = plugin.get_description()
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
description = plugin.__description__
|
||||||
|
except AttributeError:
|
||||||
|
description = ''
|
||||||
|
return description
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_version(plugin):
|
||||||
|
"""
|
||||||
|
Returns the version string of a plugin. The plugin argument must be a#
|
||||||
|
python dotted module path.
|
||||||
|
"""
|
||||||
|
plugin = get_plugin(plugin)
|
||||||
|
try:
|
||||||
|
version = plugin.get_version()
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
version = plugin.__version__
|
||||||
|
except AttributeError:
|
||||||
|
version = 'unknown'
|
||||||
|
return version
|
||||||
|
|
||||||
|
|
||||||
|
def get_urlpatterns(plugin):
|
||||||
|
"""
|
||||||
|
Returns the urlpatterns object for a plugin. The plugin argument must be
|
||||||
|
a python dotted module path.
|
||||||
|
"""
|
||||||
|
plugin = get_plugin(plugin)
|
||||||
|
try:
|
||||||
|
urlpatterns = plugin.urlpatterns
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
urlpatterns = plugin.urls.urlpatterns
|
||||||
|
except AttributeError:
|
||||||
|
urlpatterns = None
|
||||||
|
return urlpatterns
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
from mock import MagicMock, patch
|
from mock import patch
|
||||||
|
|
||||||
from openslides import get_version
|
from openslides import get_version
|
||||||
from openslides.agenda.models import Item
|
from openslides.agenda.models import Item
|
||||||
@ -23,24 +23,10 @@ class VersionViewTest(TestCase):
|
|||||||
@patch('openslides.core.views.settings')
|
@patch('openslides.core.views.settings')
|
||||||
def test_with_missing_plugin(self, mock_settings):
|
def test_with_missing_plugin(self, mock_settings):
|
||||||
"""
|
"""
|
||||||
Tests that an not existing app does not appear on the version view.
|
Tests that a not existing app does not appear on the version view.
|
||||||
"""
|
"""
|
||||||
mock_settings.INSTALLED_PLUGINS = ('unexisting_app_nvhbkdfgmnsd',)
|
mock_settings.INSTALLED_PLUGINS = ('unexisting_app_nvhbkdfgmnsd',)
|
||||||
response = self.client.get('/version/')
|
self.assertRaises(ImportError, self.client.get, '/version/')
|
||||||
self.assertNotContains(response, 'unexisting_app_nvhbkdfgmnsd', status_code=200)
|
|
||||||
|
|
||||||
@patch('openslides.core.views.settings')
|
|
||||||
@patch('openslides.core.views.import_module')
|
|
||||||
def test_with_plugin_without_version(self, mock_import_module, mock_settings):
|
|
||||||
"""
|
|
||||||
Tests that an exisiting app does not appear in the version view if
|
|
||||||
there are no version data.
|
|
||||||
"""
|
|
||||||
mock_settings.INSTALLED_PLUGINS = ('existing_app_without_version',)
|
|
||||||
mock_module = MagicMock(spec=['some_useless_attribute_ghbnckj756j36'])
|
|
||||||
mock_import_module.configure_mock(return_value=mock_module)
|
|
||||||
response = self.client.get('/version/')
|
|
||||||
self.assertNotContains(response, 'unexisting_app_nvhbkdfgmnsd', status_code=200)
|
|
||||||
|
|
||||||
|
|
||||||
class SearchViewTest(TestCase):
|
class SearchViewTest(TestCase):
|
||||||
|
0
tests/plugin_api/__init__.py
Normal file
0
tests/plugin_api/__init__.py
Normal file
35
tests/plugin_api/test_plugin_api.py
Normal file
35
tests/plugin_api/test_plugin_api.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from django.test.client import Client
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
from openslides.utils.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(INSTALLED_PLUGINS=('tests.plugin_api.test_plugin_one',))
|
||||||
|
class TestPluginOne(TestCase):
|
||||||
|
urls = 'tests.plugin_api.urls' # Use reloaded urlpatterns for this TestCase
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.admin_client = Client()
|
||||||
|
self.admin_client.login(username='admin', password='admin')
|
||||||
|
|
||||||
|
def test_version_page(self):
|
||||||
|
response = self.admin_client.get('/version/')
|
||||||
|
self.assertContains(response, 'Test Plugin ta3Ohmaiquee2phaf9ei')
|
||||||
|
self.assertContains(response, '(Short description of test plugin Sah9aiQuae5hoocai7ai)')
|
||||||
|
self.assertContains(response, '– Version test_version_string_MoHonepahfofiree6Iej')
|
||||||
|
|
||||||
|
def test_url_patterns(self):
|
||||||
|
response = self.admin_client.get('/test_plugin_one_url_Eexea4nie1fexaax3oX7/')
|
||||||
|
self.assertRedirects(response, '/version/')
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(INSTALLED_PLUGINS=('tests.plugin_api.test_plugin_two',))
|
||||||
|
class TestPluginTwo(TestCase):
|
||||||
|
def test_version_page(self):
|
||||||
|
admin_client = Client()
|
||||||
|
admin_client.login(username='admin', password='admin')
|
||||||
|
response = admin_client.get('/version/')
|
||||||
|
self.assertContains(response, 'tests.plugin_api.test_plugin_two')
|
||||||
|
self.assertContains(response, '– Version unknown')
|
13
tests/plugin_api/test_plugin_one/__init__.py
Normal file
13
tests/plugin_api/test_plugin_one/__init__.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
|
__verbose_name__ = 'Test Plugin ta3Ohmaiquee2phaf9ei'
|
||||||
|
__version__ = 'test_version_string_MoHonepahfofiree6Iej'
|
||||||
|
__description__ = 'Short description of test plugin Sah9aiQuae5hoocai7ai'
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'',
|
||||||
|
url(r'^test_plugin_one_url_Eexea4nie1fexaax3oX7/$',
|
||||||
|
RedirectView.as_view(pattern_name='core_version', permanent=False)))
|
0
tests/plugin_api/test_plugin_two/__init__.py
Normal file
0
tests/plugin_api/test_plugin_two/__init__.py
Normal file
7
tests/plugin_api/urls.py
Normal file
7
tests/plugin_api/urls.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from openslides import urls
|
||||||
|
|
||||||
|
reload(urls)
|
||||||
|
|
||||||
|
urlpatterns = urls.urlpatterns
|
@ -1,3 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
from openslides.urls import urlpatterns
|
from openslides.urls import urlpatterns
|
||||||
|
Loading…
Reference in New Issue
Block a user