def runTest(self): """ Tests the PluginChannel SQLObject """ Channel.deleteMany(None) fake_plugin = Plugin.selectBy(name='fake_plugin').getOne() plugin_channel = PluginChannel(name='MyPluginChannel', plugin=fake_plugin, subscription_right='public') user = User(fullname='User', email='test@localhost') user2 = User(fullname='User2', email='test2@localhost') assert plugin_channel.get_type_name() == 'Plugin fake_plugin' # Test user permissions def assert_no_permission(c, u): assert c.get_channel_permissions_of( u) == UserPermissions.no_permission assert u not in c.get_admins() and u not in c.get_contribs() def has_contrib(u, check_inlist=True): return plugin_channel.has_contrib(u) and ( not check_inlist or u in plugin_channel.get_contribs()) def has_admin(u): return plugin_channel.has_admin( u) and u in plugin_channel.get_admins() assert_no_permission(plugin_channel, user) assert_no_permission(plugin_channel, user2) plugin_channel.give_permission_to_user( user, UserPermissions.channel_contributor) role = Role.selectBy(user=user, channel=plugin_channel).getOne() assert has_contrib(user) assert not has_admin(user) assert not has_contrib(user2) assert not has_admin(user2) assert role.permission_level == UserPermissions.channel_contributor == plugin_channel.get_channel_permissions_of( user) assert json.loads(plugin_channel.get_users_as_json()) == { str(user.id): UserPermissions.channel_contributor.value } plugin_channel.give_permission_to_user( user, UserPermissions.channel_administrator) assert has_contrib(user, check_inlist=False) assert has_admin(user) assert not has_contrib(user2) assert not has_admin(user2) assert role.permission_level == UserPermissions.channel_administrator == plugin_channel.get_channel_permissions_of( user) assert json.loads(plugin_channel.get_users_as_json()) == { str(user.id): UserPermissions.channel_administrator.value } assert json.loads(PluginChannel.get_channels_users_as_json([plugin_channel])) == \ {str(plugin_channel.id): {str(user.id): UserPermissions.channel_administrator.value}} plugin_channel.remove_permission_to_user(user) plugin_channel.give_permission_to_user( user2, UserPermissions.channel_administrator) assert not has_contrib(user) assert not has_admin(user) assert has_contrib(user2, check_inlist=False) assert has_admin(user2) plugin_channel.remove_permission_to_user(user2) assert not has_contrib(user2) assert not has_admin(user2) # Test plugin config parameters assert plugin_channel.get_config_param( 'string_param') == 'default string' assert plugin_channel.get_config_param('int_param') == 1 assert plugin_channel.get_config_param('float_param') == float('-inf') assert plugin_channel.get_config_param('boolean_param') is True assert plugin_channel.get_config_param('template_param') is None with pytest.raises(KeyError): assert plugin_channel.get_config_param( 'this_param_does_not_exists') def assert_value_is_set(param, value): plugin_channel.plugin_config[param] = value plugin_channel.plugin_config = plugin_channel.plugin_config # Force SQLObject update assert plugin_channel.get_config_param(param) == value assert_value_is_set('string_param', 'Hello, world!') assert_value_is_set('int_param', 42) assert_value_is_set('float_param', 42.0) assert_value_is_set('boolean_param', False) assert_value_is_set('template_param', 'fake-template') # Test parameters access rights ppar = PluginParamAccessRights.selectBy(plugin=fake_plugin, name='int_param').getOne() ppar.channel_contributor_read = False ppar.channel_contributor_write = False ppar.channel_administrator_read = True ppar.channel_administrator_write = False ppar.administrator_read = True ppar.administrator_write = True user.super_admin = True assert plugin_channel.has_visible_params_for(user) for param in [ 'string_param', 'int_param', 'float_param', 'boolean_param', 'template_param' ]: assert plugin_channel.get_access_rights_for(param, user) == (True, True) user.super_admin = False assert not plugin_channel.has_visible_params_for(user) plugin_channel.give_permission_to_user( user, UserPermissions.channel_contributor) assert not plugin_channel.has_visible_params_for(user) assert plugin_channel.get_access_rights_for('int_param', user) == (False, False) plugin_channel.give_permission_to_user( user, UserPermissions.channel_administrator) assert plugin_channel.has_visible_params_for(user) assert plugin_channel.get_access_rights_for('int_param', user) == (True, False) user.admin = True assert plugin_channel.has_visible_params_for(user) assert plugin_channel.get_access_rights_for('int_param', user) == (True, True) plugin_channel.remove_permission_to_user(user) user.admin = False assert not plugin_channel.has_visible_params_for(user) assert plugin_channel.get_access_rights_for('int_param', user) == (False, False) # Test miscellaneous parameters assert plugin_channel.cache_activated is True plugin_channel.plugin.cache_activated_default = False assert plugin_channel.cache_activated is False plugin_channel.cache_activated = True assert plugin_channel.cache_activated is True assert plugin_channel.cache_validity is 60 plugin_channel.plugin.cache_validity_default = 120 assert plugin_channel.cache_validity is 120 plugin_channel.cache_validity = 42 assert plugin_channel.cache_validity is 42 assert plugin_channel.keep_noncomplying_capsules is False plugin_channel.plugin.keep_noncomplying_capsules_default = True assert plugin_channel.keep_noncomplying_capsules is True plugin_channel.keep_noncomplying_capsules = False assert plugin_channel.keep_noncomplying_capsules is False # Test flatten() plugin_channel.enabled = False assert plugin_channel.flatten() == [] assert plugin_channel.flatten(keep_disabled_channels=True) == [ plugin_channel ] plugin_channel.enabled = True assert plugin_channel.flatten() == [plugin_channel]
def POST(self): """ Handles channel creation, editing, deletion, configuration and user permissions. """ form = web.input() current_user = User.get(self.session['user']['id']) channel = None try: if form.action.startswith('create') or form.action.startswith( 'edit'): # Prepare creation or edition of channels/bundles name = form.name.strip() description = form.description if form.description and form.description.strip( ) else None enabled = form.get('enabled') == 'on' if form.subscription_right not in [ 'public', 'restricted', 'private' ]: raise ImmediateFeedback(form.action, 'invalid_subscription_right') if len(name) < 3: raise ImmediateFeedback(form.action, 'invalid_name') if form.action.startswith('create'): if UserPermissions.administrator not in current_user.highest_permission_level: logger.warning( 'user %s tried to create a channel without being admin', current_user.log_name) raise web.forbidden() try: if form.action == 'create-channel': try: plugin_id = int(form.plugin) except ValueError: raise ImmediateFeedback(form.action, 'invalid_plugin') p = Plugin.get(plugin_id) channel = PluginChannel( name=name, plugin=p, subscription_right=form.subscription_right, description=description, enabled=enabled) if p.webapp: self.plugin_manager.add_mapping(self.app, channel) elif form.action == 'create-bundle': channel = ChannelBundle( name=name, description=description, subscription_right=form.subscription_right, enabled=enabled) else: raise web.badrequest() except SQLObjectNotFound: raise ImmediateFeedback(form.action, 'invalid_plugin') except DuplicateEntryError: raise ImmediateFeedback(form.action, 'name_already_exists') logger.info('channel ' + channel.name + ' created by ' + current_user.log_name) elif form.action.startswith('edit'): if UserPermissions.administrator not in current_user.highest_permission_level: raise web.forbidden() try: form.id = int(form.id) channel = (PluginChannel if form.action == 'edit-channel' else Channel).get(form.id) except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') previous_state = { 'name': channel.name, 'description': channel.description, 'subscription_right': channel.subscription_right, 'enabled': channel.enabled } new_state = { 'name': name, 'description': description, 'subscription_right': form.subscription_right, 'enabled': enabled } state_diff = dict( set(new_state.items()) - set(previous_state.items())) if form.action == 'edit-channel': try: plugin_id = int(form.plugin) p = Plugin.get(plugin_id) add_mapping = p.webapp and channel.plugin != p previous_state['plugin'] = channel.plugin new_state['plugin'] = p except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_plugin') elif form.action == 'edit-bundle': pass # There is nothing more to edit for a bundle than a channel else: raise web.badrequest() try: channel.set(**new_state) except DuplicateEntryError: channel.set(**previous_state) # Rollback raise ImmediateFeedback(form.action, 'name_already_exists') logger.info( '[Channel %s (%d)] ' % (channel.name, channel.id) + current_user.log_name + ' edited the channel.\n' 'Previous state: %s\n' % str({ k: v for k, v in previous_state.items() if k in state_diff }) + 'New state: %s' % str(state_diff)) if form.action == 'edit-channel' and add_mapping: self.plugin_manager.add_mapping(self.app, channel) elif form.action.startswith('delete'): if not current_user.super_admin: logger.warning( 'the user %s tried to delete a channel without having the rights to do it', current_user.log_name) raise web.forbidden() try: form.id = int(form.id) channel = Channel.get(form.id) if channel.subscriptions.count( ) > 0 and 'confirm-delete' not in form: raise ImmediateFeedback( form.action, 'channel_has_subscriptions', { 'channel': { 'name': channel.name, 'id': channel.id, 'description': channel.description, 'subscription_right': channel.subscription_right }, 'plugin_id': channel.plugin.id if form.action == 'delete-channel' else None, 'subscriptions': [(s.screen.id, s.screen.name, s.screen.building.name) for s in channel.subscriptions] }) form.name = channel.name channel_name = channel.name channel.destroySelf() logger.info('the channel %s has been deleted by user %s', channel_name, current_user.log_name) except (SQLObjectNotFound, ValueError) as e: print(e) raise ImmediateFeedback(form.action, 'invalid_id') elif form.action == 'add-users-channel': try: if 'users' not in form: raise web.badrequest() form.users = json.loads(form.users) form.id = int(form.id) channel = PluginChannel.get(form.id) if not channel.has_admin( current_user ) and UserPermissions.administrator not in current_user.highest_permission_level: raise web.forbidden() form.name = channel.name for user_id, diff in form.users.items(): user_id = int(user_id) user = User.get(user_id) if 'permission' in diff: permission_level = diff['permission'] new_permission_level = UserPermissions( permission_level) old_permission_level = channel.get_channel_permissions_of( user) if new_permission_level == UserPermissions.no_permission \ and (UserPermissions.administrator in current_user.highest_permission_level or old_permission_level == UserPermissions.channel_contributor): channel.remove_permission_to_user(user) logger.info( 'permissions of user %s concerning channel %s have been removed by user %s', user.log_name, channel.name, current_user.log_name) elif (new_permission_level == UserPermissions.channel_contributor and channel.has_admin( current_user) and old_permission_level == UserPermissions.no_permission) \ or (new_permission_level in UserPermissions.channel_administrator and UserPermissions.administrator in current_user.highest_permission_level): channel.give_permission_to_user( user, new_permission_level) logger.info( 'permissions of user %s concerning channel %s have been set to %s by user %s', user.log_name, channel.name, UserPermissions.get_permission_string( new_permission_level), current_user.log_name) if 'authorized_subscriber' in diff: authorized_subscriber = diff[ 'authorized_subscriber'] if authorized_subscriber and ( user not in channel.authorized_subscribers): channel.addUser(user) logger.info( 'the user %s has been added to channel %s as authorized subscriber by user %s', user.log_name, channel.name, current_user.log_name) elif not authorized_subscriber and ( user in channel.authorized_subscribers): channel.removeUser(user) logger.info( 'the user %s has been removed from channel %s as authorized subscriber by user %s', user.log_name, channel.name, current_user.log_name) except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') except (KeyError, json.JSONDecodeError): raise ImmediateFeedback(form.action, 'invalid_users') elif form.action == 'configure': try: form.id = int(form.id) channel = PluginChannel.get(form.id) pattern = re.compile(r'list\[.*\]') if UserPermissions.administrator in current_user.highest_permission_level or UserPermissions.channel_administrator in channel.get_channel_permissions_of( current_user) or channel.has_contrib(current_user): for k, v in [(k, v) for k, v in channel.plugin.channels_params.items() if channel.get_access_rights_for( k, current_user)[1]]: # Iterates on the parameters the current user can write to if v['type'] == 'bool': value = k in form and form[k] == 'on' elif v['type'] == 'int': value = int(form[k]) if not (v.get('min', float('-inf')) <= value <= v.get('max', float('inf'))): continue elif pattern.match(v['type']): inner_type = v['type'][5:-1] if inner_type == 'string': value = web.input(**{k: ['']})[k] elif pattern.match(inner_type): inner_type = inner_type[5:-1] if inner_type == 'string': delimiter = form[k + '-delimiter'] values = web.input(**{k: ['']})[k] lists = [] l = [] for v in values: if v == delimiter: lists.append(l) l = [] else: l.append(v) value = lists elif k in form: if v['type'] == 'template' and form[k] == '~': value = None else: value = form[k] else: continue if channel.get_config_param(k) != value: channel.plugin_config[k] = value logger.info( 'the %s parameter of channel %s has been changed to %s by user %s', k, channel.name, value, current_user.log_name) if current_user.super_admin: channel.cache_activated = 'cache-activated' in form and form[ 'cache-activated'] == 'on' channel.cache_validity = int( form['cache-validity'] ) if 'cache-validity' in form and form[ 'cache-validity'] else channel.cache_validity channel.keep_noncomplying_capsules = 'keep-capsules' in form and form[ 'keep-capsules'] == 'on' channel.plugin_config = channel.plugin_config # Force SQLObject update try: self.plugin_manager.invalidate_cache( channel.plugin.name, channel.id) self.plugin_manager.get_plugin( channel.plugin.name).get_content(channel.id) except MisconfiguredParameters as e: for faulty_param in e: add_feedback(form.action, faulty_param[0], faulty_param) raise web.seeother('/channels/%d' % channel.id) except Exception as e: add_feedback(form.action, 'general_error', str(e)) raise web.seeother('/channels/%d' % channel.id) else: raise web.forbidden() form.name = channel.name except (SQLObjectNotFound, ValueError): raise ImmediateFeedback(form.action, 'invalid_id') if channel: form.name = channel.name add_feedback(form.action, 'ok') except ImmediateFeedback: if channel is not None and channel.enabled: form.enabled = 'on' store_form(form) return self.render_page(current_user)