Example #1
0
    def import_all(self):
        """Import content."""

        content_digest = Config.operation_digest
        content_uuid = Config.operation_uuid
        if content_digest or content_uuid:
            collection = self._storage.search(uuid=content_uuid, digest=content_digest)
            if len(collection) == 1:
                resource = next(collection.resources())
                digest = resource.digest
                updates = Migrate.load(Config.get_operation_file())
                self._logger.debug('updating: %s ' % resource.category,
                                   ':with: uuid: %.16s' % content_uuid if content_uuid else
                                   ':with: digest: %.16s' % resource.digest)
                if len(updates) == 1:
                    resource.migrate(next(updates.resources()))
                    self._storage.update(digest, resource)
                else:
                    Cause.push(Cause.HTTP_BAD_REQUEST, 'updates for content: %.16s :could not be used' % digest)
            else:
                Config.validate_search_context(collection, 'import')
        else:
            self._logger.debug('importing content: %s', Config.get_operation_file())
            collection = Migrate.load(Config.get_operation_file())
            self._storage.import_content(collection)
Example #2
0
    def on_get(self, request, response):
        """Search unique resource attributes.

        Search is made from all content categories by default.

        Args:
            request (obj): Falcon Request().
            response (obj): Falcon Response().
        """

        self._logger.debug('run: %s %s', request.method, request.uri)
        if 'scat' not in request.params:
            request.params['scat'] = Const.CATEGORIES
        api = Api(self._category, Api.UNIQUE, request.params)
        Config.load(api)
        self._content.run()
        if not self._content.uniques:
            Cause.push(
                Cause.HTTP_NOT_FOUND,
                'cannot find unique fields for %s attribute' % self._category)
        if Cause.is_ok():
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.fields(self._category,
                                            self._content.uniques, request,
                                            response)
            response.status = Cause.http_status()
        else:
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.error(Cause.json_message())
            response.status = Cause.http_status()

        Cause.reset()
        self._logger.debug('end: %s %s', request.method, request.uri)
Example #3
0
    def update(self):
        """Update content."""

        collection = self._storage.search(
            scat=Config.search_cat_kws,
            sall=Config.search_all_kws,
            stag=Config.search_tag_kws,
            sgrp=Config.search_grp_kws,
            search_filter=Config.search_filter,
            uuid=Config.operation_uuid,
            digest=Config.operation_digest,
            identity=Config.operation_identity,
            data=Config.content_data
        )
        if len(collection) == 1:
            stored = next(collection.resources())
            digest = stored.digest
            updates = Config.get_resource(stored)
            if updates and updates != stored:
                self._logger.debug('updating stored: %s :with digest: %.16s', self._category, digest)
                stored.migrate(updates)
                self.collection = self._storage.update(digest, stored)
            else:
                self._logger.debug('content: %s :with digest: %.16s :was not updated', self._category, digest)
        else:
            Config.validate_search_context(collection, 'update')
Example #4
0
    def on_get(self, request, response, sall=None, stag=None, sgrp=None):
        """Search resources.

        Args:
            request (obj): Falcon Request().
            response (obj): Falcon Response().
            sall (str): Search all ``sall`` path parameter.
            stag (str): Search tags ``stag`` path parameter.
            sgrp (str): Search groups ``sgrp`` path parameter.
        """

        self._logger.debug('run: %s %s', request.method, request.uri)
        if sall:
            request.params['sall'] = sall
        if stag:
            request.params['stag'] = stag
        if sgrp:
            request.params['sgrp'] = sgrp
        api = Api(self._category, Api.SEARCH, request.params)
        Config.load(api)
        self._content.run()
        if not self._content.collection and Config.search_limit != 0:
            Cause.push(Cause.HTTP_NOT_FOUND, 'cannot find resources')
        if Cause.is_ok():
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.collection(self._content.collection, request, response, pagination=True)
            response.status = Cause.http_status()
        else:
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.error(Cause.json_message())
            response.status = Cause.http_status()

        Cause.reset()
        self._logger.debug('end: %s %s', request.method, request.uri)
