Пример #1
0
 def test_oneOf_branch_is_chosen_based_on_type_errors(self):
     schema = {
         "oneOf": [
             {
                 "type": ["string", "array"]
             },
             {
                 "oneOf": [{
                     "type": "integer"
                 }, {
                     "type": "number",
                     "minimum": 5
                 }]
             },
         ]
     }
     errors = config_schema.process_config(True, schema)
     # If there are type errors on both sides, it should be a virtual type error with all types
     assert len(errors) == 1
     assert tuple(errors[0].schema_path) == ('oneOf', 'type')
     # It should have all the types together
     assert set(errors[0].validator_value) == set(
         ['string', 'array', 'number', 'integer'])
     # If there are no type errors going down one branch it should choose it
     errors = config_schema.process_config(1.5, schema)
     assert len(errors) == 1
     assert errors[0].validator == 'minimum'
Пример #2
0
 def test_custom_error_template(self):
     schema = {
         'type': 'string',
         'minLength': 10,
         'error': '{{validator}} failed for {{instance}}'
     }
     errors = config_schema.process_config(13, schema)
     assert errors[0].message == "type failed for 13"
     errors = config_schema.process_config('aoeu', schema)
     assert errors[0].message == "minLength failed for aoeu"
Пример #3
0
 def test_custom_error_template(self):
     schema = {
         'type': 'string',
         'minLength': 10,
         'error': '{{validator}} failed for {{instance}}',
     }
     errors = config_schema.process_config(13, schema)
     assert errors[0].message == "type failed for 13"
     errors = config_schema.process_config('aoeu', schema)
     assert errors[0].message == "minLength failed for aoeu"
Пример #4
0
    def on_task_start(self, task, config):
        if not config:
            return

        files = config
        if isinstance(config, basestring):
            files = [config]

        for name in files:
            name = os.path.expanduser(name)
            if not os.path.isabs(name):
                name = os.path.join(task.manager.config_base, name)
            include = yaml.load(io.open(name, encoding='utf-8'))
            errors = process_config(include, plugin.plugin_schemas(context='task'))
            if errors:
                log.error('Included file %s has invalid config:' % name)
                for error in errors:
                    log.error('[%s] %s', error.json_pointer, error.message)
                task.abort('Invalid config in included file %s' % name)
            log.debug('Merging %s into task %s' % (name, task.name))
            # merge
            try:
                merge_dict_from_to(include, task.config)
            except MergeException:
                raise plugin.PluginError('Failed to merge include file to task %s, incompatible datatypes' % task.name)
Пример #5
0
    def validate_config(self):
        """
        Check all root level keywords are valid.

        :returns: A list of `ValidationError`s
        """
        return config_schema.process_config(self.config)
Пример #6
0
    def on_task_start(self, task, config):
        if not config:
            return

        files = config
        if isinstance(config, basestring):
            files = [config]

        for name in files:
            name = os.path.expanduser(name)
            if not os.path.isabs(name):
                name = os.path.join(task.manager.config_base, name)
            include = yaml.load(io.open(name, encoding='utf-8'))
            errors = process_config(include,
                                    plugin.plugin_schemas(context='task'))
            if errors:
                log.error('Included file %s has invalid config:' % name)
                for error in errors:
                    log.error('[%s] %s', error.json_pointer, error.message)
                task.abort('Invalid config in included file %s' % name)
            log.debug('Merging %s into task %s' % (name, task.name))
            # merge
            try:
                merge_dict_from_to(include, task.config)
            except MergeException:
                raise plugin.PluginError(
                    'Failed to merge include file to task %s, incompatible datatypes'
                    % task.name)
Пример #7
0
    def validate_config(self):
        """
        Check all root level keywords are valid.

        :returns: A list of `ValidationError`s
        """
        return config_schema.process_config(self.config)
Пример #8
0
    def on_task_prepare(self, task, config):
        if not config:
            return

        files = config
        if isinstance(config, str):
            files = [config]

        for file_name in files:
            file = os.path.expanduser(file_name)
            if not os.path.isabs(file):
                file = os.path.join(task.manager.config_base, file)
            with io.open(file, encoding='utf-8') as inc_file:
                include = yaml.safe_load(inc_file)
                inc_file.flush()
            errors = process_config(include, plugin.plugin_schemas(interface='task'))
            if errors:
                logger.error('Included file {} has invalid config:', file)
                for error in errors:
                    logger.error('[{}] {}', error.json_pointer, error.message)
                task.abort('Invalid config in included file %s' % file)

            logger.debug('Merging {} into task {}', file, task.name)
            # merge
            try:
                task.merge_config(include)
            except MergeException:
                raise plugin.PluginError(
                    'Failed to merge include file to task %s, incompatible datatypes' % task.name
                )
