Exemple #1
0
def edit(args: Dict[str, str], config: Dict[str, str]):
    """
    Edit the content of an artifact.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> the IDs (the one you see with kb list)
                        associated to the artifact we want to edit
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    initializer.init(config)

    # if an ID is specified, load artifact with that ID
    if args["id"]:
        edit_by_id(args["id"], config)

    # else if a title is specified
    elif args["title"]:
        edit_by_name(args["title"], args["category"], config)

    # else try to guess
    elif args["nameid"]:
        if args["nameid"].isdigit():
            edit_by_id(args["nameid"], config)
        else:
            edit_by_name(args["nameid"], args["category"], config)
Exemple #2
0
def apply_on_set(args: Dict[str, str], config: Dict[str, str]):
    """
    Apply the specified template to all the filtered artifacts
    """
    # Check initialization
    initializer.init(config)

    tags_list = None
    if args["tags"] and args["tags"] != "":
        tags_list = args["tags"].split(';')

    conn = db.create_connection(config["PATH_KB_DB"])
    is_query_strict = not args["extended_match"]
    rows = db.get_artifacts_by_filter(conn,
                                      title=args["title"],
                                      category=args["category"],
                                      tags=tags_list,
                                      status=args["status"],
                                      author=args["author"],
                                      is_strict=is_query_strict)

    for artifact in rows:
        updated_artifact = Artifact(id=artifact.id,
                                    title=artifact.title,
                                    category=artifact.category,
                                    tags=artifact.tags,
                                    author=artifact.author,
                                    status=artifact.status,
                                    template=args["template"])
        db.update_artifact_by_id(conn, artifact.id, updated_artifact)
Exemple #3
0
def delete(args: Dict[str, str], config: Dict[str, str]):
    """
    Delete a list of artifacts from the kb knowledge base.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> a list of IDs (the ones you see with kb list)
                        associated to the artifacts we want to delete
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    db_id:          - True if this is a raw DB id, 
                      False if this is a viewed artifact IDs
    """
    initializer.init(config)

    response = delete_artifacts(args, config, False)

    if response == -200:
        print("Artifact removed.")
    
    if response == -301:
        print("There is more than one artifact with that title, please specify a category")
    
    if response == -302:
        print("There is no artifact with that name, please specify a correct artifact name")
Exemple #4
0
def template(args: Dict[str, str], config: Dict[str, str]):
    """
    Manage templates for kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      template_command -> the sub-command to execute for templates
                                          that can be: "add", "delete", "edit",
                                          "list" or "new".
                      file -> used if the command is add, representing the template
                              file to add to kb
                      template -> used if the command is "delete", "edit" or "new" 
                                  to represent the name of the template
                      query -> used if the command is "list"
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DEFAULT_TEMPLATE - the path to the kb default template
                      PATH_KB_TEMPLATES        - the path to kb templates
                      EDITOR                   - the editor program to call
    """

    # Check initialization
    initializer.init(config)

    COMMANDS[args["template_command"]](args, config)
Exemple #5
0
def add(args: Dict[str, str], config: Dict[str, str]):
    """
    Adds a list of artifacts to the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      file -> a list of files to add to kb
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
                      tags -> the tags assigned to the artifact(s)
                      author -> the author to assign to the artifact
                      status -> the status to assign to the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      EDITOR            - the editor program to call
    """
    # Check if the add command has proper arguments/options
    is_valid_add = args["file"] or args["title"]
    if not is_valid_add:
        print("Please, either specify a file or a title for the new artifact")
        sys.exit(1)

    # Check initialization
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])
    if args["file"]:
        for fname in args["file"]:
            if fs.is_directory(fname):
                continue
            add_file_to_kb(conn, args, config, fname)
    else:
        # Get title for the new artifact
        title = args["title"]

        # Assign a "default" category if not provided
        category = args["category"] or "default"

        # Create "category" directory if it does not exist
        category_path = Path(config["PATH_KB_DATA"], category)
        category_path.mkdir(parents=True, exist_ok=True)

        if not db.is_artifact_existing(conn, title, category):
            # If a file is provided, copy the file to kb directory
            # otherwise open up the editor and create some content
            shell_cmd = shlex.split(
                config["EDITOR"]) + [str(Path(category_path, title))]
            call(shell_cmd)

        new_artifact = Artifact(id=None,
                                title=title,
                                category=category,
                                path="{category}/{title}".format(
                                    category=category, title=title),
                                tags=args["tags"],
                                status=args["status"],
                                author=args["author"])
        db.insert_artifact(conn, new_artifact)
Exemple #6
0
def view(args: Dict[str, str], config: Dict[str, str]):
    """
    View an artifact contained in the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> the IDs (the one you see with kb list)
                        associated to the artifact to view
                      title -> the title of the artifact to view
                      category -> the category of the artifact to view
                      editor -> a boolean, if True the file will
                        be opened in a text editor as a temporary file
                        hence the original will not be affected
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      PATH_KB_MARKERS   - the file associated to the markers
                      EDITOR            - the editor program to call
    """
    # Check initialization
    initializer.init(config)

    color_mode = not args["no_color"]
    if args["id"]:
        view_by_id(args["id"], config, args["editor"], color_mode)
    elif args["title"]:
        view_by_name(args["title"], args["category"], config, args["editor"],
                     color_mode)
Exemple #7
0
def update_artifact(conn, old_artifact: Artifact, args: Dict[str, str], config: Dict[str, str], attachment):
    """
    Update artifact properties within the knowledge base of kb.

    Arguments:
    old_artifact:   - an object of type Artifact containing the old artifact details
    args:           - a dictionary containing the following fields:
                      id -> an id of an artifact - note - the ACTUAL db_id
                      title -> the title to be assigned to the artifact
                        to update
                      category -> the category to be assigned to the
                        artifact to update
                      tags -> the tags to be assigned to the artifact
                        to update
                      author -> the author to be assigned to the artifact
                        to update
                      status -> the status to be assigned to the artifact
                        to update
                      template -> the template to be assigned to the artifact
                        to update
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    attachment:     - new file content
"""
    initializer.init(config)

    template_name = args.get("template", "")
    updated_artifact = Artifact(
        id=None,
        title=args.get("title", old_artifact.title),
        category=args.get("category", old_artifact.category),
        tags=args.get("tags", old_artifact.tags),
        author=args.get("author", old_artifact.author),
        status=args.get("status", old_artifact.status),
        template=args.get("template", old_artifact.template),
        path=args.get("category", old_artifact.category) + '/' + args.get("title", old_artifact.title)
    )
    db.update_artifact_by_id(conn, old_artifact.id, updated_artifact)
    # If either title or category has been changed, we must move the file
    if args["category"] or args["title"]:
        old_category_path = Path(
            config["PATH_KB_DATA"],
            old_artifact.category)
        new_category_path = Path(
            config["PATH_KB_DATA"],
            args["category"] or old_artifact.category)
        fs.create_directory(new_category_path)

        fs.move_file(Path(old_category_path, old_artifact.title), Path(
            new_category_path, args["title"] or old_artifact.title))
        return -200
Exemple #8
0
def edit(args: Dict[str, str], config: Dict[str, str]):
    """
    Edit the content of an artifact.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> the IDs (the one you see with kb list)
                        associated to the artifact we want to edit
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])
    # if an ID is specified, load artifact with that ID
    if args["id"]:
        artifact = history.get_artifact(conn, config["PATH_KB_HIST"],
                                        args["id"])

        category_path = Path(config["PATH_KB_DATA"], artifact.category)

        shell_cmd = config["EDITOR"].split() + [
            Path(category_path, artifact.title)
        ]
        call(shell_cmd)

    # else if a title is specified
    elif args["title"]:
        artifacts = db.get_artifacts_by_filter(conn,
                                               title=args["title"],
                                               category=args["category"],
                                               is_strict=True)

        if len(artifacts) == 1:
            artifact = artifacts.pop()
            category_path = Path(config["PATH_KB_DATA"], artifact.category)
            shell_cmd = config["EDITOR"].split() + [
                Path(category_path, artifact.title)
            ]
            call(shell_cmd)
        elif len(artifacts) > 1:
            print(
                "There is more than one artifact with that title, please specify a category"
            )
        else:
            print(
                "There is no artifact with that name, please specify a correct artifact name"
            )
