Ticket CLI

Description:
 A simple CLI for managing tickets and tasks in a terminal environment.
Uses a small .csv to store created tickets.

Usage:
 ticket <command> [arguments]

Commands:
 list,  -ls           List all tickets
 add,   -a  <text>    Add a new ticket
 del,   -d  <id>      Delete a ticket
 close, -c  <id>      Close a ticket
 open,  -o  <id>      Re-open a ticket
 help,  -h            Show this help

Examples:
 ticket add Buy milk
 ticket -a “Walk the dog”
 ticket close 3
 ticket del 7
 ticket list

Download ticket.sh

#!/bin/bash
#

#######################
# GLOBAL VARIABLES
########################
DATA_FILE="$HOME/.ticket.csv"
DELIM="%"
VERSION="1.6"

####################
# COLOUR VARIABLES
####################

# Terminal Formatting
RESET="\033[0m"
BOLD="\033[1m"

# UI Colours
CLR_ERROR="\033[38;5;196m"  # Bright Red
CLR_SUCCESS="\033[38;5;46m" # Bright Lime Green

CLR_INFO="\033[38;5;226m"         # Gold
CLR_ACTION="\033[38;5;141m"       # Light Purple / Lavender
CLR_LABEL="\033[38;5;81m"         # Bright Sky Blue
CLR_LABEL2="\033[38;5;2m"         # Dark Forest Green
CLR_PROMPT="${BOLD}\033[38;5;51m" # Aqua + Bold
CLR_TEXT="\033[38;5;254m"         # Light Grey
CLR_FRAME="\033[38;5;245m"        # Darker Grey

set -e

#######################
# Unicode box Chars
########################
H="─"
V="│"

TL="┌"
TR="┐"
BL="└"
BR="┘"

LT="├"
RT="┤"
TT="┬"
BT="┴"
CR="┼"

TH_FRAME="${CLR_FRAME}${TL}────${TT}─────────────────────${TT}────────${TT}───────────────────────────────────────────────────────────${TR}${RESET}"
MD_FRAME="${CLR_FRAME}${LT}────${CR}─────────────────────${CR}────────${CR}───────────────────────────────────────────────────────────${RT}${RESET}"
BH_FRAME="${CLR_FRAME}${BL}────${BT}─────────────────────${BT}────────${BT}───────────────────────────────────────────────────────────${BR}${RESET}"

ROW_PREFIX="${CLR_FRAME}${V}${RESET}"

############
# FUNCTIONS
#############

error() {
    echo
    echo -e "  ${CLR_ERROR}Error: ${RESET}$1"
    echo
}

ticket_action() {
    echo
    echo "────────────────────────"
    echo -e " ▶ ${1}Ticket (${RESET}${BOLD}${2}${RESET}${1}) ${3}${RESET}"
    echo "────────────────────────"
}

next_id() {

    if [[ ! -s "$DATA_FILE" ]]; then
        echo 1
        return
    fi

    awk -F'%' '
        $1 > max { max = $1 }
        END { print max + 1 }
    ' "$DATA_FILE"
}

cmd_list() {

    if [[ ! -s "$DATA_FILE" ]]; then
        touch "$DATA_FILE"
    fi

    local FMT="$ROW_PREFIX %2s $ROW_PREFIX %-19s $ROW_PREFIX %-6s $ROW_PREFIX %-47s $ROW_PREFIX\n"

    echo
    echo -e "${TH_FRAME}"

    printf "$FMT" "ID" "DATE" "STATE" "TICKET"
    printf "%b" "$RESET"
    echo -e "${MD_FRAME}"

    if [[ ! -s "$DATA_FILE" ]]; then
        echo " No current tickets"
        echo -e "${MD_FRAME}"
    fi

    #framing check
    first=1

    while IFS="$DELIM" read -r id status datetime ticket; do

        # Ifs to determine framing
        if ((!first)); then
            echo -e "${MD_FRAME}"
        fi
        first=0

        # Setup Ticket Contents
        printf "$ROW_PREFIX %2s $ROW_PREFIX %-19s $ROW_PREFIX " \
            "$id" "$datetime"

        #Ticket Colouring
        if [[ "$status" == "OPEN" ]]; then
            printf "%b%-6s%b" "$CLR_SUCCESS" "$status" "$RESET"
        else
            printf "%b%-6s%b" "$CLR_ERROR" "$status" "$RESET"
        fi

        # Ticket Description
        printf " $ROW_PREFIX %s\n" "$ticket"

    done <"$DATA_FILE"

    echo -e "${BH_FRAME}"
    echo

}

cmd_add() {
    id=$(next_id)
    status="OPEN"
    datetime="$(date '+%Y-%m-%d / %H:%M')"
    ticket="$*"

    printf '%s%s%s%s%s%s%s\n' \
        "$id" "$DELIM" \
        "$status" "$DELIM" \
        "$datetime" "$DELIM" \
        "$ticket" >>"$DATA_FILE"

    ticket_action ${CLR_SUCCESS} ${id} "Created"
}