Пример #9
0
    def post(self, session=None):
        """ Add new task """
        data = request.json

        task_name = data["name"]

        if task_name in self.manager.user_config.get("tasks", {}):
            return {"error": "task already exists"}, 409

        if "tasks" not in self.manager.user_config:
            self.manager.user_config["tasks"] = {}
        if "tasks" not in self.manager.config:
            self.manager.config["tasks"] = {}

        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed, schema=task_api_schema.__schema__, set_defaults=True)

        if errors:
            return {"error": "problem loading config, raise a BUG as this should not happen!"}, 500

        self.manager.user_config["tasks"][task_name] = data["config"]
        self.manager.config["tasks"][task_name] = task_schema_processed["config"]

        self.manager.save_config()
        self.manager.config_changed()
        return {"name": task_name, "config": self.manager.user_config["tasks"][task_name]}, 201
Пример #10
0
    def post(self, session=None):
        """ Add new task """
        data = request.json

        task_name = data['name']

        if task_name in self.manager.user_config.get('tasks', {}):
            return {'error': 'task already exists'}, 409

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed,
                                schema=task_api_schema.__schema__,
                                set_defaults=True)

        if errors:
            return {
                'error':
                'problem loading config, raise a BUG as this should not happen!'
            }, 500

        self.manager.user_config['tasks'][task_name] = data['config']
        self.manager.config['tasks'][task_name] = task_schema_processed[
            'config']

        self.manager.save_config()
        self.manager.config_changed()
        return {
            'name': task_name,
            'config': self.manager.user_config['tasks'][task_name]
        }, 201
Пример #11
0
    def on_task_prepare(self, task, config):
        if not config:
            return

        files = config
        if isinstance(config, str):
            files = [config]

        for file_name in files:
            file = os.path.expanduser(file_name)
            if not os.path.isabs(file):
                file = os.path.join(task.manager.config_base, file)
            with io.open(file, encoding='utf-8') as inc_file:
                include = yaml.load(inc_file)
                inc_file.flush()
            errors = process_config(include, plugin.plugin_schemas(interface='task'))
            if errors:
                log.error('Included file %s has invalid config:', file)
                for error in errors:
                    log.error('[%s] %s', error.json_pointer, error.message)
                task.abort('Invalid config in included file %s' % file)

            log.debug('Merging %s into task %s', file, task.name)
            # merge
            try:
                task.merge_config(include)
            except MergeException:
                raise plugin.PluginError('Failed to merge include file to task %s, incompatible datatypes' % task.name)
Пример #12
0
    def post(self, session=None):
        """ Add new task """
        data = request.json

        task_name = data['name']

        if task_name in self.manager.user_config.get('tasks', {}):
            return {'error': 'task already exists'}, 409

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed, schema=task_api_schema.__schema__, set_defaults=True)

        if errors:
            return {'error': 'problem loading config, raise a BUG as this should not happen!'}, 500

        self.manager.user_config['tasks'][task_name] = data['config']
        self.manager.config['tasks'][task_name] = task_schema_processed['config']

        self.manager.save_config()
        self.manager.config_changed()
        return {'name': task_name, 'config': self.manager.user_config['tasks'][task_name]}, 201
Пример #13
0
    def post(self, session=None):
        """ Add new task """
        data = request.json

        task_name = data['name']

        if task_name in self.manager.user_config.get('tasks', {}):
            raise Conflict('task already exists')

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        task_schema_processed = copy.deepcopy(data)
        errors = process_config(
            task_schema_processed, schema=task_input_schema.__schema__, set_defaults=True
        )

        if errors:
            raise APIError('problem loading config, raise a BUG as this should not happen!')

        self.manager.user_config['tasks'][task_name] = data['config']
        self.manager.config['tasks'][task_name] = task_schema_processed['config']

        self.manager.save_config()
        self.manager.config_changed()
        rsp = jsonify({'name': task_name, 'config': self.manager.user_config['tasks'][task_name]})
        rsp.status_code = 201
        return rsp
Пример #14
0
 def test_custom_keyword_error_overrides(self):
     schema = {
         'type': 'string',
         'error_type': 'This is not okay',
         'error': 'This is worse'
     }
     errors = config_schema.process_config(13, schema)
     assert errors[0].message == schema['error_type']