Exemple #9
0
def search_kb(args: Dict[str, str], config: Dict[str, str]):
    """
    Search artifacts within the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      query -> filter for the title field of the artifact
                      category -> filter for the category field of the artifact
                      tags -> filter for the tags field of the artifact
                      author -> filter for the author field of the artifact
                      status -> filter for the status field of the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    # Check initialization
    initializer.init(config)


    conn = db.create_connection(config["PATH_KB_DB"])
    
    categories = ls.list_categories(config)
    print(categories)

    # List all categories
    if args.get("all_categories", False) is True:
        categories = ls.list_categories(config)
        return categories
    
    # List all categories
    if args.get("all_tags", False) is True:
        all_tags = ls.list_tags(conn, config)
        return all_tags

    tags_list = None
    if args.get("tags",False) is True:
        if args["tags"] and args["tags"] != "":
            tags_list = args["tags"].split(';')

    rows = db.get_artifacts_by_filter(
        conn,
        title=args.get("query",''),
        category=args.get("category",''),
        tags=tags_list,
        status=args.get("status",''),
        author=args.get("author",''))

    
    artifacts = sorted(rows, key=lambda x: x.title)
    return artifacts
Exemple #10
0
def delete(args: Dict[str, str], config: Dict[str, str]):
    """
    Delete a list of artifacts from the kb knowledge base.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> a list of IDs (the ones you see with kb list)
                        associated to the artifacts we want to delete
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    if args["id"]:
        for i in args["id"]:
            artifact_id = history.get_artifact_id(config["PATH_KB_HIST"], i)
            artifact = db.get_artifact_by_id(conn, artifact_id)

            if not artifact:
                continue

            db.delete_artifact_by_id(conn, artifact_id)

            category_path = Path(config["PATH_KB_DATA"], artifact.category)

            Path(category_path, artifact.title).unlink()
            if fs.count_files(category_path) == 0:
                fs.remove_directory(category_path)

            print("Artifact {category}/{title} removed!".format(
                category=artifact.category, title=artifact.title))
        sys.exit(0)

    # else if a title is specified
    elif args["title"]:
        artifacts = db.get_artifacts_by_filter(conn, title=args["title"],
                                               category=args["category"],
                                               is_strict=True)
        if len(artifacts) == 1:
            artifact = artifacts.pop()
            db.delete_artifact_by_id(conn, artifact.id)
            print("Artifact {}/{} removed!".format(artifact.category, artifact.title))
        else:
            print(
                "There is more than one artifact with that title, please specify a category")
