예제 #1
0
    def post(self, channel):
        config = json.loads(self.form.config)
        post_process_config(config, channel)
        try:
            content = get_content(channel.id, config)
        except ValueError:
            resp.badrequest()

        self.plugin_manager.dereference_assets(content)
        self.plugin_manager.cache_assets(content, channel.id)
        try:
            preview = self.ictv_renderer.render_screen(content, controls=True)
        except (KeyError, ValueError):
            return "Preview could not be generated.<br><code>%s</code>" % traceback.format_exc(
            )
        except (TypeError):
            return "A problem occured."
        return preview
예제 #2
0
    def PATCH_AUTH(self, capsule_id, channel):
        try:
            post_data = flask.request.get_json(force=True)
        except JSONDecodeError:
            resp.badrequest()

        try:
            c = EditorCapsule.selectBy(id=int(capsule_id),
                                       channel=channel).getOne()
        except SQLObjectNotFound:
            resp.notfound()

        if 'name' in post_data and len(post_data['name']) < 3:
            resp.badrequest()

        if 'validity' in post_data:
            validity_from, validity_to = post_data['validity']
            if not (type(validity_from) == type(validity_to) ==
                    int) or validity_to < validity_from:
                resp.badrequest()
            try:
                validity_from, validity_to = datetime.fromtimestamp(
                    validity_from), datetime.fromtimestamp(validity_to)
            except (TypeError, ValueError):
                resp.badrequest()
            post_data['validity_from'] = validity_from
            post_data['validity_to'] = validity_to
            del post_data['validity']

        update_dict = {
            k: v
            for k, v in filter(
                lambda x: x[0] in
                ['name', 'theme', 'validity_from', 'validity_to'],
                post_data.items())
        }
        try:
            c.set(**update_dict)
        except DuplicateEntryError:
            resp.badrequest()

        resp.nocontent()
예제 #3
0
    def POST_AUTH(self, capsule_id, channel):
        try:
            post_data = flask.request.get_json(force=True)
        except JSONDecodeError:
            resp.badrequest()

        try:
            c = EditorCapsule.selectBy(id=int(capsule_id),
                                       channel=channel).getOne()
        except SQLObjectNotFound:
            resp.notfound()

        if {'duration', 'template', 'content'} != set(post_data.keys()):
            resp.badrequest()
        try:
            s = EditorSlide(s_order=c.slides.count(), capsule=c, **post_data)
        except SQLObjectIntegrityError:
            resp.badrequest()

        EditorSlide.rectify_s_order(c.id)
        response = resp.created()
        response.header[
            'Location'] = '/channels/{}/api/capsules/{}/slides/{}'.format(
                channel.id, capsule_id, s.id)
        return response
예제 #4
0
    def PATCH_AUTH(self, capsule_id, slide_id, channel):
        try:
            post_data = flask.request.get_json(force=True)
        except JSONDecodeError:
            resp.badrequest()

        try:
            c = EditorCapsule.selectBy(id=int(capsule_id),
                                       channel=channel).getOne()
            s = EditorSlide.selectBy(id=int(slide_id), capsule=c).getOne()
        except SQLObjectNotFound:
            resp.notfound()

        update_dict = {
            k: v
            for k, v in filter(
                lambda x: x[0] in ['duration', 'template', 'content'],
                post_data.items())
        }
        s.set(**update_dict)

        resp.nocontent()