Пример #15
0
    def validate_config(self):
        """
        Check all root level keywords are valid.

        :returns: A list of `ValidationError`s
        """
        fire_event('manager.before_config_validate', self)
        return config_schema.process_config(self.config)
Пример #16
0
    def validate_config(self):
        """
        Check all root level keywords are valid.

        :returns: A list of `ValidationError`s
        """
        fire_event('manager.before_config_validate', self)
        return config_schema.process_config(self.config)
Пример #17
0
 def test_oneOf_branch_is_chosen_based_on_type_errors(self):
     schema = {
         "oneOf": [
             {"type": ["string", "array"]},
             {"oneOf": [{"type": "integer"}, {"type": "number", "minimum": 5}]},
         ]
     }
     errors = config_schema.process_config(True, schema)
     # If there are type errors on both sides, it should be a virtual type error with all types
     assert len(errors) == 1
     assert tuple(errors[0].schema_path) == ('oneOf', 'type')
     # It should have all the types together
     assert set(errors[0].validator_value) == set(['string', 'array', 'number', 'integer'])
     # If there are no type errors going down one branch it should choose it
     errors = config_schema.process_config(1.5, schema)
     assert len(errors) == 1
     assert errors[0].validator == 'minimum'
Пример #18
0
 def wrapper(*args, **kwargs):
     payload = request.json
     try:
         errors = process_config(config=payload, schema=model.__schema__, set_defaults=False)
         if errors:
             raise ValidationError(errors)
     except RefResolutionError as e:
         raise ApiError(str(e))
     return func(*args, **kwargs)
Пример #19
0
    def on_task_start(self, task, config):

        series = {}
        for input_name, input_config in config.get('from', {}).items():
            input = plugin.get_plugin_by_name(input_name)
            if input.api_ver == 1:
                raise plugin.PluginError('Plugin %s does not support API v2' % input_name)

            method = input.phase_handlers['input']
            try:
                result = method(task, input_config)
            except PluginError as e:
                log.warning('Error during input plugin %s: %s' % (input_name, e))
                continue
            if not result:
                log.warning('Input %s did not return anything' % input_name)
                continue

            for entry in result:
                s = series.setdefault(entry['title'], {})
                if entry.get('tvdb_id'):
                    s['set'] = {'tvdb_id': entry['tvdb_id']}

                # Allow configure_series to set anything available to series
                for key, schema in self.settings_schema['properties'].items():
                    if 'configure_series_' + key in entry:
                        errors = process_config(entry['configure_series_' + key], schema, set_defaults=False)
                        if errors:
                            log.debug('not setting series option %s for %s. errors: %s' % (key, entry['title'], errors))
                        else:
                            s[key] = entry['configure_series_' + key]

        # Set the config_modified flag if the list of shows changed since last time
        new_hash = str(get_config_hash(series))
        with Session() as session:
            last_hash = session.query(LastHash).filter(LastHash.task == task.name).first()
            if not last_hash:
                last_hash = LastHash(task=task.name)
                session.add(last_hash)
            if last_hash.hash != new_hash:
                task.config_changed()
            last_hash.hash = new_hash

        if not series:
            log.info('Did not get any series to generate series configuration')
            return

        # Make a series config with the found series
        # Turn our dict of series with settings into a list of one item dicts
        series_config = {'generated_series': [dict([x]) for x in series.items()]}
        # If options were specified, add them to the series config
        if 'settings' in config:
            series_config['settings'] = {'generated_series': config['settings']}
        # Merge our series config in with the base series config
        self.merge_config(task, series_config)
