def test_app_links_hide(self): """Test visibility of app links with timeline hidden""" url = reverse( 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} ) expected = [ (self.superuser, len(get_active_plugins())), (self.user_owner, len(get_active_plugins()) - 1), ] self.assert_element_count(expected, url, 'sodar-pr-nav-app-plugin')
def get_all_settings(cls, project=None, user=None, post_safe=False): """ Return all setting values. If the value is not found, return the default. :param project: Project object (can be None) :param user: User object (can be None) :param post_safe: Whether POST safe values should be returned (bool) :return: Dict :raise: ValueError if neither project nor user are set """ if not project and not user: raise ValueError('Project and user are both unset') ret = {} app_plugins = get_active_plugins() for plugin in app_plugins: p_settings = cls.get_setting_defs(APP_SETTING_SCOPE_PROJECT, plugin=plugin) for s_key in p_settings: ret['settings.{}.{}'.format(plugin.name, s_key)] = cls.get_app_setting( plugin.name, s_key, project, user, post_safe) return ret
def get_all_settings(cls, project=None, user=None): """ Return all setting values. If the value is not found, return the default. :param project: Project object (can be None) :param user: User object (can be None) :return: Dict :raise: ValueError if neither project nor user are set """ cls._check_project_and_user(project, user) ret = {} app_plugins = get_active_plugins() for plugin in app_plugins: p_settings = cls.get_setting_defs(plugin, APP_SETTING_SCOPE_PROJECT) for s_key in p_settings: ret['settings.{}.{}'.format(plugin.name, s_key)] = cls.get_app_setting( plugin.name, s_key, project, user) return ret
def get_site_app_messages(user): """Get messages from site apps""" plugins = get_active_plugins('site_app') ret = [] for p in plugins: ret += p.get_messages(user) return ret
def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) # App plugins context['project_plugins'] = get_active_plugins('project_app') context['site_plugins'] = get_active_plugins('site_app') context['backend_plugins'] = get_active_plugins('backend') # Project statistics context['project_count'] = Project.objects.filter( type=PROJECT_TYPE_PROJECT ).count() context['category_count'] = Project.objects.filter( type=PROJECT_TYPE_CATEGORY ).count() # User statistics context['user_total_count'] = User.objects.all().count() context['user_ldap_count'] = User.objects.exclude( groups__name__in=['', SYSTEM_USER_GROUP] ).count() context['user_local_count'] = User.objects.filter( groups__name__in=['', SYSTEM_USER_GROUP] ).count() context['user_admin_count'] = User.objects.filter( is_superuser=True ).count() # Basic site info context['site_title'] = settings.SITE_TITLE context['site_subtitle'] = settings.SITE_SUBTITLE context['site_instance_title'] = settings.SITE_INSTANCE_TITLE # Remote site info context['site_mode'] = settings.PROJECTROLES_SITE_MODE if settings.PROJECTROLES_SITE_MODE == SITE_MODE_SOURCE: context['site_target_count'] = RemoteSite.objects.filter( mode=SITE_MODE_TARGET ).count() return context
def test_include_none_value(self): """Test get_backend_include none attribute check""" # TODO: Replace with get_app_plugin once implemented for backend plugins backend_plugin = get_active_plugins('backend')[0] type(backend_plugin).javascript_url = None type(backend_plugin).css_url = None self.assertEqual(c_tags.get_backend_include(backend_plugin.name, 'js'), '') self.assertEqual( c_tags.get_backend_include(backend_plugin.name, 'css'), '')
def handle(self, *args, **options): if 'sodar_cache' not in settings.ENABLED_BACKEND_PLUGINS: logger.error( 'SodarCache backend not enabled in settings, cancelled!' ) return cache_backend = get_backend_api('sodar_cache') if not cache_backend: logger.error('SodarCache backend plugin not available, cancelled!') return update_kwargs = {} if 'project' in options and options['project']: try: project = Project.objects.get(sodar_uuid=options['project']) update_kwargs['project'] = project logger.info( 'Limiting sync to project "{}" ({})"'.format( project.title, project.sodar_uuid ) ) except Project.DoesNotExist: logger.error( 'Project not found with UUID={}'.format(options['project']) ) return except ValidationError: logger.error('Not a valid UUID: {}'.format(options['project'])) return if not update_kwargs: logger.info('Synchronizing cache for all projects') plugins = get_active_plugins(plugin_type='project_app') for plugin in plugins: try: plugin.update_cache(**update_kwargs) except Exception as ex: logger.error( 'Update failed for plugin "{}": "{}"'.format( plugin.name, ex ) ) logger.info('Cache synchronization OK')
def setUp(self): super().setUp() self.sidebar_ids = [ 'sodar-pr-nav-project-detail', 'sodar-pr-nav-project-roles', 'sodar-pr-nav-project-update', ] # Add app plugin navs for p in get_active_plugins(): self.sidebar_ids.append('sodar-pr-nav-app-plugin-{}'.format(p.name))
def update_cache(cls, name=None, project=None, user=None): """ Update items by certain name within a project by calling implemented functions in project app plugins. :param name: Item name to limit update to (string, optional) :param project: Project object to limit update to (optional) :param user: User object to denote user triggering the update (optional) """ plugins = get_active_plugins(plugin_type='project_app') for plugin in plugins: plugin.update_cache(name, project, user)
def test_include_invalid_url(self): """Test get_backend_include file existence check""" # TODO: Replace with get_app_plugin once implemented for backend plugins backend_plugin = get_active_plugins('backend')[0] type(backend_plugin ).javascript_url = 'example_backend_app/js/NOT_EXISTING_JS.js' type(backend_plugin ).css_url = 'example_backend_app/css/NOT_EXISTING_CSS.css' self.assertEqual(c_tags.get_backend_include(backend_plugin.name, 'js'), '') self.assertEqual( c_tags.get_backend_include(backend_plugin.name, 'css'), '')
def _get_user_settings(self): for plugin in get_active_plugins(): p_settings = app_settings.get_setting_defs( plugin, APP_SETTING_SCOPE_USER, user_modifiable=True ) for s_key, s_val in p_settings.items(): yield { 'label': s_val.get('label') or '{}.{}'.format(plugin.name, s_key), 'value': app_settings.get_app_setting( plugin.name, s_key, user=self.request.user ), 'description': s_val.get('description'), }
def _sync_apps(self): """Run taskflow synchronization methods in project app plugins""" plugins = get_active_plugins(plugin_type='project_app') for plugin in plugins: sync_data = plugin.get_taskflow_sync_data() logger.info('Synchronizing app "{}"...'.format(plugin.name)) if sync_data: self._submit_sync(plugin.name, sync_data, raise_exception=False) else: logger.info('Nothing to synchronize.')
def __init__(self, *args, **kwargs): #: The user to display the settings for. self.user = kwargs.pop('current_user') super().__init__(*args, **kwargs) # Add settings fields self.app_plugins = get_active_plugins() for plugin in self.app_plugins: p_settings = app_settings.get_setting_defs(plugin, APP_SETTING_SCOPE_USER, user_modifiable=True) for s_key, s_val in p_settings.items(): s_field = 'settings.{}.{}'.format(plugin.name, s_key) field_kwarg = { 'required': False, 'label': s_val.get('label') or '{}.{}'.format(plugin.name, s_key), 'help_text': s_val.get('description'), } widget_attrs = { 'placeholder': s_val.get('placeholder') or None } if s_val['type'] == 'STRING': self.fields[s_field] = forms.CharField( max_length=APP_SETTING_VAL_MAXLENGTH, widget=forms.TextInput(attrs=widget_attrs), **field_kwarg, ) elif s_val['type'] == 'INTEGER': self.fields[s_field] = forms.IntegerField( widget=forms.TextInput(attrs=widget_attrs), **field_kwarg, ) elif s_val['type'] == 'BOOLEAN': self.fields[s_field] = forms.BooleanField(**field_kwarg) # Set initial value self.initial[s_field] = app_settings.get_app_setting( app_name=plugin.name, setting_name=s_key, user=self.user)
def get_project_list_columns(): """Return custom project list columns as a sorted list""" cols = [] i = 0 for app_plugin in [ ap for ap in get_active_plugins(plugin_type='project_app') if ap.project_list_columns ]: for k, v in app_plugin.project_list_columns.items(): v['app_plugin'] = app_plugin v['key'] = k v['ordering'] = v.get('ordering') or i cols.append(v) i += 1 return sorted(cols, key=lambda x: x['ordering'])
def test_get_backend_include(self): """Test get_backend_include""" # TODO: Replace with get_app_plugin once implemented for backend plugins backend_plugin = get_active_plugins('backend')[0] type(backend_plugin ).javascript_url = 'example_backend_app/js/greeting.js' type(backend_plugin).css_url = 'example_backend_app/css/greeting.css' self.assertEqual( c_tags.get_backend_include(backend_plugin.name, 'js'), '<script type="text/javascript" ' 'src="/static/example_backend_app/js/greeting.js"></script>', ) self.assertEqual( c_tags.get_backend_include(backend_plugin.name, 'css'), '<link rel="stylesheet" type="text/css" ' 'href="/static/example_backend_app/css/greeting.css"/>', )
def get_all_defaults(cls, scope): """ Get all default settings for a scope. :param scope: :return: """ cls._check_scope(scope) ret = {} app_plugins = get_active_plugins() for plugin in app_plugins: p_settings = cls.get_setting_defs(plugin, scope) for s_key in p_settings: ret['settings.{}.{}'.format(plugin.name, s_key)] = cls.get_default_setting( plugin.name, s_key) return ret
def get_all_defaults(cls, scope, post_safe=False): """ Get all default settings for a scope. :param scope: Setting scope (PROJECT, USER or PROJECT_USER) :param post_safe: Whether POST safe values should be returned (bool) :return: Dict """ cls._check_scope(scope) ret = {} app_plugins = get_active_plugins() for plugin in app_plugins: p_settings = cls.get_setting_defs(scope, plugin=plugin) for s_key in p_settings: ret['settings.{}.{}'.format(plugin.name, s_key)] = cls.get_default_setting( plugin.name, s_key, post_safe) return ret
def get_site_apps(): """Get active site apps""" return get_active_plugins('site_app')
def setUp(self): super().setUp() self.plugin_count = len(get_active_plugins())
def test_get_project_column_count(self): """Test get_project_column_count()""" app_plugins = get_active_plugins() self.assertEqual(tags.get_project_column_count(app_plugins), 4) self.assertEqual(tags.get_project_column_count([]), 2)
def handle(self, *args, **options): if 'taskflow' not in settings.ENABLED_BACKEND_PLUGINS: print_msg('Taskflow not enabled in settings, cancelled!') raise CommandError taskflow = get_backend_api('taskflow') if not taskflow: print_msg('Taskflow backend plugin not available, cancelled!') raise CommandError def submit_sync(app_name, sync_data, raise_exception=False): """Submit flows found in an app's sync_data structure""" for item in sync_data: project = Project.objects.get(sodar_uuid=item['project_uuid']) print_msg('Syncing flow "{}" by {} for "{}" ({})'.format( item['flow_name'], app_name, project.title, project.sodar_uuid, )) try: taskflow.submit( project_uuid=item['project_uuid'], flow_name=item['flow_name'], flow_data=item['flow_data'], targets=TARGETS, ) except taskflow.FlowSubmitException as ex: print_msg('Exception raised by flow!') print(str(ex)) # If we don't want to continue on failure if raise_exception: raise ex print_msg('Synchronizing project data with taskflow...') print_msg('Target(s) = ' + ', '.join([t for t in TARGETS])) # Only sync PROJECT type projects as we (currently) don't have any # use for CATEGORY projects in taskflow projects = Project.objects.filter( type=PROJECT_TYPE_PROJECT).order_by('pk') #################### # Projectroles sync #################### # NOTE: For projectroles, this is done here as projects must be created # or we can not continue with sync.. Also, removed projects are # NOT deleted automatically (they shouldn't be deleted anyway). # We first set up the projects and exit if syncing them fails. project_sync_data = [] role_sync_data = [] for project in projects: owner_as = project.get_owner() # Create project project_sync_data.append({ 'project_uuid': str(project.sodar_uuid), 'project_title': project.title, 'flow_name': 'project_create', 'flow_data': { 'project_title': project.title, 'project_description': project.description, 'parent_uuid': str(project.parent.sodar_uuid) if project.parent else 0, 'owner_username': owner_as.user.username, 'owner_uuid': str(owner_as.user.sodar_uuid), 'owner_role_pk': owner_as.role.pk, }, }) # Set up roles role_sync_data.append({ 'project_uuid': str(project.sodar_uuid), 'project_title': project.title, 'flow_name': 'role_sync_delete_all', 'flow_data': { 'owner_username': owner_as.user.username }, }) for role_as in project.roles.exclude(role=Role.objects.get( name=SODAR_CONSTANTS['PROJECT_ROLE_OWNER'])): role_sync_data.append({ 'project_uuid': str(project.sodar_uuid), 'project_title': project.title, 'flow_name': 'role_update', 'flow_data': { 'username': role_as.user.username, 'user_uuid': str(role_as.user.sodar_uuid), 'role_pk': str(role_as.role.pk), }, }) try: submit_sync('projectroles', project_sync_data, raise_exception=True) # In case of a failure here we can't continue with the rest of the sync except taskflow.FlowSubmitException: print_msg('Project creation failed! Unable to continue, exiting..') return submit_sync('projectroles', role_sync_data, raise_exception=False) ########### # App sync ########### plugins = get_active_plugins(plugin_type='project_app') for plugin in plugins: sync_data = plugin.get_taskflow_sync_data() print_msg('Synchronizing app "{}"...'.format(plugin.name)) if sync_data: submit_sync(plugin.name, sync_data, raise_exception=False) else: print_msg('Nothing to synchronize.') print_msg('Project data synchronized.')
def __init__(self, *args, **kwargs): #: The user to display the settings for. self.user = kwargs.pop('current_user') super().__init__(*args, **kwargs) # Add settings fields self.app_plugins = get_active_plugins(plugin_type='project_app') self.user_plugins = get_active_plugins(plugin_type='site_app') self.app_plugins = self.app_plugins + self.user_plugins for plugin in self.app_plugins: p_settings = app_settings.get_setting_defs(APP_SETTING_SCOPE_USER, plugin=plugin, user_modifiable=True) for s_key, s_val in p_settings.items(): s_field = 'settings.{}.{}'.format(plugin.name, s_key) s_widget_attrs = s_val.get('widget_attrs') or {} s_widget_attrs['placeholder'] = s_val.get('placeholder') setting_kwargs = { 'required': False, 'label': s_val.get('label') or '{}.{}'.format(plugin.name, s_key), 'help_text': s_val.get('description'), } if s_val['type'] == 'STRING': self.fields[s_field] = forms.CharField( max_length=APP_SETTING_VAL_MAXLENGTH, **setting_kwargs) elif s_val['type'] == 'INTEGER': self.fields[s_field] = forms.IntegerField(**setting_kwargs) elif s_val['type'] == 'BOOLEAN': self.fields[s_field] = forms.BooleanField(**setting_kwargs) elif s_val['type'] == 'JSON': # NOTE: Attrs MUST be supplied here (#404) if 'class' in s_widget_attrs: s_widget_attrs['class'] += ' sodar-json-input' else: s_widget_attrs['class'] = 'sodar-json-input' self.fields[s_field] = forms.CharField( widget=forms.Textarea(attrs=s_widget_attrs), **setting_kwargs, ) # Modify initial value and attributes if s_val['type'] != 'JSON': # Add optional attributes from plugin (#404) # NOTE: Experimental! Use at your own risk! self.fields[s_field].widget.attrs.update(s_widget_attrs) self.initial[s_field] = app_settings.get_app_setting( app_name=plugin.name, setting_name=s_key, user=self.user) else: self.initial[s_field] = json.dumps( app_settings.get_app_setting( app_name=plugin.name, setting_name=s_key, user=self.user, ))
def _init_app_settings(self): # Set up setting query kwargs self.p_kwargs = ({ 'user_modifiable': True } if not self.current_user.is_superuser else {}) self.app_settings = AppSettingAPI() self.app_plugins = sorted(get_active_plugins(), key=lambda x: x.name) for plugin in self.app_plugins: # Show non-modifiable settings to superusers p_settings = self.app_settings.get_setting_defs( APP_SETTING_SCOPE_PROJECT, plugin=plugin, **self.p_kwargs) for s_key, s_val in p_settings.items(): s_field = 'settings.{}.{}'.format(plugin.name, s_key) s_widget_attrs = s_val.get('widget_attrs') or {} setting_kwargs = { 'required': False, 'label': s_val.get('label') or '{}.{}'.format(plugin.name, s_key), 'help_text': s_val['description'], } if s_val['type'] == 'JSON': # NOTE: Attrs MUST be supplied here (#404) if 'class' in s_widget_attrs: s_widget_attrs['class'] += ' sodar-json-input' else: s_widget_attrs['class'] = 'sodar-json-input' self.fields[s_field] = forms.CharField( widget=forms.Textarea(attrs=s_widget_attrs), **setting_kwargs) if self.instance.pk: self.initial[s_field] = json.dumps( self.app_settings.get_app_setting( app_name=plugin.name, setting_name=s_key, project=self.instance, )) else: self.initial[s_field] = json.dumps( self.app_settings.get_default_setting( app_name=plugin.name, setting_name=s_key)) else: if s_val['type'] == 'STRING': self.fields[s_field] = forms.CharField( max_length=APP_SETTING_VAL_MAXLENGTH, **setting_kwargs) elif s_val['type'] == 'INTEGER': self.fields[s_field] = forms.IntegerField( **setting_kwargs) elif s_val['type'] == 'BOOLEAN': self.fields[s_field] = forms.BooleanField( **setting_kwargs) # Add optional attributes from plugin (#404) # NOTE: Experimental! Use at your own risk! self.fields[s_field].widget.attrs.update(s_widget_attrs) # Set initial value if self.instance.pk: self.initial[ s_field] = self.app_settings.get_app_setting( app_name=plugin.name, setting_name=s_key, project=self.instance, ) else: self.initial[ s_field] = self.app_settings.get_default_setting( app_name=plugin.name, setting_name=s_key) # Add hidden note if s_val.get('user_modifiable') is False: self.fields[s_field].label += ' [HIDDEN]' self.fields[s_field].help_text += ' [HIDDEN FROM USERS]'
def get_backend_plugins(): """Get active backend plugins""" return get_active_plugins('backend')