| 1 | # Copyright (c) 2010 by Yaco Sistemas |
|---|
| 2 | # |
|---|
| 3 | # This file is part of Merengue. |
|---|
| 4 | # |
|---|
| 5 | # Merengue is free software: you can redistribute it and/or modify |
|---|
| 6 | # it under the terms of the GNU Lesser General Public License as published by |
|---|
| 7 | # the Free Software Foundation, either version 3 of the License, or |
|---|
| 8 | # (at your option) any later version. |
|---|
| 9 | # |
|---|
| 10 | # Merengue is distributed in the hope that it will be useful, |
|---|
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | # GNU Lesser General Public License for more details. |
|---|
| 14 | # |
|---|
| 15 | # You should have received a copy of the GNU Lesser General Public License |
|---|
| 16 | # along with Merengue. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | from os import path |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | from django.conf import settings |
|---|
| 21 | from django.utils.translation import ugettext |
|---|
| 22 | |
|---|
| 23 | from south.signals import post_migrate |
|---|
| 24 | from transmeta import get_fallback_fieldname |
|---|
| 25 | |
|---|
| 26 | from merengue.urlresolvers import get_url_default_lang |
|---|
| 27 | from merengue.registry import register, have_registered_items |
|---|
| 28 | from merengue.registry.items import RegistrableItem |
|---|
| 29 | from merengue.registry.models import RegisteredItem |
|---|
| 30 | from merengue.utils import is_last_application, classproperty |
|---|
| 31 | |
|---|
| 32 | |
|---|
| 33 | class Plugin(RegistrableItem): |
|---|
| 34 | singleton = True |
|---|
| 35 | url_prefixes = () |
|---|
| 36 | active_by_default = False |
|---|
| 37 | |
|---|
| 38 | def get_url_prefixes(self): |
|---|
| 39 | prefixes = [] |
|---|
| 40 | for url_prefix, url in self.url_prefixes: |
|---|
| 41 | prefix = url_prefix |
|---|
| 42 | if isinstance(url_prefix, dict): |
|---|
| 43 | prefix = url_prefix.get(get_url_default_lang()) |
|---|
| 44 | prefixes.append((path.join(settings.BASE_URL[1:], prefix), url)) |
|---|
| 45 | |
|---|
| 46 | return prefixes |
|---|
| 47 | |
|---|
| 48 | @classmethod |
|---|
| 49 | def get_category(cls): |
|---|
| 50 | return 'plugin' |
|---|
| 51 | |
|---|
| 52 | @classproperty |
|---|
| 53 | @classmethod |
|---|
| 54 | def model(self): |
|---|
| 55 | from merengue.pluggable.models import RegisteredPlugin |
|---|
| 56 | return RegisteredPlugin |
|---|
| 57 | |
|---|
| 58 | def _get_registered_items(self, item_classes): |
|---|
| 59 | for item_class in item_classes: |
|---|
| 60 | reg_item = RegisteredItem.objects.get_by_item_class(item_class) |
|---|
| 61 | yield reg_item.get_registry_item() |
|---|
| 62 | |
|---|
| 63 | def get_actions(self): |
|---|
| 64 | return [] # to override in plugins |
|---|
| 65 | |
|---|
| 66 | def get_actions_items(self): |
|---|
| 67 | return [] # to override in plugins |
|---|
| 68 | |
|---|
| 69 | def get_blocks(self): |
|---|
| 70 | return [] # to override in plugins |
|---|
| 71 | |
|---|
| 72 | def get_middlewares(self): |
|---|
| 73 | return [] # to override in plugins |
|---|
| 74 | |
|---|
| 75 | def get_viewlets(self): |
|---|
| 76 | return [] # to override in plugins |
|---|
| 77 | |
|---|
| 78 | def post_actions(self): |
|---|
| 79 | pass |
|---|
| 80 | |
|---|
| 81 | def models(self): |
|---|
| 82 | return [] # to override in plugins |
|---|
| 83 | |
|---|
| 84 | def section_models(self): |
|---|
| 85 | return [] # to override in plugins |
|---|
| 86 | |
|---|
| 87 | def section_register_hook(self, site_related, model): |
|---|
| 88 | pass |
|---|
| 89 | |
|---|
| 90 | def get_model_admins(self): |
|---|
| 91 | return [] # to override in plugins |
|---|
| 92 | |
|---|
| 93 | def get_perms(self): |
|---|
| 94 | return [] # to override in plugins |
|---|
| 95 | |
|---|
| 96 | def get_toolbar_panels(self): |
|---|
| 97 | return [] # to override in plugins |
|---|
| 98 | |
|---|
| 99 | def get_section_prefixes(self): |
|---|
| 100 | return [] # to override in plugins |
|---|
| 101 | |
|---|
| 102 | def post_install(self): |
|---|
| 103 | pass |
|---|
| 104 | |
|---|
| 105 | def get_notifications(self): |
|---|
| 106 | return [] # to override in plugins |
|---|
| 107 | |
|---|
| 108 | def get_blocks_items(self): |
|---|
| 109 | return self._get_registered_items(self.get_blocks()) |
|---|
| 110 | |
|---|
| 111 | def get_toolbar_panels_items(self): |
|---|
| 112 | return self._get_registered_items(self.get_toolbar_panels()) |
|---|
| 113 | |
|---|
| 114 | def get_viewlets_items(self): |
|---|
| 115 | return self._get_registered_items(self.get_viewlets()) |
|---|
| 116 | |
|---|
| 117 | |
|---|
| 118 | def register_plugin(plugin_dir): |
|---|
| 119 | from merengue.pluggable.models import RegisteredPlugin |
|---|
| 120 | from merengue.pluggable.utils import get_plugin_config, validate_plugin |
|---|
| 121 | plugin_config = get_plugin_config(plugin_dir) |
|---|
| 122 | if plugin_config: |
|---|
| 123 | validate_plugin(plugin_config) |
|---|
| 124 | try: |
|---|
| 125 | reg_plugin = RegisteredPlugin.objects.get_by_item_class(plugin_config) |
|---|
| 126 | except RegisteredPlugin.DoesNotExist: |
|---|
| 127 | reg_plugin = register(plugin_config) |
|---|
| 128 | plugin = reg_plugin.get_registry_item() |
|---|
| 129 | reg_plugin.name = getattr(plugin, 'name') |
|---|
| 130 | reg_plugin.directory_name = plugin_dir |
|---|
| 131 | reg_plugin.description = getattr(plugin, 'description', '') |
|---|
| 132 | reg_plugin.version = getattr(plugin, 'version', '') |
|---|
| 133 | reg_plugin.required_apps = getattr(plugin, 'required_apps', |
|---|
| 134 | None) |
|---|
| 135 | reg_plugin.required_plugins = getattr(plugin, |
|---|
| 136 | 'required_plugins', |
|---|
| 137 | None) |
|---|
| 138 | reg_plugin.meta_info = {} |
|---|
| 139 | if hasattr(plugin, 'screenshot'): |
|---|
| 140 | reg_plugin.meta_info['screenshot'] = plugin.screenshot |
|---|
| 141 | reg_plugin.meta_info['actions'] = [] |
|---|
| 142 | for action in plugin.get_actions(): |
|---|
| 143 | reg_plugin.meta_info['actions'].append({'name': unicode(action.name), 'help_text': unicode(action.help_text)}) |
|---|
| 144 | reg_plugin.meta_info['blocks'] = [] |
|---|
| 145 | for block in plugin.get_blocks(): |
|---|
| 146 | reg_plugin.meta_info['blocks'].append({'name': unicode(block.name), 'help_text': unicode(block.help_text)}) |
|---|
| 147 | if plugin.get_model_admins(): |
|---|
| 148 | reg_plugin.meta_info['has_own_admin'] = True |
|---|
| 149 | else: |
|---|
| 150 | reg_plugin.meta_info['has_own_admin'] = False |
|---|
| 151 | reg_plugin.meta_info['middlewares'] = [] |
|---|
| 152 | for middleware in plugin.get_middlewares(): |
|---|
| 153 | reg_plugin.meta_info['middlewares'].append(middleware) |
|---|
| 154 | reg_plugin.meta_info['section_models'] = [] |
|---|
| 155 | for model, admin in plugin.section_models(): |
|---|
| 156 | reg_plugin.meta_info['section_models'].append({'name': unicode(model._meta.verbose_name)}) |
|---|
| 157 | reg_plugin.meta_info['viewlets'] = [] |
|---|
| 158 | for viewlet in plugin.get_viewlets(): |
|---|
| 159 | reg_plugin.meta_info['viewlets'].append({'name': unicode(viewlet.name), 'help_text': unicode(viewlet.help_text)}) |
|---|
| 160 | |
|---|
| 161 | if "notification" in settings.INSTALLED_APPS: |
|---|
| 162 | from notification.models import create_notice_type |
|---|
| 163 | for notification in plugin.get_notifications(): |
|---|
| 164 | label, display, description = notification |
|---|
| 165 | create_notice_type(label, display, description) |
|---|
| 166 | |
|---|
| 167 | reg_plugin.save() |
|---|
| 168 | return reg_plugin |
|---|
| 169 | return None |
|---|
| 170 | |
|---|
| 171 | |
|---|
| 172 | def enable_active_plugins(): |
|---|
| 173 | from merengue.pluggable.models import RegisteredPlugin |
|---|
| 174 | from merengue.pluggable.utils import enable_plugin, get_plugin_module_name, reload_models_cache |
|---|
| 175 | for plugin_registered in RegisteredPlugin.objects.actives(): |
|---|
| 176 | enable_plugin(get_plugin_module_name(plugin_registered.directory_name)) |
|---|
| 177 | reload_models_cache() |
|---|
| 178 | |
|---|
| 179 | |
|---|
| 180 | def register_all_plugins(verbose=False): |
|---|
| 181 | from merengue.pluggable.models import RegisteredPlugin |
|---|
| 182 | from merengue.pluggable.utils import (get_plugin_directories, get_plugin_config, |
|---|
| 183 | reload_models_cache, remove_from_installed_apps, |
|---|
| 184 | clear_plugin_module_cache, get_plugin_module_name) |
|---|
| 185 | from merengue.pluggable.checker import mark_broken_plugin |
|---|
| 186 | try: |
|---|
| 187 | for plugin_dir in get_plugin_directories(): |
|---|
| 188 | try: |
|---|
| 189 | if verbose: |
|---|
| 190 | plugin_config = get_plugin_config(plugin_dir) |
|---|
| 191 | if plugin_config: |
|---|
| 192 | if not have_registered_items(plugin_config): |
|---|
| 193 | print 'Registering new plugin %s...' % plugin_dir |
|---|
| 194 | else: |
|---|
| 195 | print 'Re-registering plugin %s...' % plugin_dir |
|---|
| 196 | else: |
|---|
| 197 | print 'Error walking to plugin %s.' % plugin_dir |
|---|
| 198 | register_plugin(plugin_dir) |
|---|
| 199 | except: |
|---|
| 200 | mark_broken_plugin(plugin_dir) |
|---|
| 201 | print 'Error registering %s plugin... go to next plugin.' % plugin_dir |
|---|
| 202 | finally: |
|---|
| 203 | for plugin in RegisteredPlugin.objects.inactives(): |
|---|
| 204 | clear_plugin_module_cache(get_plugin_module_name(plugin.directory_name)) |
|---|
| 205 | remove_from_installed_apps(plugin.directory_name) |
|---|
| 206 | reload_models_cache() |
|---|
| 207 | |
|---|
| 208 | |
|---|
| 209 | def active_default_plugins(*args, **kwargs): |
|---|
| 210 | """ active default plugins and creates the portal menu in each language """ |
|---|
| 211 | # Only want to run this signal after all application was migrated, but |
|---|
| 212 | # south have not a "post all migrations" signal. |
|---|
| 213 | # The workaround is "collab" have to be the last application migrated |
|---|
| 214 | if is_last_application(kwargs['app']): |
|---|
| 215 | # register required plugins |
|---|
| 216 | for plugin_dir in settings.REQUIRED_PLUGINS: |
|---|
| 217 | active_plugin_with_deps(plugin_dir) |
|---|
| 218 | # populate menu |
|---|
| 219 | from merengue.section.models import Menu |
|---|
| 220 | name_attr = get_fallback_fieldname('name') |
|---|
| 221 | attrs = {name_attr: 'Portal menu', 'slug': settings.MENU_PORTAL_SLUG} |
|---|
| 222 | try: |
|---|
| 223 | portal_menu = Menu.objects.get(slug=settings.MENU_PORTAL_SLUG) |
|---|
| 224 | except Menu.DoesNotExist: |
|---|
| 225 | # creating portal menu if does not exist |
|---|
| 226 | portal_menu = Menu.objects.create(**attrs) |
|---|
| 227 | for lang_code, lang_text in settings.LANGUAGES: |
|---|
| 228 | setattr(portal_menu, 'name_%s' % lang_code, ugettext('portal menu')) |
|---|
| 229 | portal_menu.save() |
|---|
| 230 | |
|---|
| 231 | |
|---|
| 232 | def active_plugin_with_deps(plugin_dir): |
|---|
| 233 | """ active plugins with its dependences """ |
|---|
| 234 | from merengue.pluggable.utils import install_plugin |
|---|
| 235 | registered_plugin = register_plugin(plugin_dir) |
|---|
| 236 | plugin = registered_plugin.get_registry_item() |
|---|
| 237 | for dep in getattr(plugin, 'required_plugins', []): |
|---|
| 238 | active_plugin_with_deps(dep) |
|---|
| 239 | registered_plugin.installed = True |
|---|
| 240 | registered_plugin.active = True |
|---|
| 241 | registered_plugin.save() |
|---|
| 242 | install_plugin(registered_plugin) |
|---|
| 243 | |
|---|
| 244 | |
|---|
| 245 | post_migrate.connect(active_default_plugins) |
|---|