Пример #20
0
    def on_task_start(self, task, config):

        series = {}
        for input_name, input_config in config.get('from', {}).items():
            input = plugin.get_plugin_by_name(input_name)
            if input.api_ver == 1:
                raise plugin.PluginError('Plugin %s does not support API v2' % input_name)

            method = input.phase_handlers['input']
            try:
                result = method(task, input_config)
            except PluginError as e:
                log.warning('Error during input plugin %s: %s' % (input_name, e))
                continue
            if not result:
                log.warning('Input %s did not return anything' % input_name)
                continue

            for entry in result:
                s = series.setdefault(entry['title'], {})
                if entry.get('tvdb_id'):
                    s['set'] = {'tvdb_id': entry['tvdb_id']}

                # Allow configure_series to set anything available to series
                for key, schema in self.settings_schema['properties'].items():
                    if 'configure_series_' + key in entry:
                        errors = process_config(entry['configure_series_' + key], schema, set_defaults=False)
                        if errors:
                            log.debug('not setting series option %s for %s. errors: %s' % (key, entry['title'], errors))
                        else:
                            s[key] = entry['configure_series_' + key]

        # Set the config_modified flag if the list of shows changed since last time
        new_hash = str(hashlib.md5(str(sorted(series)).encode('utf-8')).hexdigest())
        with Session() as session:
            last_hash = session.query(LastHash).filter(LastHash.task == task.name).first()
            if not last_hash:
                last_hash = LastHash(task=task.name)
                session.add(last_hash)
            if last_hash.hash != new_hash:
                task.config_changed()
            last_hash.hash = new_hash

        if not series:
            log.info('Did not get any series to generate series configuration')
            return

        # Make a series config with the found series
        # Turn our dict of series with settings into a list of one item dicts
        series_config = {'generated_series': [dict([s]) for s in series.items()]}
        # If options were specified, add them to the series config
        if 'settings' in config:
            series_config['settings'] = {'generated_series': config['settings']}
        # Merge our series config in with the base series config
        self.merge_config(task, series_config)
Пример #21
0
    def on_task_start(self, task, config):

        series = {}
        for input_name, input_config in config.get("from", {}).items():
            input = plugin.get_plugin_by_name(input_name)
            if input.api_ver == 1:
                raise plugin.PluginError("Plugin %s does not support API v2" % input_name)

            method = input.phase_handlers["input"]
            try:
                result = method(task, input_config)
            except PluginError as e:
                log.warning("Error during input plugin %s: %s" % (input_name, e))
                continue
            if not result:
                log.warning("Input %s did not return anything" % input_name)
                continue

            for entry in result:
                s = series.setdefault(entry["title"], {})
                if entry.get("tvdb_id"):
                    s["set"] = {"tvdb_id": entry["tvdb_id"]}

                # Allow configure_series to set anything available to series
                for key, schema in self.settings_schema["properties"].items():
                    if "configure_series_" + key in entry:
                        errors = process_config(entry["configure_series_" + key], schema, set_defaults=False)
                        if errors:
                            log.debug("not setting series option %s for %s. errors: %s" % (key, entry["title"], errors))
                        else:
                            s[key] = entry["configure_series_" + key]

        # Set the config_modified flag if the list of shows changed since last time
        new_hash = str(get_config_hash(series))
        with Session() as session:
            last_hash = session.query(LastHash).filter(LastHash.task == task.name).first()
            if not last_hash:
                last_hash = LastHash(task=task.name)
                session.add(last_hash)
            if last_hash.hash != new_hash:
                task.config_changed()
            last_hash.hash = new_hash

        if not series:
            log.info("Did not get any series to generate series configuration")
            return

        # Make a series config with the found series
        # Turn our dict of series with settings into a list of one item dicts
        series_config = {"generated_series": [dict([x]) for x in series.items()]}
        # If options were specified, add them to the series config
        if "settings" in config:
            series_config["settings"] = {"generated_series": config["settings"]}
        # Merge our series config in with the base series config
        self.merge_config(task, series_config)
Пример #22
0
    def on_task_prepare(self, task, config):

        series = {}
        for input_name, input_config in config.get('from', {}).items():
            input_plugin = plugin.get_plugin_by_name(input_name)
            method = input_plugin.phase_handlers['input']
            try:
                result = method(task, input_config)
            except PluginError as e:
                logger.warning('Error during input plugin {}: {}', input_name,
                               e)
                continue
            if not result:
                logger.warning('Input {} did not return anything', input_name)
                continue

            for entry in result:
                s = series.setdefault(entry['title'], {})
                if entry.get('tvdb_id'):
                    s['set'] = {'tvdb_id': entry['tvdb_id']}

                # Allow configure_series to set anything available to series
                for key, schema in self.settings_schema['properties'].items():
                    if 'configure_series_' + key in entry:
                        errors = process_config(entry['configure_series_' +
                                                      key],
                                                schema,
                                                set_defaults=False)
                        if errors:
                            logger.debug(
                                'not setting series option {} for {}. errors: {}',
                                key,
                                entry['title'],
                                errors,
                            )
                        else:
                            s[key] = entry['configure_series_' + key]

        if not series:
            logger.info(
                'Did not get any series to generate series configuration')
            return

        # Make a series config with the found series
        # Turn our dict of series with settings into a list of one item dicts
        series_config = {
            'generated_series': [dict([x]) for x in series.items()]
        }
        # If options were specified, add them to the series config
        if 'settings' in config:
            series_config['settings'] = {
                'generated_series': config['settings']
            }
        # Merge our series config in with the base series config
        self.merge_config(task, series_config)