Example #5
0
    def on_get(self, request, response, identity, field):
        """Get defined content field based on resource ID.

        If the given uuid matches to multiple resources or no resources at
        all, an error is returned. This conflicts against the JSON API v1.0
        specifications. See the Snippy documentation for more information.

        Args:
            request (obj): Falcon Request().
            response (obj): Falcon Response().
            identity (str): Partial or full message digest or UUID.
            field (str): Resource attribute.
        """

        self._logger.debug('run: %s %s', request.method, request.uri)
        local_params = {'identity': identity, 'fields': field}
        api = Api(self._category, Api.SEARCH, local_params)
        Config.load(api)
        self._content.run()
        if len(self._content.collection) != 1:
            Cause.push(Cause.HTTP_NOT_FOUND, 'content identity: %s was not unique and matched to: %d resources' %
                       (identity, len(self._content.collection)))
        if Cause.is_ok():
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.resource(self._content.collection, request, response, identity, field=field, pagination=False)
            response.status = Cause.http_status()
        else:
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.error(Cause.json_message())
            response.status = Cause.http_status()

        Cause.reset()
        self._logger.debug('end: %s %s', request.method, request.uri)
Example #6
0
    def on_post(self, request, response, **kwargs):  # pylint: disable=unused-argument
        """Create new resource.

        Args:
            request (obj): Falcon Request().
            response (obj): Falcon Response().
        """

        self._logger.debug('run: %s %s', request.method, request.uri)
        collection = Collection()
        data = Validate.json_object(request)
        for resource in data:
            api = Api(self._category, Api.CREATE, resource)
            Config.load(api)
            self._content.run(collection)
        if Cause.is_ok():
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.collection(collection, request, response)
            response.status = Cause.http_status()
        else:
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.error(Cause.json_message())
            response.status = Cause.http_status()
        Cause.reset()
        self._logger.debug('end: %s %s', request.method, request.uri)
Example #7
0
    def on_put(self, request, response, identity):
        """Update resource based on the resource ID.

        Args:
            request (obj): Falcon Request().
            response (obj): Falcon Response().
            identity (str): Partial or full message digest or UUID.
        """

        self._logger.debug('run: %s %s', request.method, request.uri)
        collection = Validate.json_object(request, identity)
        for resource in collection:
            api = Api(self._category, Api.UPDATE, resource)
            Config.load(api)
            self._content.run()
        if Cause.is_ok():
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.resource(self._content.collection, request, response, identity)
            response.status = Cause.http_status()
        else:
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.error(Cause.json_message())
            response.status = Cause.http_status()

        Cause.reset()
        self._logger.debug('end: %s %s', request.method, request.uri)
Example #8
0
    def test_config_create_006():
        """Test that tags can be added inside quotes separated by comma and
        space after comma."""

        content = 'docker rm $(docker ps -a -q)'
        brief = 'Remove all docker containers'
        groups = ('docker', )
        tags = ('cleanup', 'container', 'docker')
        links = (
            'https://askubuntu.com/questions/574163/how-to-stop-and-remove-a-docker-container',
        )
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'create', '-c', content, '-b', brief, '-g', 'docker',
                '-t', 'docker, container, cleanup', '-l', links[0]
            ]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_groups, tuple)
        assert isinstance(Config.content_tags, tuple)
        assert isinstance(Config.content_links, tuple)
        assert Config.content_data == tuple([content])
        assert Config.content_brief == brief
        assert Config.content_groups == groups
        assert Config.content_tags == tags
        assert Config.content_links == links
Example #9
0
    def test_config_create_013():
        """Test that multiple links can be added by separating them with
        bar."""

        content = 'docker rm $(docker ps -a -q)'
        brief = 'Remove all docker containers'
        tags = ('cleanup', 'container', 'docker')
        links = (
            'https://askubuntu.com/questions/574163/how-to-stop-and-remove-a-docker-container',
            'https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes'
        )
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'create', '-c', content, '-b', brief, '-t',
                'docker, container, cleanup', '-l', '|'.join(links)
            ]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert isinstance(Config.content_links, tuple)
        assert Config.content_data == tuple([content])
        assert Config.content_brief == brief
        assert Config.content_tags == tags
        assert Config.content_links == links
