Skip to content

esdc Third Party Apps

Daniel Kontšek edited this page Nov 13, 2016 · 8 revisions

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 settings

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.

App settings

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'

Modules and settings in esdc-ce API/GUI

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'

Signals

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.

Navigation

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)

FAQ page

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>

JavaScript

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.

Tasks

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)
Clone this wiki locally