Exemple #11
0
def search(args: Dict[str, str], config: Dict[str, str]):
    """
    Search artifacts within the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      query -> filter for the title field of the artifact
                      category -> filter for the category field of the artifact
                      tags -> filter for the tags field of the artifact
                      author -> filter for the author field of the artifact
                      status -> filter for the status field of the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    # Check initialization
    initializer.init(config)

    tags_list = None
    if args["tags"] and args["tags"] != "":
        tags_list = args["tags"].split(';')

    conn = db.create_connection(config["PATH_KB_DB"])
    rows = db.get_artifacts_by_filter(
        conn,
        title=args["query"],
        category=args["category"],
        tags=tags_list,
        status=args["status"],
        author=args["author"])

    # rows.sort(key=lambda x: x[1])
    artifacts = sorted(rows, key=lambda x: x.title)

    # Write to history file
    history.write(config["PATH_KB_HIST"], artifacts)

    # Is full_identifier mode enabled?
    if args["full_identifier"]:
        printer.print_search_result_full_mode(artifacts)
        return

    # Print resulting list
    color_mode = not args["no_color"]
    if args["verbose"]:
        printer.print_search_result_verbose(artifacts, color_mode)
    else:
        printer.print_search_result(artifacts, color_mode)
Exemple #12
0
def add(args: Dict[str, str], config: Dict[str, str]):
    """
    Adds a list of artifacts to the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      file -> a list of files to add to kb
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
                      tags -> the tags assigned to the artifact(s)
                      author -> the author to assign to the artifact
                      status -> the status to assign to the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      EDITOR            - the editor program to call
    """
    # Check if the add command has proper arguments/options
    is_valid_add = args["file"] or args["title"]
    if not is_valid_add:
        print("Please, either specify a file or a title for the new artifact")
        sys.exit(1)

    # Check initialization
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    if args["file"]:
        for fname in args["file"]:
            if fs.is_directory(fname):
                continue
            add_file_to_kb(conn, args, config, fname)
    else:

        if not db.is_artifact_existing(conn, args["title"], args["category"]):
            pass
        else:
            with tempfile.NamedTemporaryFile(delete=True) as f:
                shell_cmd = shlex.split(config["EDITOR"]) + [f]
                call(shell_cmd)
                args["temp_file"] = f

        result = add_artifact(conn, args, config)
        return (result)
Exemple #13
0
def delete(args: Dict[str, str], config: Dict[str, str]):
    """
    Delete a list of artifacts from the kb knowledge base.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> a list of IDs (the ones you see with kb list)
                        associated to the artifacts we want to delete
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    """
    initializer.init(config)

    if args["id"]:
        for i in args["id"]:
            delete_by_id(i, config)

    elif args["title"]:
        delete_by_name(args["title"], args["category"], config)
Exemple #14
0
def grep(args: Dict[str, str], config: Dict[str, str]):
    """
    Grep through the list of artifacts of the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      regex -> the regex to search for
                      case_insensitive -> a boolean, if true,
                        the search will be case insensitive
                      matches -> a boolean, if true, only the raw
                        matches will be shown
                      verbose -> a boolean, if true, a verbose
                        output is produced on screen
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    # Get all artifacts
    rows = db.get_artifacts_by_filter(conn, title="")

    # Get all the file paths related to the artifacts in the database
    file_list = [Path(config["PATH_KB_DATA"], r.category, r.title)
                 for r in rows]

    # Grep in the files
    results = fs.grep_in_files(
        file_list,
        args["regex"],
        args["case_insensitive"])

    # Get the list of artifact tuples in the form (category,title)
    artifact_names = [fs.get_filename_parts_wo_prefix(
        res[0], config["PATH_KB_DATA"]) for res in results]

    # If user specied --matches -> just show matching lines and exit
    if args["matches"]:
        printer.print_grep_matches(artifact_names)
        sys.exit(0)

    # Get the set of uniq artifacts
    uniq_artifact_names = set(artifact_names)

    # Get the number of matches (hits) for each path found
    filecounts = get_hits_per_artifact_name(artifact_names)

    grep_result = list()

    for art in uniq_artifact_names:
        artifact = db.get_artifacts_by_filter(
            conn, category=art[0], title=art[1])[0]
        if artifact:
            no_of_hits = filecounts[art]
            grep_result.append((artifact, no_of_hits))

    # Sort by number of hits, the largest -> the first
    grep_result.sort(key=lambda x: x[1], reverse=True)

    grep_artifacts = [r[0] for r in grep_result]
    grep_hits = [r[1] for r in grep_result]

    # Write to history file
    history.write(config["PATH_KB_HIST"], grep_artifacts)

    color_mode = not args["no_color"]
    if args["verbose"]:
        printer.print_grep_result_verbose(
            grep_artifacts, grep_hits, color_mode)
    else:
        printer.print_grep_result(grep_artifacts, grep_hits, color_mode)