cmd_delete() {
    local delete_id="$1"

    #
    # Ensure the ID is numerical & Exists
    #

    # If Blank
    if [[ -z "$delete_id" ]]; then
        error "No Ticket ID Specified"
        echo "  Usage: ticket -d <id>"
        echo
        return 1
    fi

    # IF input isn't a number
    if [[ ! $delete_id =~ ^[0-9]+$ ]]; then
        error "${delete_id} is not a numerical value"
        exit
    fi

    # If delete_id is 5, this searches specifically for "^5%"
    # to ensure the delete_id exists in $DATA_FILE
    if grep -q "^${delete_id}${DELIM}" "$DATA_FILE"; then

        #
        # Finish checks - continue Deleting
        #

        while IFS="$DELIM" read -r id status datetime ticket; do
            if [[ "$id" != "$delete_id" ]]; then
                printf '%s%%%s%%%s%%%s\n' \
                    "$id" "$status" "$datetime" "$ticket"
            fi
        done <"$DATA_FILE" >"$DATA_FILE.tmp"

        mv "$DATA_FILE.tmp" "$DATA_FILE"

        ticket_action ${CLR_ERROR} ${delete_id} "Deleted"

    else
        error "Ticket '$delete_id' does not exist."
    fi
}

cmd_open() {
    local open_id="$1"

    # If Blank
    if [[ -z "$open_id" ]]; then
        error "No Ticket ID Specified"
        echo "  Usage: ticket -o <id>"
        echo
        return 1
    fi

    # IF input isn't a number
    if [[ ! $open_id =~ ^[0-9]+$ ]]; then
        error "${open_id} is not a numerical value"
        return 1
    fi

    if grep -q "^${open_id}${DELIM}" "$DATA_FILE"; then

        # Create the tempfile
        >"$DATA_FILE.tmp"

        while IFS="$DELIM" read -r id status datetime ticket; do
            if [[ "$id" == "$open_id" ]]; then
                if [[ "$status" == "OPEN" ]]; then
                    ticket_action "$CLR_ERROR" "$open_id" "Already Open"
                    echo
                    exit 0
                else
                    status="OPEN"
                fi
            fi

            #Append data to the temp file
            printf '%s%%%s%%%s%%%s\n' \
                "$id" "$status" "$datetime" "$ticket" >>"$DATA_FILE.tmp"
        done <"$DATA_FILE"

        #overwrite our csv
        mv "$DATA_FILE.tmp" "$DATA_FILE"
        ticket_action "$CLR_SUCCESS" "$open_id" "Opened"
        echo
    else
        error "Ticket '$open_id' does not exist."
    fi
}

cmd_close() {
    local close_id="$1"

    # If Blank
    if [[ -z "$close_id" ]]; then
        error "No Ticket ID Specified"
        echo "  Usage: ticket -c <id>"
        echo
        return 1
    fi

    # IF input isn't a number
    if [[ ! $close_id =~ ^[0-9]+$ ]]; then
        error "${close_id} is not a numerical value"
        return 1
    fi

    if grep -q "^${close_id}${DELIM}" "$DATA_FILE"; then

        # Create the tempfile
        >"$DATA_FILE.tmp"

        while IFS="$DELIM" read -r id status datetime ticket; do
            if [[ "$id" == "$close_id" ]]; then
                if [[ "$status" == "CLOSED" ]]; then
                    ticket_action "$CLR_ERROR" "$close_id" "Already Closed"
                    echo
                    exit 0
                else
                    status="CLOSED"
                fi
            fi

            printf '%s%%%s%%%s%%%s\n' \
                "$id" "$status" "$datetime" "$ticket" >>"$DATA_FILE.tmp"
        done <"$DATA_FILE"

        mv "$DATA_FILE.tmp" "$DATA_FILE"
        ticket_action "$CLR_ERROR" "$close_id" "Closed"
        echo
    else
        error "Ticket '$close_id' does not exist."
    fi
}

usage() {
    echo -e "${BOLD}Odi's Ticket CLI v${VERSION}${RESET}"
    echo
    echo -e "${BOLD}Description:${RESET}"
    echo -e "${CLR_TEXT}  A simple CLI for managing tickets and tasks.${RESET}"
    echo
    echo -e "${BOLD}Usage:${RESET}"
    echo -e "  ${CLR_TEXT}ticket <command> [arguments]${RESET}"
    echo

    echo -e "${BOLD}Commands:${RESET}"
    echo -e "${CLR_TEXT}  list,  -ls           List all tickets"
    echo -e "  add,   -a  <text>    Add a new ticket"
    echo -e "  del,   -d  <id>      Delete a ticket"
    echo -e "  close, -c  <id>      Close a ticket"
    echo -e "  open,  -o  <id>      Re-open a ticket"
    echo -e "  help,  -h            Show this help${RESET}"
    echo

    echo -e "${BOLD}Examples:${RESET}"
    echo -e "${CLR_TEXT}  ticket add Buy milk"
    echo -e "  ticket -a \"Walk the dog\""
    echo -e "  ticket close 3"
    echo -e "  ticket del 7"
    echo -e "  ticket list${RESET}"
    echo
}

#############
# COMMANDS
##############

if [[ $# -eq 0 ]]; then
    usage
    exit 0
fi

case "${1:-}" in
    add | -a)
        shift
        cmd_add "$@"
        ;;

    delete | del | -d)
        shift
        cmd_delete "$1"
        ;;

    close | -c)
        shift
        cmd_close "$@"
        ;;

    open | -o)
        shift
        cmd_open "$@"
        ;;

    list | -ls)
        shift
        cmd_list "$@"
        ;;

    help | -h | --help)
        usage
        ;;

    *)
        echo "Unknown command."
        usage
        exit 1
        ;;
esac