Пример #23
0
            def wrapper(*args, **kwargs):
                payload = request.json
                try:
                    schema = schema_override if schema_override else model.__schema__
                    errors = process_config(config=payload, schema=schema, set_defaults=False)

                    if errors:
                        raise ValidationError(errors)
                except RefResolutionError as e:
                    raise APIError(str(e))
                return func(*args, **kwargs)
Пример #24
0
def config_root_key(root_key):
    if request.method == 'PUT':
        schema = resolve_ref('/schema/config/%s' % root_key)
        errors = process_config(request.json, schema, set_defaults=False)
        if errors:
            return jsonify({'$errors': errors}), 400
        manager.config[root_key] = request.json
    if root_key not in manager.config:
        return 'Not found', 404
    response = jsonify(manager.config[root_key])
    response.headers[b'Content-Type'] += '; profile=/schema/config/%s' % root_key
    return response
Пример #25
0
def config_root_key(root_key):
    if request.method == 'PUT':
        schema = resolve_ref('/schema/config/%s' % root_key)
        errors = process_config(request.json, schema, set_defaults=False)
        if errors:
            return jsonify({'$errors': errors}), 400
        manager.config[root_key] = request.json
    if root_key not in manager.config:
        return 'Not found', 404
    response = jsonify(manager.config[root_key])
    response.headers[
        b'Content-Type'] += '; profile=/schema/config/%s' % root_key
    return response
Пример #26
0
 def test_error_with_path(self):
     schema = {
         'properties': {
             'p': {
                 'items': {
                     'type': 'string',
                     'error': 'ERROR'
                 }
             }
         }
     }
     errors = config_schema.process_config({'p': [13]}, schema)
     assert errors[0].json_pointer == '/p/0'
     assert errors[0].message == 'ERROR'
Пример #27
0
def config_section(section):
    if request.method == "PUT":
        schema = resolve_ref("/schema/config/%s" % section)
        errors = process_config(request.json, schema, set_defaults=False)
        if errors:
            return jsonify({"$errors": errors}), 400
        manager.config[section] = request.json
    if section not in manager.config:
        return jsonify(error="Not found"), 404
    if request.method == "DELETE":
        del manager.config[section]
        return Response(status=204)
    response = jsonify(manager.config[section])
    response.headers[b"Content-Type"] += "; profile=/schema/config/%s" % section
    return response
Пример #28
0
def config_section(section):
    if request.method == 'PUT':
        schema = resolve_ref('/schema/config/%s' % section)
        errors = process_config(request.json, schema, set_defaults=False)
        if errors:
            return jsonify({'$errors': errors}), 400
        manager.config[section] = request.json
    if section not in manager.config:
        return jsonify(error='Not found'), 404
    if request.method == 'DELETE':
        del manager.config[section]
        return Response(status=204)
    response = jsonify(manager.config[section])
    response.headers[b'Content-Type'] += '; profile=/schema/config/%s' % section
    return response
Пример #29
0
    def on_task_start(self, task, config):
        if not config:
            return

        files = config
        if isinstance(config, str):
            files = [config]

        for file_name in files:
            file_name = os.path.expanduser(file_name)
            if not os.path.isabs(file_name):
                file_name = os.path.join(task.manager.config_base, file_name)
            with io.open(file_name, encoding='utf-8') as inc_file:
                include = yaml.load(inc_file)
                inc_file.flush()
            errors = process_config(include,
                                    plugin.plugin_schemas(interface='task'))
            if errors:
                log.error('Included file %s has invalid config:', file_name)
                for error in errors:
                    log.error('[%s] %s', error.json_pointer, error.message)
                task.abort('Invalid config in included file %s' % file_name)

            new_hash = str(get_config_hash(include))
            with Session() as session:
                last_hash = session.query(LastHash).filter(
                    LastHash.task == task.name).filter(
                        LastHash.file == file_name).first()
                if not last_hash:
                    log.debug(
                        'no config hash detected for task %s with file %s, creating',
                        task.name, file_name)
                    last_hash = LastHash(task=task.name, file=file_name)
                    session.add(last_hash)
                if last_hash.hash != new_hash:
                    log.debug(
                        'new hash detected, triggering config change event')
                    task.config_changed()
                last_hash.hash = new_hash

            log.debug('Merging %s into task %s', file_name, task.name)
            # merge
            try:
                merge_dict_from_to(include, task.config)
            except MergeException:
                raise plugin.PluginError(
                    'Failed to merge include file to task %s, incompatible datatypes'
                    % task.name)
