-
Notifications
You must be signed in to change notification settings - Fork 28
esdc Third Party Apps
Your can create a esdc third party app the same way as Django apps are created. In this article we will go through differences and changes that you need to do in order to load your app automatically by esdc-ce.
esdc-ce uses Django settings to modify its behavior or to define constants. In your app you can create the same settings and merge them into esdc-ce settings automatically. Here is a brief description of settings related to third party applications:
-
THIRD_PARTY_APPS_ENABLED - global setting that can disable all third party apps at once. Constant is set to
True
by default. -
THIRD_PARTY_APPS - global setting that defines third party apps to be loaded in the system. Generated automatically from
core/external/apps
.
In your app, create a file called settings.py
, where you can specify settings that are used in your code to manipulate app functionality and define app constants. In order to be loaded by esdc-ce settings, file settings.py
has to be copied (or symlinked) to core/external/apps
directory and named after your app. Even if your app does not have any settings, an empty file with your app's name has to be created in core/external/apps
.
Sample settings.py file:
YOUR_APP_ENABLED = True
YOUR_APP_FUNCTIONALITY_SUBSET_ENABLED = False
YOUR_APP_OTHER_FUNCTIONALITY_SUBSET_ENABLED = False
YOUR_APP_SETTING = False
YOUR_APP_FUNCTIONALITY_SUBSET_URL = ''
YOUR_APP_FUNCTIONALITY_SUBSET_KEY = ''
OTHER_FUNCTIONALITY_SETTING = 'some constant used in app'
esdc-ce will search for dc_settings.py
in the root directory of your application. This file is optional, but if you decide to create it, it has to have certain structure, in order to work properly. Values from this file will be used to generate modules and settings in Datacenter > Settings. Values defined in core/external/apps
files will be automatically displayed here (or local_settings.py
values, if you have overridden default third party apps modules and settings values).
Module - a certain functionality of your app, that can be enabled or disabled. You should have at least one module setting (your app), so it can be disabled, but you can have more (e.g. to allow your app to connect to remote service). A module setting has always a boolean value, so it is either enabled or disabled. If you disable a module in your
local_settings.py
file, users will be able to see it, but nobody will be able to enable the module anywhere.
Setting - configuration variable used in your app (e.g. an email address). Settings can have different types, e.g. string, list, boolean, etc.
-
DEFAULT_DC_MODULES, DEFAULT_DC_SETTINGS - modules and settings that are used in default DC and all other DCs use this value, e. g. global value that can not be customized per DC. This constant is optional and doesn't have to be defined, but once it is, it has to be list of lists, where the inner lists contain a name of the module (string) and a serializer field object.
-
DC_MODULES, DC_SETTINGS - modules and settings that can be customized per DC. This constant is optional and doesn't have to be defined, but once it is, it has to be list of lists, where the inner lists contain a name of the setting (string) and a serializer field object.
-
SETTINGS_TEMPLATES - fields that will be generated according to settings defined in DEFAULT_DC_SETTINGS and DC_SETTINGS. This constant is optional and doesn't have to be defined, but once it is, it has to be dictionary. The key of the dictionary is the name of the setting (either default_dc or dc) and the value is a path to a template that will be rendered by the form. If a setting is not defined here the system will try to guess the type and render an appropriate input type.
-
SETTINGS_ICON - HTML font icon that will be rendered for the group of the settings in your app. This cpnstant is optional and doesn't have to be defined, but once it is it has to be string.
Sample dc_settings.py
file:
from django.utils.translation import ugettext_lazy as _
from api import serializers as s
DEFAULT_DC_MODULES = (
('YOUR_APP_ENABLED', s.BooleanField(label=_('Your app label (your_app_module)'))),
('YOUR_APP_FUNCTIONALITY_SUBSET_ENABLED', s.BooleanField(label=_('Your app cool feature (your_app_module)'), help_text=_('This cool feature allows extend app functionality in a certain way, and is either enabled for all DCs or None.'))),
)
DC_MODULES = (
('YOUR_APP_OTHER_FUNCTIONALITY_SUBSET_ENABLED', s.BooleanField(label=_('Your app other cool feature (your_app_module)'), help_text=_('This other feature allows extend app functionality in a certain way, but can be disabled per DC.'))),
)
DEFAULT_DC_SETTINGS = (
('YOUR_APP_SETTING', s.BooleanField(label='YOUR_APP_SETTING', help_text=_('Setting that changes, behavior of your app, for all DC.'))),
('YOUR_APP_FUNCTIONALITY_SUBSET_URL', s.CharField(label='YOUR_APP_FUNCTIONALITY_SUBSET_URL')),
('YOUR_APP_FUNCTIONALITY_SUBSET_KEY', s.CharField(label='YOUR_APP_FUNCTIONALITY_SUBSET_KEY')),
)
DC_SETTINGS = (
('OTHER_FUNCTIONALITY_SETTING', s.CharField(label='OTHER_FUNCTIONALITY_SETTING', help_text=_('Other feature setting customized per DC.'))),
)
SETTINGS_TEMPLATES = {
'YOUR_APP_SETTING': 'gui/table_form_field_checkbox.html',
'OTHER_FUNCTIONALITY_SETTING': 'gui/table_form_field_checkbox.html',
}
SETTINGS_ICON = 'icon-inbox'
We use Django signals in several places, in order to connect third party apps to esdc-ce. Check out the gui/signals.py
file in order to see where you can connect your app to esdc-ce. If you need a signal in other places, feel free to submit a merge request with new signal definition.
Most probably your app will need to generate links in the esdc-ce navigation. To do so, add a signal receiver somewhere, where Django can collect it. If you use utils.py for view helper functions, it is recommended to store it here. Sample receiver:
from django.utils.translation import ugettext as _
from django.dispatch import receiver
from gui.signals import navigation_initialized
YOUR_APP = {
'title': _('YOUR APP'),
'icon': 'inbox',
'url': 'standard-functionality',
'active_views': {'standard-functionality', 'other-functionality'},
# 'children': [] # Built on runtime
}
YOUR_APP_OTHER_FUNCTIONALITY = [
{
'title': _('OTHER FUNCTIONALITY'),
'icon': 'comments-alt',
'url': 'other-functionality'
},
]
YOUR_APP_STANDARD_FUNCTIONALITY = [
{
'title': _('STANDARD FUNCTIONALITY'),
'icon': 'folder-open',
'url': 'standard-functionality'
},
]
@receiver(navigation_initialized)
def generate_myapp_navigation(request, nav, **kwargs):
if request.dc.settings.DEFAULT_DC_MODULES:
user = request.user
request.dc.settings.OTHER_FUNCTIONALITY_SETTING:
YOUR_APP['children'] = YOUR_APP_STANDARD_FUNCTIONALITY + YOUR_APP_OTHER_FUNCTIONALITY
nav.append(YOUR_APP)
else:
YOUR_APP['children'] = YOUR_APP_STANDARD_FUNCTIONALITY
nav.append(YOUR_APP)
Your app has the ability to connect to the FAQ page just by creating a signal receiver.
from django.utils.translation import ugettext as _
from django.dispatch import receiver
from gui.signals import generate_faq_subsections
@receiver(generate_faq_subsections)
def faq_section(request, **kwargs):
"""
Signal receiver that returns template and its context, which will be used during FAQ page rendering.
"""
dc_settings = request.dc.settings
if dc_settings.DC_MODULES:
context = {}
context.update('some_stuff')
return 'your_app_module/your_app_module_faq.html', context
You also need to create a template that will be appended to the FAQ page. In this case your_app_module/your_app_module_faq.html
:
{% load i18n %}
<h3>Your app FAQ</h3>
<li>
<h4>{% trans "Some question?" %}</h4>
<p>
{% trans "And some answers..." %}
</p>
</li>
External apps can use JavaScript signals provided via the mini-signals library. Signals should be declared in gui/static/gui/js/signals.js
in the main project. External apps can easily add handlers to these signals and extend the functionality of GUI views.
esdc-ce supports asynchronous task execution. System will search for tasks.py
in the root directory of your application. This file is optional, but if you decide to create it, it has to have a certain structure, in order to work properly.
Sample tasks.py
file:
from que.tasks import cq, get_task_logger
from vms.models import DefaultDc
from your_app_module.models import Dbmodel
__all__ = ('check_something',)
logger = get_task_logger(__name__)
@cq.task(name='your_app_module.tasks.check_something')
def check_something():
"""
This is a task to check something.
"""
logger.info('Started')
if DefaultDc().settings.YOUR_APP_SETTING:
for something_to_check in Dbmodel.objects.filter(status=Dbmodel.STATUS):
something_to_check.updated_by_task = True
something_to_check.save()
logger.info('We have updated %s', something_to_check.name)
Homepage | User Guide | API Reference | Wiki