예제 #5
0
    def post(self, capsuleid, channel):
        try:
            caps_db = EditorCapsule.get(int(capsuleid))
            slides = caps_db.slides
            form = self.form

            logger_extra = {'channel_name': channel.name, 'channel_id': channel.id}
            logger = get_logger('editor', channel)
            if caps_db.channel != channel:
                return "there is no capsule with the id " + str(capsuleid) + " in the channel " + str(channel.id)
            if form.action == 'delete':
                try:
                    slide = EditorSlide.get(int(form.id))
                except ValueError:
                    return "this is not a valid slide id"
                except SQLObjectNotFound:
                    return "there is no slide with the id " + form.id + " in the channel " + str(channel.id)
                slide.destroySelf()
                slides = EditorSlide.rectify_s_order(capsuleid)
            elif form.action == 'duplicate':
                try:
                    slide = EditorSlide.get(int(form.id))
                except ValueError:
                    return "this is not a valid slide id"
                except SQLObjectNotFound:
                    return "there is no slide with the id " + form.id + " in the channel " + str(channel.id)
                duplicate = slide.duplicate(s_order=-1)
                caps_db.insert_slide_at(duplicate, slide.s_order + 1)
                slides = caps_db.slides
            elif form.action == 'order':
                try:
                    new_order = json.loads(form.order)
                except AttributeError:
                    return "you seem to try to change the order of slides that doesn't exist..."
                except JSONDecodeError:
                    return "invalid changes"
                for k, v in new_order.items():
                    try:
                        slide = EditorSlide.get(int(k))
                        if slide.capsule.id != int(capsuleid):
                            return "you try to change the order of a slide in a different capsule..."
                        slide.s_order = int(v)
                    except ValueError:
                        return "invalid changes"
                    except SQLObjectNotFound:
                        return "You try to change the order of slides that doesn't exist..."
                slides = EditorSlide.rectify_s_order(capsuleid)
            elif form.action == 'theme':
                caps_db = EditorCapsule.get(int(capsuleid))
                if caps_db.channel != channel:
                    return "there is no capsule with the id " + str(capsuleid) + " in the channel " + str(channel.id)

                if form.theme not in Themes:
                    raise ImmediateFeedback(form.action, 'not_existing_theme')
                caps_db.theme = form.theme
            elif form.action == 'edit':
                try:
                    name = form.name.strip()
                    capsule = caps_db
                    if not name:
                        raise ValueError('name')

                    date_from = datetime.datetime.strptime(form['date-from'], "%Y-%m-%dT%H:%M:%S%z")
                    date_to = datetime.datetime.strptime(form['date-to'], "%Y-%m-%dT%H:%M:%S%z")
                    if date_to <= date_from:
                        raise ValueError('dates')

                    capsule.name = name
                    capsule.validity_from = date_from
                    capsule.validity_to = date_to
                except SQLObjectNotFound:
                    return seeother(channel.id, '/')
                except DuplicateEntryError:
                    raise ImmediateFeedback(form.action, 'name_already_exists')
                except ValueError as e:
                    raise ImmediateFeedback(form.action, 'invalid_name' if e.args[0] == 'name' else 'dates_inverted')
            elif form.action.startswith('import'):
                storage_manager = StorageManager(channel.id)
                capsule = caps_db
                background_color = 'white' if 'white-background' in form and form['white-background'] == 'on' else 'black'
                offset = EditorSlide.selectBy(capsule=capsule).max('s_order')
                offset = offset + 1 if offset is not None else 0

                if form.action == 'import-slides' and 'pdf' in form:
                    slide_files = []
                    try:
                        with Color(background_color) as bg:
                            with Image(blob=form.pdf.read(), resolution=150) as pdf:
                                for i, page in enumerate(pdf.sequence):
                                    img_page = Image(image=page)
                                    img_page.background_color = bg
                                    img_page.alpha_channel = False
                                    img_page.format = 'jpeg'
                                    img_page.transform(resize='1920x1080>')
                                    asset = storage_manager.store_file(img_page.make_blob('jpeg'),
                                                                       filename='import-capsule-%d-slide-%d.jpeg' % (capsule.id, offset + i),
                                                                       user=self.session['user']['id'])
                                    slide_files.append(asset)
                        slide_duration = channel.get_config_param('duration') * 1000
                        for i, slide_file in enumerate(slide_files):
                            s = EditorSlide(duration=slide_duration,
                                            content={'background-1': {'file': slide_file.id,
                                                                      'size': 'contain',
                                                                      'color': background_color}},
                                            s_order=offset + i, template='template-image-bg', capsule=capsule)

                            AssetSlideMapping(assetID=slide_file.id, slideID=s.id)
                    except (ValueError, TypeError):
                        logger.warning('An Exception has been encountered when importing PDF file:', extra=logger_extra,
                                       exc_info=True)
                elif form.action == 'import-video' and 'video' in form:
                    try:
                        video_slide = EditorSlide.from_video(form.video, storage_manager, self.transcoding_queue, capsule, self.session['user']['id'], background_color)
                        if type(video_slide) is str:  # Video is being transcoded
                            raise ImmediateFeedback(form.action, 'video_transcoding', video_slide)
                    except TypeError as e:
                        raise ImmediateFeedback(form.action, 'invalid_video_format', e.type)
                else:
                    resp.badrequest()
            elif form.action == 'duration':
                try:
                    slide_id = int(form.id)
                    slide = EditorSlide.get(slide_id)
                    if "duration" in form:
                        duration = float(form.duration)*1000
                        if duration < 0:
                            raise ImmediateFeedback(form.action, "negative_slide_duration")
                    else:
                        duration = -1
                    slide.duration = duration
                except SQLObjectNotFound:
                    return seeother(channel.id, '/')
                except ValueError:
                    raise ImmediateFeedback(form.action, 'invalid_slide_duration')
            add_feedback(form.action, 'ok')
        except ValueError:
            return "this is not a valid capsule id"
        except SQLObjectNotFound:
            return "there is no capsule with the id " + str(capsuleid) + " in the channel " + str(channel.id)
        except ImmediateFeedback:
            store_form(form)
        return self.render_page(channel=channel, capsule=caps_db, slides=caps_db.slides)