Пример #30
0
    def put(self, task, session: Session = None) -> Response:
        """ Update tasks config """
        data = request.json

        new_task_name = data['name']

        if task not in self.manager.user_config.get('tasks', {}):
            raise NotFoundError(f'task `{task}` not found')

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        if task != new_task_name:
            # Rename task
            if new_task_name in self.manager.user_config['tasks']:
                raise BadRequest('cannot rename task as it already exist')

            del self.manager.user_config['tasks'][task]
            del self.manager.config['tasks'][task]

        # Process the task config
        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed,
                                schema=task_return_schema.__schema__,
                                set_defaults=True)

        if errors:
            raise APIError(
                'problem loading config, raise a BUG as this should not happen!'
            )

        self.manager.user_config['tasks'][new_task_name] = data['config']
        self.manager.config['tasks'][new_task_name] = task_schema_processed[
            'config']

        self.manager.save_config()
        self.manager.config_changed()

        rsp = jsonify({
            'name':
            new_task_name,
            'config':
            self.manager.user_config['tasks'][new_task_name]
        })
        rsp.status_code = 200
        return rsp
Пример #31
0
def config_section(section):
    if request.method == 'PUT':
        schema = resolve_ref('/schema/config/%s' % section)
        errors = process_config(request.json, schema, set_defaults=False)
        if errors:
            return jsonify({'$errors': errors}), 400
        manager.config[section] = request.json
    if section not in manager.config:
        return jsonify(error='Not found'), 404
    if request.method == 'DELETE':
        del manager.config[section]
        return Response(status=204)
    response = jsonify(manager.config[section])
    response.headers[
        b'Content-Type'] += '; profile=/schema/config/%s' % section
    return response
Пример #32
0
    def put(self, task, session=None):
        """ Update tasks config """
        data = request.json

        new_task_name = data['name']

        if task not in self.manager.user_config.get('tasks', {}):
            return {'error': 'task does not exist'}, 404

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        code = 200
        if task != new_task_name:
            # Rename task
            if new_task_name in self.manager.user_config['tasks']:
                return {'error': 'cannot rename task as it already exist'}, 400

            del self.manager.user_config['tasks'][task]
            del self.manager.config['tasks'][task]
            code = 201

        # Process the task config
        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed,
                                schema=task_api_schema.__schema__,
                                set_defaults=True)

        if errors:
            return {
                'error':
                'problem loading config, raise a BUG as this should not happen!'
            }, 500

        self.manager.user_config['tasks'][new_task_name] = data['config']
        self.manager.config['tasks'][new_task_name] = task_schema_processed[
            'config']

        self.manager.save_config()
        self.manager.config_changed()

        return {
            'name': new_task_name,
            'config': self.manager.user_config['tasks'][new_task_name]
        }, code
Пример #33
0
    def on_task_prepare(self, task, config):

        series = {}
        for input_name, input_config in config.get('from', {}).items():
            input_plugin = plugin.get_plugin_by_name(input_name)
            method = input_plugin.phase_handlers['input']
            try:
                result = method(task, input_config)
            except PluginError as e:
                log.warning('Error during input plugin %s: %s' % (input_name, e))
                continue
            if not result:
                log.warning('Input %s did not return anything' % input_name)
                continue

            for entry in result:
                s = series.setdefault(entry['title'], {})
                if entry.get('tvdb_id'):
                    s['set'] = {'tvdb_id': entry['tvdb_id']}

                # Allow configure_series to set anything available to series
                for key, schema in self.settings_schema['properties'].items():
                    if 'configure_series_' + key in entry:
                        errors = process_config(
                            entry['configure_series_' + key], schema, set_defaults=False
                        )
                        if errors:
                            log.debug(
                                'not setting series option %s for %s. errors: %s'
                                % (key, entry['title'], errors)
                            )
                        else:
                            s[key] = entry['configure_series_' + key]

        if not series:
            log.info('Did not get any series to generate series configuration')
            return

        # Make a series config with the found series
        # Turn our dict of series with settings into a list of one item dicts
        series_config = {'generated_series': [dict([x]) for x in series.items()]}
        # If options were specified, add them to the series config
        if 'settings' in config:
            series_config['settings'] = {'generated_series': config['settings']}
        # Merge our series config in with the base series config
        self.merge_config(task, series_config)