Example #10
0
def database_mock(request, mocker):
    """Mock database for testing."""

    from snippy.storage.database import Database as Db

    Config.init(['snippy', '-q'] + Database.get_cli_params()
                )  # Prevent unnecessary CLI help output with quiet option.
    mocker.patch.object(Config,
                        'storage_file',
                        Database.get_storage(),
                        create=True)
    mocker.patch.object(Config,
                        'storage_schema',
                        Database.get_schema(),
                        create=True)

    database = Db()
    database.init()

    def fin():
        """Clear the resources at the end."""

        database.disconnect()
        Database.delete_all_contents()
        Database.delete_storage()

    request.addfinalizer(fin)

    return database
Example #11
0
    def release(self):
        """Release service resource."""

        self.storage.disconnect()
        Cause.reset()
        Config.reset()
        Logger.reset()
Example #12
0
    def test_config_search_001():
        """Test that search can be used with one keyword."""

        search_kw = ('docker', )
        Config.init(None)
        Config.load(Cli(['snippy', 'search', '--sall', 'docker']))
        assert isinstance(Config.search_all_kws, tuple)
        assert Config.search_all_kws == search_kw
Example #13
0
    def test_config_search_004():
        """Test that search keywords can be added so that they are separated
        by spaces before and after the words."""

        search_kw = ('cleanup', 'container', 'docker')
        Config.init(None)
        Config.load(
            Cli(['snippy', 'search', '--sall', 'docker, container, cleanup']))
        assert isinstance(Config.search_all_kws, tuple)
        assert Config.search_all_kws == search_kw
Example #14
0
    def test_config_search_003():
        """Test that search keywords can be added inside quotes separated by
        comma and spaces after comma."""

        search_kw = ('cleanup', 'container', 'docker')
        Config.init(None)
        Config.load(
            Cli(['snippy', 'search', '--sall', 'docker, container, cleanup']))
        assert isinstance(Config.search_all_kws, tuple)
        assert Config.search_all_kws == search_kw
Example #15
0
    def test_config_create_002():
        """Test that new snippet can be created without optional arguments."""

        content = 'docker rm $(docker ps -a -q)'
        Config.init(None)
        Config.load(Cli(['snippy', 'create', '-c', content]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert not Config.content_brief
        assert not Config.content_tags
Example #16
0
    def test_config_create_004():
        """Test that new snippet can be created with a single tag."""

        content = 'docker rm $(docker ps -a -q)'
        tags = ('docker', )
        Config.init(None)
        Config.load(Cli(['snippy', 'create', '-c', content, '-t', 'docker']))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert not Config.content_brief
        assert Config.content_tags == tags
Example #17
0
    def test_config_create_003():
        """Test that new snippet can be created with brief description but
        no tags."""

        content = 'docker rm $(docker ps -a -q)'
        brief = 'Remove all docker containers'
        Config.init(None)
        Config.load(Cli(['snippy', 'create', '-c', content, '-b', brief]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert Config.content_brief == brief
        assert not Config.content_tags
Example #18
0
    def test_config_search_007():
        """Test that search keywords are accepted if they contain special
        characters."""

        search_kw = (u'cleanup_testing', u'container-managemenet',
                     u'docker–testing')
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'search', '--sall', 'docker–testing, ',
                'container-managemenet, ', 'cleanup_testing'
            ]))
        assert isinstance(Config.search_all_kws, tuple)
        assert Config.search_all_kws == search_kw
        assert len(Config.search_all_kws) == 3
Example #19
0
    def create(self):
        """Create new content."""

        self._logger.debug('creating new: %s', self._category)
        collection = Config.get_collection()
        collection = self._storage.create(collection)
        self.collection.migrate(collection)
Example #20
0
    def dump_completion(cls, complete):
        """Dump shell completion script into a file.

        Args:
            complete (str): Name of the shell for completion.
        """

        filename = Config.get_operation_file()
        path, _ = os.path.split(filename)
        cls._logger.debug('exporting: %s :completion: %s', Config.complete,
                          filename)
        if not os.path.exists(path) or not os.access(path, os.W_OK):
            Cause.push(
                Cause.HTTP_BAD_REQUEST,
                'cannot export: {} :completion file because path is not writable: {}'
                .format(complete, filename))
            return

        with open(filename, 'w') as outfile:
            try:
                outfile.write(Config.completion[Config.complete])
            except IOError as error:
                cls._logger.exception(
                    'fatal failure when creating {} shell completion file: {}',
                    filename, error)
                Cause.push(
                    Cause.HTTP_INTERNAL_SERVER_ERROR,
                    'fatal failure while exporting shell completion {}'.format(
                        filename))
Example #21
0
    def _get_schema_validator():
        """Get schema validator.

        Returns:
            obj: Jsonschema draft7 validator.
        """

        schema = Config.server_schema()
        Draft7Validator.check_schema(schema)
        resolver = RefResolver(base_uri=Config.server_schema_base_uri(),
                               referrer=schema)
        validator = Draft7Validator(schema,
                                    resolver=resolver,
                                    format_checker=None)

        return validator
Example #22
0
    def test_config_create_009():
        """Test that tags can be added so that they are separated by comma
        after the words like in '-t docker, container, cleanup'."""

        content = 'docker rm $(docker ps -a -q)'
        tags = ('cleanup', 'container', 'docker')
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'create', '-c', content, '-t', 'docker,',
                'container,', 'cleanup'
            ]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert Config.content_tags == tags