예제 #6
0
    def post(self, channel):
        form = self.form

        logger_extra = {'channel_name': channel.name, 'channel_id': channel.id}
        logger = get_logger('editor', channel)
        capsules = None
        try:
            if form['action'] == 'delete':
                try:
                    capsule_id = int(form['id'])
                except ValueError:
                    raise ImmediateFeedback(form.action, 'invalid_id')
                try:
                    capsule = EditorCapsule.get(capsule_id)
                except SQLObjectNotFound:
                    raise ImmediateFeedback(form.action, 'no_id_matching')

                if channel != capsule.channel:
                    raise ImmediateFeedback(form.action, 'wrong_channel')
                if capsule is None:
                    raise ImmediateFeedback(form.action, 'no_id_matching')
                capsule.destroySelf()
                capsules = EditorCapsule.rectify_c_order(channel.id)

            elif form['action'] == 'duplicate':
                try:
                    capsule_id = int(form['id'])
                except ValueError:
                    raise ImmediateFeedback(form.action, 'invalid_id')
                try:
                    capsule = EditorCapsule.get(capsule_id)
                except SQLObjectNotFound:
                    raise ImmediateFeedback(form.action, 'no_id_matching')

                if channel != capsule.channel:
                    raise ImmediateFeedback(form.action, 'wrong_channel')
                if capsule is None:
                    raise ImmediateFeedback(form.action, 'no_id_matching')
                capsule.duplicate(owner_id=self.session['user']['id'])
                capsules = EditorCapsule.rectify_c_order(channel.id)

            elif form.action == 'order':
                try:
                    new_order = json.loads(form.order)
                except AttributeError:
                    return "you seem to try to change the order of slides that doesn't exist..."
                except JSONDecodeError:
                    return "invalid changes"
                capsules_to_reorder = {}
                for k in new_order.keys():
                    try:
                        capsule = EditorCapsule.get(int(k))
                        capsules_to_reorder[k] = capsule
                        if capsule.channel.id != channel.id:
                            return "you try to change the order of a capsule in a different channel..."
                    except SQLObjectNotFound:
                        return "You try to change the order of slides that doesn't exist..."
                sorted_list = sorted(capsules_to_reorder.values(),
                                     key=lambda caps: caps.c_order)
                new_to_old_order = {}
                i = 0
                for elem in sorted_list:
                    new_to_old_order[i] = elem.c_order
                    i += 1
                try:
                    for k, v in new_order.items():
                        capsules_to_reorder[k].c_order = new_to_old_order[int(
                            v)]
                except ValueError:
                    return "invalid changes"
                capsules = EditorCapsule.rectify_c_order(channel.id)

            elif form['action'] == 'create' or form['action'].startswith(
                    'import'):
                name = form['name'].strip()
                if not name:
                    raise ImmediateFeedback(form.action, 'invalid_name')
                try:
                    if 'date-from' in form and 'date-to' in form:
                        try:
                            date_from = datetime.datetime.strptime(
                                form['date-from'], "%Y-%m-%dT%H:%M:%S%z")
                            date_to = datetime.datetime.strptime(
                                form['date-to'], "%Y-%m-%dT%H:%M:%S%z")
                        except ValueError:
                            raise ImmediateFeedback(form.action,
                                                    'wrong_date_values')
                    else:
                        if 'capsule_validity' in channel.plugin_config:
                            validity = int(
                                channel.plugin_config['capsule_validity'])
                        else:
                            validity = int(
                                channel.plugin.
                                channels_params['capsule_validity']['default'])
                        date_from = datetime.datetime.now()
                        time_delta = datetime.timedelta(hours=validity)
                        date_to = date_from + time_delta
                    if date_to <= date_from:
                        raise ImmediateFeedback(form.action, 'dates_inverted')
                    capsule = EditorCapsule(
                        name=form['name'],
                        channel=channel,
                        ownerID=self.session['user']['id'],
                        creation_date=datetime.datetime.now(),
                        c_order=EditorCapsule.select().count(),
                        validity_from=date_from,
                        validity_to=date_to)
                    if form.action.startswith('import'):
                        storage_manager = StorageManager(channel.id)
                        background_color = 'white' if 'white-background' in form and form[
                            'white-background'] == 'on' else 'black'

                        if form.action == 'import-capsule' and 'pdf' in form:

                            slide_files = []
                            try:
                                with Color(background_color) as bg:
                                    with Image(blob=form.pdf.read(),
                                               resolution=150) as pdf:
                                        for i, page in enumerate(pdf.sequence):
                                            img_page = Image(image=page)
                                            img_page.background_color = bg
                                            img_page.alpha_channel = False
                                            img_page.format = 'jpeg'
                                            img_page.transform(
                                                resize='1920x1080>')
                                            slide_files.append(
                                                storage_manager.store_file(
                                                    img_page.make_blob('jpeg'),
                                                    filename=
                                                    'import-capsule-%d-slide-%d.jpeg'
                                                    % (capsule.id, i),
                                                    user=self.session['user']
                                                    ['id']))
                                slide_duration = channel.get_config_param(
                                    'duration') * 1000
                                for i, slide_file in enumerate(slide_files):
                                    s = EditorSlide(
                                        duration=slide_duration,
                                        content={
                                            'background-1': {
                                                'file': slide_file.id,
                                                'size': 'contain',
                                                'color': background_color
                                            }
                                        },
                                        s_order=i,
                                        template='template-image-bg',
                                        capsule=capsule)
                                    AssetSlideMapping(assetID=slide_file.id,
                                                      slideID=s.id)
                            except (ValueError, TypeError):
                                logger.warning(
                                    'An Exception has been encountered when importing PDF file:',
                                    extra=logger_extra,
                                    exc_info=True)
                        elif form.action == 'import-video' and 'video' in form:
                            try:
                                video_slide = EditorSlide.from_video(
                                    form.video, storage_manager,
                                    self.transcoding_queue, capsule,
                                    self.session['user']['id'],
                                    background_color)
                                if type(video_slide
                                        ) is str:  # Video is being transcoded
                                    raise ImmediateFeedback(
                                        form.action, 'video_transcoding',
                                        video_slide)
                            except TypeError as e:
                                capsule.destroySelf()
                                raise ImmediateFeedback(
                                    form.action, 'invalid_video_format',
                                    e.type if hasattr(e, 'type') else None)
                        else:
                            resp.badrequest()

                except DuplicateEntryError:
                    raise ImmediateFeedback(form.action, 'name_already_exists')
            elif form['action'] == 'edit':
                name = form['name'].strip()
                if not name:
                    raise ImmediateFeedback(form.action, 'invalid_name')
                try:
                    capsule_id = int(form['id'])
                except ValueError:
                    raise ImmediateFeedback(form.action, 'invalid_id')
                try:
                    capsule = EditorCapsule.get(capsule_id)
                except SQLObjectNotFound:
                    raise ImmediateFeedback(form.action, 'no_id_matching')

                if channel != capsule.channel:
                    raise ImmediateFeedback(form.action, 'wrong_channel')
                try:
                    capsule.name = name
                except DuplicateEntryError:
                    raise ImmediateFeedback(form.action, 'name_already_exists')
                try:
                    date_from = datetime.datetime.strptime(
                        form['date-from'], "%Y-%m-%dT%H:%M:%S%z")
                    date_to = datetime.datetime.strptime(
                        form['date-to'], "%Y-%m-%dT%H:%M:%S%z")
                except ValueError:
                    raise ImmediateFeedback(form.action, 'wrong_date_values')
                if date_to <= date_from:
                    raise ImmediateFeedback(form.action, 'dates_inverted')
                capsule.validity_from = date_from
                capsule.validity_to = date_to
            add_feedback(form.action, 'ok')
        except ImmediateFeedback:
            pass
        store_form(form)
        return self.render_page(channel, capsules)