Пример #34
0
    def validate_config(self, config: dict = None) -> dict:
        """
        Check all root level keywords are valid. Config may be modified by before_config_validate hooks. Modified
        config will be returned.

        :param config: Config to check. If not provided, current manager config will be checked.
        :raises: `ValueError` when config fails validation. There will be an `errors` attribute with the schema errors.
        :returns: Final validated config.
        """
        conf = config if config else self.config
        conf = fire_event('manager.before_config_validate', conf, self)
        errors = config_schema.process_config(conf)
        if errors:
            err = ValueError('Did not pass schema validation.')
            err.errors = errors
            raise err
        else:
            return conf
Пример #35
0
    def validate_config(self, config=None):
        """
        Check all root level keywords are valid. Config may be modified by before_config_validate hooks. Modified
        config will be returned.

        :param config: Config to check. If not provided, current manager config will be checked.
        :raises: `ValueError` when config fails validation. There will be an `errors` attribute with the schema errors.
        :returns: Final validated config.
        """
        if not config:
            config = self.config
        config = fire_event('manager.before_config_validate', config, self)
        errors = config_schema.process_config(config)
        if errors:
            err = ValueError('Did not pass schema validation.')
            err.errors = errors
            raise err
        else:
            return config
Пример #36
0
    def put(self, task, session=None):
        """ Update tasks config """
        data = request.json

        new_task_name = data['name']

        if task not in self.manager.user_config.get('tasks', {}):
            raise NotFoundError('task `%s` not found' % task)

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        if task != new_task_name:
            # Rename task
            if new_task_name in self.manager.user_config['tasks']:
                raise BadRequest('cannot rename task as it already exist')

            del self.manager.user_config['tasks'][task]
            del self.manager.config['tasks'][task]

        # Process the task config
        task_schema_processed = copy.deepcopy(data)
        errors = process_config(
            task_schema_processed, schema=task_return_schema.__schema__, set_defaults=True
        )

        if errors:
            raise APIError('problem loading config, raise a BUG as this should not happen!')

        self.manager.user_config['tasks'][new_task_name] = data['config']
        self.manager.config['tasks'][new_task_name] = task_schema_processed['config']

        self.manager.save_config()
        self.manager.config_changed()

        rsp = jsonify(
            {'name': new_task_name, 'config': self.manager.user_config['tasks'][new_task_name]}
        )
        rsp.status_code = 200
        return rsp
Пример #37
0
    def post(self, task, session=None):
        """ Update tasks config """
        data = request.json

        new_task_name = data['name']

        if task not in self.manager.user_config.get('tasks', {}):
            return {'error': 'task does not exist'}, 404

        if 'tasks' not in self.manager.user_config:
            self.manager.user_config['tasks'] = {}
        if 'tasks' not in self.manager.config:
            self.manager.config['tasks'] = {}

        code = 200
        if task != new_task_name:
            # Rename task
            if new_task_name in self.manager.user_config['tasks']:
                return {'error': 'cannot rename task as it already exist'}, 400

            del self.manager.user_config['tasks'][task]
            del self.manager.config['tasks'][task]
            code = 201

        # Process the task config
        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed, schema=task_api_schema.__schema__, set_defaults=True)

        if errors:
            return {'error': 'problem loading config, raise a BUG as this should not happen!'}, 500

        self.manager.user_config['tasks'][new_task_name] = data['config']
        self.manager.config['tasks'][new_task_name] = task_schema_processed['config']

        self.manager.save_config()
        self.manager.config_changed()

        return {'name': new_task_name, 'config': self.manager.user_config['tasks'][new_task_name]}, code
Пример #38
0
    def post(self, task, session=None):
        """ Update tasks config """
        data = request.json

        new_task_name = data["name"]

        if task not in self.manager.user_config.get("tasks", {}):
            return {"error": "task does not exist"}, 404

        if "tasks" not in self.manager.user_config:
            self.manager.user_config["tasks"] = {}
        if "tasks" not in self.manager.config:
            self.manager.config["tasks"] = {}

        code = 200
        if task != new_task_name:
            # Rename task
            if new_task_name in self.manager.user_config["tasks"]:
                return {"error": "cannot rename task as it already exist"}, 400

            del self.manager.user_config["tasks"][task]
            del self.manager.config["tasks"][task]
            code = 201

        # Process the task config
        task_schema_processed = copy.deepcopy(data)
        errors = process_config(task_schema_processed, schema=task_api_schema.__schema__, set_defaults=True)

        if errors:
            return {"error": "problem loading config, raise a BUG as this should not happen!"}, 500

        self.manager.user_config["tasks"][new_task_name] = data["config"]
        self.manager.config["tasks"][new_task_name] = task_schema_processed["config"]

        self.manager.save_config()
        self.manager.config_changed()

        return {"name": new_task_name, "config": self.manager.user_config["tasks"][new_task_name]}, code