Exemple #15
0
def update(args: Dict[str, str], config: Dict[str, str]):
    """
    Update artifact properties within the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> a list of IDs (the ones you see with kb list)
                        associated to the artifact to update
                      title -> the title to be assigned to the artifact
                        to update
                      category -> the category to be assigned to the
                        artifact to update
                      tags -> the tags to be assigned to the artifact
                        to update
                      author -> the author to be assigned to the artifact
                        to update
                      status -> the status to be assigned to the artifact
                        to update
                      template -> the template to be assigned to the artifact
                        to update
                      edit_content -> a boolean, if True -> also open the
                        artifact to edit the content
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    # if an ID is specified, load artifact with that ID
    if args["id"]:
        old_artifact = history.get_artifact(conn, config["PATH_KB_HIST"],
                                            args["id"])
        if not old_artifact:
            print("The artifact you are trying to update does not exist! "
                  "Please insert a valid ID...")
            return None

        updated_artifact = Artifact(id=None,
                                    title=args["title"],
                                    category=args["category"],
                                    tags=args["tags"],
                                    author=args["author"],
                                    status=args["status"],
                                    template=args["template"])

        db.update_artifact_by_id(conn, old_artifact.id, updated_artifact)
        # If either title or category has been changed, we must move the file
        if args["category"] or args["title"]:
            old_category_path = Path(config["PATH_KB_DATA"],
                                     old_artifact.category)
            new_category_path = Path(config["PATH_KB_DATA"], args["category"]
                                     or old_artifact.category)
            fs.create_directory(new_category_path)

            fs.move_file(
                Path(old_category_path, old_artifact.title),
                Path(new_category_path, args["title"] or old_artifact.title))
    # else if a title is specified
    elif args["title"]:
        artifact = db.get_uniq_artifact_by_filter(conn,
                                                  title=args["title"],
                                                  category=args["category"],
                                                  author=args["author"],
                                                  status=args["status"],
                                                  is_strict=True)

        if artifact:
            category_path = Path(config["PATH_KB_DATA"], artifact.category)
        else:
            print(
                "There is none or more than one artifact with that title, please specify a category"
            )

    if args["edit_content"] or args["body"]:
        if args["title"]:
            artifact_path = str(Path(category_path, artifact.title))
            shell_cmd = shlex.split(config["EDITOR"]) + [artifact_path]
        elif args["id"]:
            artifact_path = str(
                Path(config["PATH_KB_DATA"]) / old_artifact.category /
                old_artifact.title)
            shell_cmd = shlex.split(config["EDITOR"]) + [artifact_path]

        if args["body"]:
            args["body"] = args["body"].replace("\\n", "\n")
            with open(artifact_path, 'w') as art_file:
                art_file.write(args["body"])
        else:
            call(shell_cmd)
Exemple #16
0
def view(args: Dict[str, str], config: Dict[str, str]):
    """
    View an artifact contained in the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> the IDs (the one you see with kb list)
                        associated to the artifact to view
                      title -> the title of the artifact to view
                      category -> the category of the artifact to view
                      editor -> a boolean, if True the file will
                        be opened in a text editor as a temporary file
                        hence the original will not be affected
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      PATH_KB_MARKERS   - the file associated to the markers
                      EDITOR            - the editor program to call
    """
    # Check initialization
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    if args["id"]:
        artifact_id = history.get_artifact_id(
            config["PATH_KB_HIST"], args["id"])

        artifact = db.get_artifact_by_id(conn, artifact_id)

        if not artifact:
            sys.exit(1)

        category_path = Path(config["PATH_KB_DATA"], artifact.category)
        artifact_path = Path(category_path, artifact.title)

        if args["editor"]:
            with tempfile.NamedTemporaryFile() as tmpfname:
                fs.copy_file(artifact_path, tmpfname.name)
                call([config["EDITOR"], tmpfname.name])
            sys.exit(0)

        # View File
        if fs.is_text_file(artifact_path):
            markers = get_markers(config["PATH_KB_MARKERS"])
            color_mode = not args["no_color"]
            viewer.view(artifact_path, markers, color=color_mode)
        else:
            opener.open_non_text_file(artifact_path)

    elif args["title"]:
        artifact = db.get_uniq_artifact_by_filter(conn, title=args["title"],
                                                  category=args["category"],
                                                  is_strict=True)
        if artifact:
            category_path = Path(config["PATH_KB_DATA"], artifact.category)
            artifact_path = Path(category_path, artifact.title)

            content = ""
            if args["editor"]:
                call([config["EDITOR"], artifact_path])
                sys.exit(0)

            # View File
            if fs.is_text_file(artifact_path):
                markers = get_markers(config["PATH_KB_MARKERS"])
                color_mode = not args["no_color"]
                viewer.view(artifact_path, markers, color=color_mode)
            else:
                opener.open_non_text_file(artifact_path)
        else:
            print(
                "There is no artifact with that title, please specify a category")