Example #23
0
    def import_all(self):
        """Import content."""

        if Config.defaults:
            self._logger.debug('importing all default content')
            collection = Migrate.load(
                Config.default_content_file(Const.SNIPPET))
            collection.migrate(
                Migrate.load(Config.default_content_file(Const.SOLUTION)))
            collection.migrate(
                Migrate.load(Config.default_content_file(Const.REFERENCE)))
            self._storage.import_content(collection)
        else:
            Cause.push(
                Cause.HTTP_BAD_REQUEST,
                'import operation for content category \'all\' is supported only with default content'
            )
Example #24
0
    def test_config_create_010():
        """Test that tags are accepted if they contain special characters."""

        content = 'docker rm $(docker ps -a -q)'
        tags = (u'cleanup_testing', u'container-managemenet',
                u'docker–testing')
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'create', '-c', content, '-t', 'docker–testing, ',
                'container-managemenet, ', 'cleanup_testing'
            ]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert Config.content_tags == tags
        assert len(Config.content_tags) == 3
Example #25
0
    def test_config_create_005():
        """Test that tags can be added inside quotes separated by comma and
        without spaces."""

        content = 'docker rm $(docker ps -a -q)'
        tags = ('cleanup', 'container', 'docker')
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'create', '-c', content, '-t',
                'docker,container,cleanup'
            ]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert not Config.content_brief
        assert Config.content_tags == tags
Example #26
0
    def test_config_create_011():
        """Test that tags are accepted if the tags are elements in a list.
        This might not be realistic case since user might not be able to
        reproduce this?"""

        content = 'docker rm $(docker ps -a -q)'
        tags = ('cleanup', 'container', 'docker')
        Config.init(None)
        Config.load(
            Cli([
                'snippy', 'create', '-c', content, '-t', 'docker', 'container',
                'cleanup'
            ]))
        assert isinstance(Config.content_data, tuple)
        assert isinstance(Config.content_brief, Const.TEXT_TYPE)
        assert isinstance(Config.content_tags, tuple)
        assert Config.content_data == tuple([content])
        assert Config.content_tags == tags