Пример #39
0
 def test_defaults_are_filled(self):
     schema = {"properties": {"p": {"default": 5}}}
     config = {}
     config_schema.process_config(config, schema)
     assert config["p"] == 5
Пример #40
0
 def test_defaults_does_not_override_explicit_value(self):
     schema = {"properties": {"p": {"default": 5}}}
     config = {"p": "foo"}
     config_schema.process_config(config, schema)
     assert config["p"] == "foo"
Пример #41
0
 def test_resolves_local_refs(self):
     schema = {'$ref': '/schema/plugin/accept_all'}
     # accept_all schema should be for type boolean
     assert not config_schema.process_config(True, schema)
     assert config_schema.process_config(14, schema)
Пример #42
0
 def validate_config(config):
     schema = plugin_schemas(context='task')
     # Don't validate commented out plugins
     schema['patternProperties'] = {'^_': {}}
     return config_schema.process_config(config, schema)
Пример #43
0
 def test_defaults_are_filled(self):
     schema = {"properties": {"p": {"default": 5}}}
     config = {}
     config_schema.process_config(config, schema)
     assert config["p"] == 5
Пример #44
0
 def validate(self, value):
     """This is just to unit test backwards compatibility of json schema with old validators"""
     errors = list(e.message for e in process_config(value, self.schema()))
     self.errors.messages = errors
     return not errors
Пример #45
0
 def test_builtin_error_rewriting(self):
     schema = {'type': 'object'}
     errors = config_schema.process_config(42, schema)
     # We don't call them objects around here
     assert 'object' not in errors[0].message
     assert 'dict' in errors[0].message
Пример #46
0
 def test_custom_keyword_error_overrides(self):
     schema = {'type': 'string', 'error_type': 'This is not okay', 'error': 'This is worse'}
     errors = config_schema.process_config(13, schema)
     assert errors[0].message == schema['error_type']
Пример #47
0
 def test_error_with_path(self):
     schema = {'properties': {'p': {'items': {'type': 'string', 'error': 'ERROR'}}}}
     errors = config_schema.process_config({'p': [13]}, schema)
     assert errors[0].json_pointer == '/p/0'
     assert errors[0].message == 'ERROR'
Пример #48
0
 def test_custom_error(self):
     schema = {'type': 'string', 'error': 'This is not okay'}
     errors = config_schema.process_config(13, schema)
     assert errors[0].message == schema['error']
Пример #49
0
 def test_custom_format_checker(self):
     schema = {'type': 'string', 'format': 'quality'}
     assert not config_schema.process_config('720p', schema)
     assert config_schema.process_config('aoeu', schema)
Пример #50
0
 def test_resolves_local_refs(self):
     schema = {'$ref': '/schema/plugin/accept_all'}
     # accept_all schema should be for type boolean
     assert not config_schema.process_config(True, schema)
     assert config_schema.process_config(14, schema)
Пример #51
0
 def test_defaults_does_not_override_explicit_value(self):
     schema = {"properties": {"p": {"default": 5}}}
     config = {"p": "foo"}
     config_schema.process_config(config, schema)
     assert config["p"] == "foo"
Пример #52
0
 def test_custom_format_checker(self):
     schema = {'type': 'string', 'format': 'quality'}
     assert not config_schema.process_config('720p', schema)
     assert config_schema.process_config('aoeu', schema)
Пример #53
0
 def validate_config(config):
     schema = plugin_schemas(context='task')
     # Don't validate commented out plugins
     schema['patternProperties'] = {'^_': {}}
     return config_schema.process_config(config, schema)
Пример #54
0
 def test_custom_error(self):
     schema = {'type': 'string', 'error': 'This is not okay'}
     errors = config_schema.process_config(13, schema)
     assert errors[0].message == schema['error']
Пример #55
0
 def test_builtin_error_rewriting(self):
     schema = {'type': 'object'}
     errors = config_schema.process_config(42, schema)
     # We don't call them objects around here
     assert 'object' not in errors[0].message
     assert 'dict' in errors[0].message