예제 #7
0
    def POST_AUTH(self, channel):
        try:
            post_data = flask.request.get_json(force=True)
        except JSONDecodeError:
            resp.badrequest()

        if {'name', 'theme', 'validity'} != set(post_data.keys()):
            resp.badrequest()

        if 'name' in post_data and len(post_data['name']) < 3:
            resp.badrequest()

        validity_from, validity_to = post_data['validity']
        if not (type(validity_from) == type(validity_to) ==
                int) or validity_to < validity_from:
            resp.badrequest()
        try:
            validity_from, validity_to = datetime.fromtimestamp(
                validity_from), datetime.fromtimestamp(validity_to)
        except (TypeError, ValueError):
            resp.badrequest()

        try:
            c = EditorCapsule(
                name=post_data['name'],
                theme=post_data['theme'],
                validity_from=validity_from,
                validity_to=validity_to,
                channel=channel,
                c_order=EditorCapsule.selectBy(channel=channel).count())
        except DuplicateEntryError:
            resp.badrequest()
        EditorCapsule.rectify_c_order(channel.id)
        response = resp.created()
        response.headers['Location'] = '/channels/{}/api/capsules/{}'.format(
            channel.id, c.id)
        return response
예제 #8
0
    def post(self):
        """ Handles channel creation, editing, deletion, configuration and user permissions. """
        form = self.form
        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 len(name) > Channel.sqlmeta.columns['name'].length:
                    raise ImmediateFeedback(form.action, 'too_long_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 self.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,
                            drop_silently_non_complying_slides=p.
                            drop_silently_non_complying_slides_default)
                        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:
                        resp.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 self.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:
                    resp.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 self.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:
                        resp.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 self.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 = self.input(**{k: ['']})[k]
                                elif pattern.match(inner_type):
                                    inner_type = inner_type[5:-1]
                                    if inner_type == 'string':
                                        delimiter = form[k + '-delimiter']
                                        values = self.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.drop_silently_non_complying_slides = 'drop_silently_non_complying_slides' in form and form[
                                'drop_silently_non_complying_slides'] == '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)
                            resp.seeother('/channels/config/%d' % channel.id)
                        except Exception as e:
                            add_feedback(form.action, 'general_error', str(e))
                            resp.seeother('/channels/config/%d' % channel.id)
                    else:
                        resp.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)