Example #27
0
    def dump(cls, collection, filename):
        """Dump collection into file."""

        if not Config.is_supported_file_format():
            cls._logger.debug('file format not supported for file %s',
                              filename)

            return

        if not collection:
            Cause.push(Cause.HTTP_NOT_FOUND, 'no content found to be exported')

            return

        cls._logger.debug('exporting contents %s', filename)
        with open(filename, 'w') as outfile:
            try:
                dictionary = {
                    'meta': {
                        'updated': Config.utcnow(),
                        'version': __version__,
                        'homepage': __homepage__
                    },
                    'data': collection.dump_dict(Config.remove_fields)
                }
                if Config.is_operation_file_text:
                    outfile.write(collection.dump_text(Config.templates))
                elif Config.is_operation_file_json:
                    json.dump(dictionary, outfile)
                    outfile.write(Const.NEWLINE)
                elif Config.is_operation_file_mkdn:
                    outfile.write(collection.dump_mkdn(Config.templates))
                elif Config.is_operation_file_yaml:
                    yaml.safe_dump(dictionary,
                                   outfile,
                                   default_flow_style=False)
                else:
                    cls._logger.debug('unknown export file format')
            except (IOError, TypeError, ValueError, yaml.YAMLError) as error:
                cls._logger.exception(
                    'fatal failure to generate formatted export file "%s"',
                    error)
                Cause.push(Cause.HTTP_INTERNAL_SERVER_ERROR,
                           'fatal failure while exporting content to file')
Example #28
0
    def dump_template(cls, category):
        """Dump content template into file."""

        filename = Config.get_operation_file()
        resource = Collection.get_resource(category, Config.utcnow())
        template = resource.get_template(category, Config.template_format,
                                         Config.templates)
        cls._logger.debug('exporting content template %s', filename)
        with open(filename, 'w') as outfile:
            try:
                outfile.write(template)
            except IOError as error:
                cls._logger.exception(
                    'fatal failure in creating %s template file "%s"',
                    category, error)
                Cause.push(
                    Cause.HTTP_INTERNAL_SERVER_ERROR,
                    'fatal failure while exporting template {}'.format(
                        filename))
Example #29
0
    def on_get(self, request, response, scat=None, sall=None, stag=None, sgrp=None):
        """Search unique groups.

        By default the search is made from all content categories.

        Args:
            request (obj): Falcon Request().
            response (obj): Falcon Response().
            scat (str): Search categories ``scat`` path parameter.
            sall (str): Search all ``sall`` path parameter.
            stag (str): Search tags ``stag`` path parameter.
            sgrp (str): Search groups ``sgrp`` path parameter.
        """

        self._logger.debug('run: %s %s', request.method, request.uri)
        if scat:
            request.params['scat'] = scat
        else:
            request.params['scat'] = Const.CATEGORIES

        if sall:
            request.params['sall'] = sall
        if stag:
            request.params['stag'] = stag
        if sgrp:
            request.params['sgrp'] = sgrp
        api = Api(self._category, Api.UNIQUE, request.params)
        Config.load(api)
        self._content.run()
        if not self._content.uniques:
            Cause.push(Cause.HTTP_NOT_FOUND, 'cannot find unique fields for groups attribute')
        if Cause.is_ok():
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.fields('groups', self._content.uniques, request, response)
            response.status = Cause.http_status()
        else:
            response.content_type = ApiResource.MEDIA_JSON_API
            response.body = Generate.error(Cause.json_message())
            response.status = Cause.http_status()

        Cause.reset()
        self._logger.debug('end: %s %s', request.method, request.uri)
Example #30
0
    def delete(self):
        """Delete content."""

        collection = self._storage.search(
            scat=Config.search_cat_kws,
            sall=Config.search_all_kws,
            stag=Config.search_tag_kws,
            sgrp=Config.search_grp_kws,
            search_filter=Config.search_filter,
            uuid=Config.operation_uuid,
            digest=Config.operation_digest,
            identity=Config.operation_identity,
            data=Config.content_data
        )
        if len(collection) == 1:
            resource = next(collection.resources())
            self._logger.debug('deleting: %s :with digest: %.16s', resource.category, resource.digest)
            self._storage.delete(resource.digest)
        else:
            Config.validate_search_context(collection, 'delete')