diff --git a/database/kwdb.sql b/database/kwdb.sql index 68b7189f7..e18e7c8ef 100644 --- a/database/kwdb.sql +++ b/database/kwdb.sql @@ -20,6 +20,32 @@ CREATE TABLE IF NOT EXISTS "command_label" ( PRIMARY KEY("id") ); +-- Table containing the kw email groups infos +CREATE TABLE IF NOT EXISTS "email_group" ( + "id" INTEGER NOT NULL UNIQUE, + "name" VARCHAR(50) NOT NULL UNIQUE, + "created_at" TEXT DEFAULT (date('now', 'localtime')), + PRIMARY KEY("id") +); + +-- Table containing the kw email contacts infos +CREATE TABLE IF NOT EXISTS "email_contact" ( + "id" INTEGER NOT NULL UNIQUE, + "name" VARCHAR(100) NOT NULL, + "email" VARCHAR(100) NOT NULL UNIQUE, + "created_at" TEXT DEFAULT (date('now', 'localtime')), + PRIMARY KEY("id") +); + +-- Table containing the association between a kw email group and it's contacts +CREATE TABLE IF NOT EXISTS "email_contact_group" ( + "contact_id" INTEGER, + "group_id" INTEGER, + PRIMARY KEY ("contact_id", "group_id"), + FOREIGN KEY ("contact_id") REFERENCES "email_contact"("id") ON DELETE CASCADE, + FOREIGN KEY ("group_id") REFERENCES "email_group"("id") ON DELETE CASCADE +); + -- Table containing the possible exit status of an executed commmand CREATE TABLE IF NOT EXISTS "status" ( "id" INTEGER NOT NULL UNIQUE, @@ -237,4 +263,13 @@ CREATE TRIGGER IF NOT EXISTS "insert_statistics" INSTEAD OF INSERT ON "statistic ); END; +CREATE TRIGGER IF NOT EXISTS "delete_contact_if_no_group" +AFTER DELETE ON "email_contact_group" +FOR EACH ROW +WHEN (SELECT COUNT(*) FROM "email_contact_group" WHERE "contact_id" = OLD.contact_id) = 0 +BEGIN + DELETE FROM "email_contact" WHERE "id" = OLD.contact_id; +END; + + COMMIT; diff --git a/documentation/conf.py b/documentation/conf.py index 83a930351..50da6cb95 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -181,6 +181,7 @@ ('man/features/kw-self-update', 'kw-self-update', 'kw self-update mechanism', ['David Tadokoro, Everaldo Junior'], 1), ('man/features/kw-patch-hub', 'kw-patch-hub', 'Terminal UI to interact with patches from lore.kernel.org', ['David Tadokoro, Rodrigo Siqueira'], 1), ('man/features/kw-bd', 'kw-bd', 'build and then deploy the kernel', ['Briza Mel de Sousa, Lorenzo Salvador'], 1), + ('man/features/kw-manage-contacts', 'kw-manage-contacts', 'create and manage email groups', ['João Guilherme Barbosa de Souza'], 1), ] diff --git a/documentation/man/features/kw-manage-contacts.rst b/documentation/man/features/kw-manage-contacts.rst new file mode 100644 index 000000000..fc02dec50 --- /dev/null +++ b/documentation/man/features/kw-manage-contacts.rst @@ -0,0 +1,93 @@ +============================================= +kw-manage-contacts - Manage groups of emails +============================================= + +.. _manage-contacts-doc: + +SYNOPSIS +======== + | *kw manage-contacts* (-c | \--group-create) [] + | *kw manage-contacts* (-r | \--group-remove) [] + | *kw manage-contacts* \--group-rename "[]:[]" + | *kw manage-contacts* \--group-add "[]:[] <[]>, ..." + | *kw manage-contacts* \--group-remove-email "[]:[] <[]>, ..." + | *kw manage-contacts* \--group-show=[] + +DESCRIPTION +=========== + +The `kw manage-contacts` is an email group manager feature that provides a comprehensive +interface for managing email groups, streamlining the process of organizing and +maintaining contact lists. This feature allows users to: + +- Create new email groups +- Delete existing email groups +- Add contacts to a group +- Remove contacts from a group +- Rename email groups +- View all groups +- View contacts within a specific group + +By integrating with the `kw send-patches` feature, email group manager simplifies +the patch submission process by making it possible to send a patch directly to a +group of contacts. Furthermore, it also guarantees the possibility of saving a +group after sending a patch. + +OPTIONS +======= +-c, \--group-create []: + Create a new group with the specified name. The group will be stored in the + email_group table, which contains the group ID, name, and creation date. + +-r, \--group-remove []: + Remove an existing group with the specified name. This action deletes the + group from the email_group table and also removes the associated contacts + in the email_contact_group table. + +\--group-rename "[]:[]": + Rename an existing group from old_name to new_name. The change will be reflected + in the email_group table. + +\--group-add "[]:[] <[]>, [] <[]>, ...": + Add contacts to an existing group. Contacts are stored in the email_contact + table and the association between contacts and groups is stored in the + email_contact_group table. + +\--group-remove-email "[]:[] <[]>, [] <[]>, ...": + Remove contacts from an existing group. This action updates the + email_contact_group table to reflect the removal. + +\--group-show[=]: + Show all existing groups or contacts of a specific group if group_name is + provided. Group information is retrieved from the email_group + table and contact information from the email_contact table. + +EXAMPLES +======== +To create a new group named "NewGroup":: + + kw manage-contacts -c "NewGroup" + +To remove an existing group named "OldGroup":: + + kw manage-contacts -r "OldGroup" + +To rename an existing group from "OldGroup" to "NewGroup":: + + kw manage-contacts --group-rename "OldGroup" + +To add contacts (John Doe and Jane Smith) to an existing group named "ExistingGroup":: + + kw manage-contacts --group-add "ExistingGroup: John Doe john.doe@example.com, Jane Smith jane.smith@example.com" + +To remove John Doe from an existing group named "ExistingGroup":: + + kw manage-contacts --group-remove-email "ExistingGroup John Doe john.doe@example.com" + +To display all existing email groups:: + + kw manage-contacts --group-show + +To display contacts of a specific group named "ExistingGroup":: + + kw manage-contacts --group-show=ExistingGroup diff --git a/documentation/man/features/kw-send-patch.rst b/documentation/man/features/kw-send-patch.rst index e310b95b4..327a0374c 100644 --- a/documentation/man/features/kw-send-patch.rst +++ b/documentation/man/features/kw-send-patch.rst @@ -6,7 +6,7 @@ kw send-patch - Send patches through mail SYNOPSIS ======== -| *kw send-patch* (-s | \--send) [\--simulate] [\--private] [\--rfc] [\--to=',...'] [\--cc=',...'] [...] [-v] [\-- ...] +| *kw send-patch* (-s | \--send) [\--simulate] [\--private] [\--rfc] [\--to=',...'] [\--cc=',...'] [\--to-groups=',...'] [\--cc-groups=',...'] [...] [-v] [\-- ...] | *kw send-patch* (-t | \--setup) [\--local | \--global] [-f | \--force] ( )... | *kw send-patch* (-i | \--interactive) [\--local | \--global] | *kw send-patch* (-l | \--list) @@ -44,10 +44,10 @@ OPTIONS ======= -s, \--send: Send a patch by email using ``git send-email`` to the email addresses - specified with ``--to`` and ``--cc``. You can provide ** to be - passed directly to ``git send-email``, they should be placed after the double - dash (``--``) argument. By default this function assumes these arguments to - ``git send-email``:: + specified with ``--to`` and ``--cc`` or the contacts group specified with ``to-groups`` + and ``cc-groups``. You can provide ** to be passed directly to + ``git send-email``, they should be placed after the double dash (``--``) argument. + By default this function assumes these arguments to ``git send-email``:: --annotate --cover-letter --no-chain-reply-to --thread @@ -63,6 +63,14 @@ OPTIONS \--cc=',...': Specify the recipients that will receive a copy of the patch via e-mail. +\--to-groups=',...': + Specify the groups recipients that contain the email of the users that + will receive the patch via e-mail. The ** list can be any + of the groups created using the ``kw manage-contacts`` feature. + +\--cc-groups=',...': + Specify the groups recipients that will receive a copy of the patch via e-mail. + \--simulate: Do everything without actually sending the e-mail. This is similar to ``git send-email``'s ``--dry-run`` option. @@ -140,6 +148,9 @@ To simulate sending the last commit as a patch just write:: kw send-patch --send --simulate --to=some@email.com +To simulate sending the last commit as a patch to a group you can use:: + kw send-patch --send --simulate --to-groups=somegroup + Then when you are sure the command executed as expected, drop the ``--simulate`` argument to actually send the patch:: diff --git a/kw b/kw index a9089a226..34df0f818 100755 --- a/kw +++ b/kw @@ -303,6 +303,13 @@ function kw() kworkflow_man "$@" ) ;; + manage-contacts) + ( + include "${KW_LIB_DIR}/kw_manage_contacts.sh" + + manage_contacts_main "$@" + ) + ;; help | --help) ( include "${KW_LIB_DIR}/help.sh" diff --git a/src/help.sh b/src/help.sh index ffd0e5a6f..847f3d919 100644 --- a/src/help.sh +++ b/src/help.sh @@ -29,6 +29,7 @@ function kworkflow_help() ' backup - Save or restore kw data' \ ' debug - Linux kernel debug utilities' \ ' send-patch - Send patches via email' \ + ' manage-contacts - Manage email contact groups' \ ' env - Handle kw envs' \ ' patch-hub - Open Terminal UI to interact with patches from lore.kernel.org' \ ' clear-cache - Clear files generated by kw' \ diff --git a/src/kw_manage_contacts.sh b/src/kw_manage_contacts.sh new file mode 100644 index 000000000..0120f6fae --- /dev/null +++ b/src/kw_manage_contacts.sh @@ -0,0 +1,970 @@ +# This file handles the interactions with the email groups and contacts. Currently it + +include "${KW_LIB_DIR}/lib/kw_config_loader.sh" +include "${KW_LIB_DIR}/lib/kwlib.sh" +include "${KW_LIB_DIR}/lib/kw_string.sh" +include "${KW_LIB_DIR}/send_patch.sh" + +# Hash containing user options +declare -gA options_values + +# Mail group database tables +declare -gr DATABASE_TABLE_GROUP='email_group' +declare -gr DATABASE_TABLE_CONTACT='email_contact' +declare -gr DATABASE_TABLE_CONTACT_GROUP='email_contact_group' + +declare -Ag condition_array +declare -Ag updates_array + +#shellcheck disable=SC2119 +function manage_contacts_main() +{ + local flag + local ret + + flag=${flag:-'SILENT'} + + if [[ "$1" =~ -h|--help ]]; then + manage_contacts_help "$1" + exit 0 + fi + + parse_manage_contacts_options "$@" + if [[ "$?" -gt 0 ]]; then + complain "${options_values['ERROR']}" + manage_contacts_help + return 22 # EINVAL + fi + + if [[ "${options_values['GROUP_CREATE']}" ]]; then + create_email_group "${options_values['GROUP']}" + + if [[ "$?" -eq 0 ]]; then + success "New group ${options_values['GROUP']} created successfully!" + fi + fi + + if [[ "${options_values['GROUP_REMOVE']}" ]]; then + remove_email_group "${options_values['GROUP']}" + + if [[ "$?" -eq 0 ]]; then + success "Group ${options_values['GROUP']} removed successfully!" + fi + fi + + if [[ -n "${options_values['GROUP_RENAME']}" ]]; then + rename_email_group "${options_values['GROUP']}" "${options_values['GROUP_RENAME']}" + + if [[ "$?" -eq 0 ]]; then + success "Group ${options_values['GROUP']} successfully renamed to ${options_values['GROUP_RENAME']}" + fi + fi + + if [[ -n "${options_values['GROUP_ADD']}" ]]; then + add_email_contacts "${options_values['GROUP_ADD']}" "${options_values['GROUP']}" + + if [[ "$?" -eq 0 ]]; then + success 'Contacts added successfully!' + fi + fi + + if [[ -n "${options_values['GROUP_REMOVE_EMAIL']}" ]]; then + remove_email_contact "${options_values['GROUP']}" "${options_values['GROUP_REMOVE_EMAIL']}" + + if [[ "$?" -eq 0 ]]; then + success 'Contact group removed successfully!' + fi + fi + + if [[ -n "${options_values['GROUP_SHOW']}" ]]; then + show_email_groups "${options_values['GROUP']}" + fi + + return 0 +} + +# This function receives the name of a new group and then check for +# incidences in the database and validate the group name before creating +# the group. +# +# @group_name: The name of the group that will be created. +# +# Returns: +# returns 0 if successful, non-zero otherwise +function create_email_group() +{ + local group_name="$1" + local values + + validate_group_name "$group_name" + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + check_existent_group "$group_name" + + if [[ "$?" -ne 0 ]]; then + warning 'This group already exists' + return 22 # EINVAL + fi + + create_group "$group_name" + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + return 0 +} + +# This function creates a new kw mail group +# +# @group_name: The name of the group that will be created. +# +# Returns: +# returns 0 if successful, non-zero otherwise +function create_group() +{ + local group_name="$1" + local sql_operation_result + + values="$(format_values_db 1 "$group_name")" + + sql_operation_result=$(insert_into "$DATABASE_TABLE_GROUP" '(name)' "$values" '' 'VERBOSE') + ret="$?" + + if [[ "$ret" -eq 2 || "$ret" -eq 61 ]]; then + complain "$sql_operation_result" + return 22 # EINVAL + elif [[ "$ret" -ne 0 ]]; then + complain "($LINENO):" $'Error while inserting group into the database with command:\n' "${sql_operation_result}" + return 22 # EINVAL + fi + + return 0 +} + +# This function validate a given group name +# +# @group_name: the group name that will be checked +# +# Return: +# returns 0 if successful, 61 if group name is empty, +# 75 if size of the group name is over 50 characters +# and 22 if group name has invalid characters as: +# [!, @, #, $, %, ^, &, (, ), (' ), (" ) and +]. +function validate_group_name() +{ + local group_name="$1" + local name_length + local has_special_character + local ret + + if [[ -z "$group_name" ]]; then + complain 'The group name is empty' + return 61 # ENODATA + fi + + name_length="$(str_length "$group_name")" + + if [[ "$name_length" -ge 50 ]]; then + complain 'The group name must be less than 50 characters' + return 75 # OVERFLOW + fi + + str_has_special_characters "$group_name" + + if [[ "$?" -eq 0 ]]; then + complain 'The group name must not contain special characters' + return 22 #EINVAL + fi + + return 0 +} + +# This function validate a given group name +# +# @group_name: the group name that will be checked +# +# Return: +# returns 0 if successful, 61 if group name is empty, +# 75 if size of the group name is over 50 characters +# and 22 if group name has invalid characters as: +# [!, @, #, $, %, ^, &, (, ), (' ), (" ) and +]. +function validate_email_group_list() +{ + local groups_list="$1" + local ret + + IFS=',' read -ra groups_array <<< "$groups_list" + for group_name in "${groups_array[@]}"; do + check_existent_group "$group_name" + ret="$?" + + if [[ "$ret" -eq 0 ]]; then + return 61 + fi + done + + return 0 +} + +# This function checks the existence of a given group +# +# @group_name: the group name that will be checked +# +# Return: +# returns group id if group exists, 0 if it doesn't +function check_existent_group() +{ + local group_name="$1" + local group_id + + condition_array=(['name']="${group_name}") + group_id="$(select_from "$DATABASE_TABLE_GROUP" 'id' '' 'condition_array')" + + if [[ -n "$group_id" ]]; then + return "$group_id" + fi + + return 0 +} + +# This function removes a given mail group and +# all of it's references in the data base. Also +# removes the contacts without group association +# +# @group_name: The name of the removed group +# +# Returns: +# returns 0 if successful, non-zero otherwise +function remove_email_group() +{ + local group_name="$1" + + check_existent_group "$group_name" + + if [[ "$?" -eq 0 ]]; then + warning 'Error, this group does not exist' + return 22 #EINVAL + fi + + remove_group "$group_name" + + if [[ "$?" -ne 0 ]]; then + return 22 #EINVAL + fi + + return 0 +} + +# This function removes a given group from the database +# +# @group_name: Name of the group which the contacts will be removed +# +# Return: +# returns 0 if successful, non-zero otherwise +function remove_group() +{ + local group_name="$1" + local sql_operation_result + + condition_array=(['name']="${group_name}") + + sql_operation_result=$(remove_from "$DATABASE_TABLE_GROUP" 'condition_array' '' '' 'VERBOSE') + ret="$?" + + if [[ "$ret" -eq 2 || "$ret" -eq 61 ]]; then + complain "$sql_operation_result" + return 22 # EINVAL + elif [[ "$ret" -ne 0 ]]; then + complain $'Error while removing group from the database with command:\n'"${sql_operation_result}" + return 22 # EINVAL + fi + + return 0 +} + +# This function renames a given mail group after checking +# the parameters passed. +# +# @old_name: The actual name of the renamed group +# @new_name: The new name wich the group will be renamed +# +# Returns: +# returns 0 if successful, non-zero otherwise +function rename_email_group() +{ + local old_name="$1" + local new_name="$2" + local group_id + + if [[ -z "$old_name" ]]; then + complain 'Error, group name is empty' + return 61 # ENODATA + fi + + check_existent_group "$old_name" + + if [[ "$?" -eq 0 ]]; then + warning 'This group does not exist so it can not be renamed' + return 22 # EINVAL + fi + + validate_group_name "$new_name" + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + rename_group "$old_name" "$new_name" + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + return 0 +} + +# This function renames a given group from the database +# +# @old_name: Name of the group that will be renamed +# @new_name: New namw of the group +# +# Return: +# returns 0 if successful, non-zero otherwise +function rename_group() +{ + local old_name="$1" + local new_name="$2" + local sql_operation_result + local ret + + condition_array=(['name']="${old_name}") + updates_array=(['name']="${new_name}") + + sql_operation_result=$(update_into "$DATABASE_TABLE_GROUP" 'updates_array' '' 'condition_array' 'VERBOSE') + ret="$?" + + if [[ "$ret" -eq 2 || "$ret" -eq 61 ]]; then + complain "$sql_operation_result" + return 22 # EINVAL + elif [[ "$ret" -ne 0 ]]; then + complain "($LINENO):" $'Error while removing group from the database with command:\n'"${sql_operation_result}" + return 22 # EINVAL + fi + + return 0 +} + +# This function add a new contact to a given kw mail group +# +# @contacts_string: The string with all the contacts informations +# @group_name: The name of the group which the contacts will be added. +# +# Returns: +# returns 0 if successful, non-zero otherwise +function add_email_contacts() +{ + local contacts_list="$1" + local group_name="$2" + local group_id + declare -A _contacts_array + + if [[ -z "$contacts_list" ]]; then + complain 'The contacts list is empty' + return 61 # ENODATA + fi + + if [[ -z "$group_name" ]]; then + complain 'The group name is empty' + return 61 # ENODATA + fi + + check_existent_group "$group_name" + group_id="$?" + + if [[ "$group_id" -eq 0 ]]; then + complain 'Error, ubable to add contacts to unexistent group' + return 22 # EINVAL + fi + + split_contact_infos "$contacts_list" _contacts_array + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + add_contacts _contacts_array + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + add_contact_group _contacts_array "$group_id" + + if [[ "$?" -ne 0 ]]; then + return 22 # EINVAL + fi + + return 0 +} + +# This function split the columns in the given contact string passed +# as parameter and create an associative array with the infos. +# +# @contacts_list: An string formed as "CONTACT_NAME , CONTACT_NAME , ..." +# @contacts_array: An associative array formed as ":" +# +# Returns: +# returns 0 if successful, non-zero otherwise +function split_contact_infos() +{ + local contacts_list="$1" + local -n contacts_array="$2" + local contacts_infos_array + local contact_info + local ret + local name + local email + local added_contacts=0 + + readarray -t contacts_infos_array < <(awk -v RS=", " '{print}' <<< "$contacts_list") + + for contact_info in "${contacts_infos_array[@]}"; do + if [[ -z "$contact_info" ]]; then + continue + fi + + check_infos_sintaxe "$contact_info" + + if [[ "$?" -ne 0 ]]; then + return 22 #EINVAL + fi + + email="$(cut --delimiter='<' --fields=2 <<< "$contact_info" | cut --delimiter='>' --fields=1)" + name="$(cut --delimiter='<' --fields=1 <<< "$contact_info")" + + validate_contact_infos "$email" "$name" + + if [[ "$?" -ne 0 ]]; then + return 22 #EINVAL + fi + + contacts_array["$email"]="$name" + ((added_contacts++)) + done + + if [[ "$added_contacts" -ne "${#contacts_array[@]}" ]]; then + complain 'Error, Some of the contacts must have a repeated email' + return 22 #EINVAL + fi + + return 0 +} + +# This function validate if the string with the contact infos is valid +# +# @contact_info: The string with the contact info, +# formed as: "CONTACT_NAME " +# +# Returns: +# returns 0 if successful, non-zero otherwise +function check_infos_sintaxe() +{ + local contact_info="$1" + local lt_pos + local lt_count + local gt_pos + local gt_count + + gt_count=$(str_count_char_repetition "$contact_info" '>') + lt_count=$(str_count_char_repetition "$contact_info" '<') + + gt_pos=$(str_get_char_position "$contact_info" '>') + lt_pos=$(str_get_char_position "$contact_info" '<') + + if [[ "$lt_count" -eq 0 ]]; then + complain 'Syntax error in the contacts list, there is a missing "<" in some of the contacts ' + return 22 #EINVAL + elif [[ "$gt_count" -eq 0 ]]; then + complain 'Syntax error in the contacts list, there is a missing ">" in some of the contacts ' + return 22 #EINVAL + elif [[ "$lt_pos" -gt "$gt_pos" ]]; then + complain 'Syntax error in the contacts list, the contact info should be like: name ' + return 22 #EINVAL + elif [[ "$lt_count" -ne 1 ]]; then + complain 'Syntax error in the contacts list, there is a remaining "<" in some of the contacts ' + return 22 #EINVAL + elif [[ "$gt_count" -ne 1 ]]; then + complain 'Syntax error in the contacts list, there is a remaining ">" in some of the contacts ' + return 22 #EINVAL + fi + + return 0 +} + +# This function check if the contacts infos email and name are valid +# +# @email: The contact email +# @name: The contact name +# +# Returns: +# returns 0 if successful, non-zero otherwise +function validate_contact_infos() +{ + local email="$1" + local name="$2" + + if [[ -z "$email" || -z "$name" ]]; then + complain 'Error, Some of the contact names or emails must be empty' + return 61 #EINVAL + fi + + validate_email "$email" + + if [[ "$?" -ne 0 ]]; then + return 22 #EINVAL + fi + + return 0 +} + +# This function add a contact in the database +# +# @contacts_array: The contact name +# +# Returns: +# returns 0 if successful, non-zero otherwise +function add_contacts() +{ + local -n contacts_array="$1" + local values + local result + local email + local contact_id + local contact_name + local message + local entries + local existent_contact + local sql_operation_result + local ret + + for email in "${!contacts_array[@]}"; do + condition_array=(["email"]="${email}") + entries=$(concatenate_with_commas '"id"' '"name"') + existent_contact=$(select_from "$DATABASE_TABLE_CONTACT" "$entries" "" "condition_array" '') + + IFS='|' read -r contact_id contact_name <<< "$existent_contact" + + if [[ -n "$contact_name" ]]; then + if [[ "${contact_name}" != "${contacts_array["$email"]}" ]]; then + message="The email '${email}' you provided is already associated with contact '${contact_name}'." + message+=$'\n' + message+="Use the existing contact name '${contact_name}' instead of renaming it to '${contacts_array["$email"]}'?" + + if [[ "$(ask_yN "$message")" =~ '0' ]]; then + updates_array=(["name"]="${contacts_array["$email"]}") + condition_array=(["id"]="${contact_id}") + update_into "$DATABASE_TABLE_CONTACT" "updates_array" '' "condition_array" + continue + fi + contacts_array["$email"]="$contact_name" + fi + continue + fi + + values=$(format_values_db 2 "${contacts_array["$email"]}" "${email}") + + sql_operation_result=$(insert_into "$DATABASE_TABLE_CONTACT" '(name, email)' "$values" '' 'VERBOSE') + ret="$?" + + if [[ "$ret" -eq 61 || "$ret" -eq 2 ]]; then + complain "$sql_operation_result" + return 22 # EINVAL + elif [[ "$ret" -ne 0 ]]; then + complain "($LINENO):" 'Error while trying to insert contact into the database with the command:\n'"${sql_operation_result}" + return 22 # EINVAL + fi + + done + + return 0 +} + +# This function add the association between the contacts +# and its group in the database +# +# @contacts_array: The contact name +# @group_id: The id of group which the contacts will be associated +# +# Returns: +# returns 0 if successful, non-zero otherwise +function add_contact_group() +{ + local -n contacts_array="$1" + local group_id="$2" + local values + local email + local contact_id + local ctt_group_association + local sql_operation_result + local ret + + for email in "${!contacts_array[@]}"; do + condition_array=(['email']="${email}") + contact_id="$(select_from "$DATABASE_TABLE_CONTACT" 'id' '' 'condition_array')" + values="$(format_values_db 2 "$contact_id" "$group_id")" + + condition_array=(['contact_id']="${contact_id}" ['group_id']="${group_id}") + ctt_group_association="$(select_from "$DATABASE_TABLE_CONTACT_GROUP" 'contact_id, group_id' '' 'condition_array')" + if [[ -n "$ctt_group_association" ]]; then + continue + fi + + sql_operation_result=$(insert_into "$DATABASE_TABLE_CONTACT_GROUP" '(contact_id, group_id)' "$values" '' 'VERBOSE') + ret="$?" + + if [[ "$ret" -eq 2 || "$ret" -eq 61 ]]; then + complain "$sql_operation_result" + return 22 # EINVAL + elif [[ "$ret" -ne 0 ]]; then + complain "($LINENO):" $'Error while trying to insert contact group into the database with the command:\n'"${sql_operation_result}" + return 22 # EINVAL + fi + + done + + return 0 +} + +# This function is used either to show the kw mail groups infos or +# some specific group contacts +# +# @group_name: an string containing the name of the group, if given +# prints group contact infos +# +# Returns: +# nothing +function show_email_groups() +{ + local group_name="$1" + local columns="$2" + local groups_info + local contacts_info + local contact_id + declare -a contacts_array + declare -a groups_array + + if [[ -z $columns ]]; then + columns="$(tput cols)" + fi + + if [[ -n "$group_name" ]]; then + + check_existent_group "$group_name" + + if [[ "$?" -eq 0 ]]; then + complain 'Error unexistent group' + return 22 #EINVAL + fi + + contacts_info="$(get_groups_contacts_infos "$group_name" '*')" + IFS=',' read -ra contacts_array <<< "$contacts_info" + print_contact_infos "$group_name" 'contacts_array' "$columns" + return + fi + + groups_info="$(select_from "$DATABASE_TABLE_GROUP")" + readarray -t groups_array <<< "$groups_info" + print_groups_infos 'groups_array' "$columns" +} + +# This function is used to print all the contacts infos of the given group +# +# @group_name: a string with the group name that will be shown +# @contacts_array: the array with the contacts infos written as: +# groups_array[0]='info1|info2|info3' +# +# Returns: +# nothing +function print_contact_infos() +{ + local group_name="$1" + local -n _contacts_array="$2" + local columns="$3" + local group_name_width=${#group_name} + local trim_width=$(((columns - group_name_width) / 2)) + local remaining_width=$((columns - group_name_width - trim_width)) + local id_width=8 + local name_width=50 + local associate_groups_width=20 + local created_at_width=12 + local email_width=$((columns - id_width - name_width - associate_groups_width - created_at_width - 8)) + + printf "%*s%s%*s\n" "$trim_width" "" "$group_name" "$remaining_width" "" | tr ' ' '-' + + printf "%-${id_width}s|%-${name_width}s|%-${email_width}s|%-${associate_groups_width}s|%-${created_at_width}s\n" "ID" "Name" "Email" "Associated Groups" "Created at" + printf "%-${columns}s\n" | tr ' ' '-' + + for contact in "${_contacts_array[@]}"; do + IFS='|' read -r id name email created_at <<< "$contact" + condition_array=(['contact_id']="$id") + associate_groups_num="$(select_from "$DATABASE_TABLE_CONTACT_GROUP" 'COUNT(*)' '' 'condition_array')" + printf "%-${id_width}s|%-${name_width}s|%-${email_width}s|%-${associate_groups_width}s|%-${created_at_width}s\n" "$id" "$name" "$email" "$associate_groups_num" "$created_at" + done + printf "%-${columns}s\n" | tr ' ' '-' + +} + +# This function get the contacts emails for the given groups +# +# @groups: a list of group names separed by comma "group1,group2,..." +# @infos: the infos that will be retrieved from the contacts written as: +# '"info1","info2"' +# +# Return: +# returns the list of the infos from the users in a given group separated with comma +function get_groups_contacts_infos() +{ + local groups="$1" + local infos="$2" + local group + local groups_list + local groups_id + local groups_recipients + local contacts_id + local contacts_id_list + + IFS=',' read -ra groups_list <<< "$groups" + for group in "${groups_list[@]}"; do + condition_array=(['name']="$group") + group_id="$(select_from "$DATABASE_TABLE_GROUP" 'id' '' 'condition_array')" + + condition_array=(['group_id']="$group_id") + contacts_id="$(select_from "$DATABASE_TABLE_CONTACT_GROUP" 'contact_id' '' 'condition_array')" + IFS=$'\n' read -d '' -ra contacts_id_list <<< "$contacts_id" + for id in "${contacts_id_list[@]}"; do + condition_array=(['id']="$id") + groups_recipients+="$(select_from "$DATABASE_TABLE_CONTACT" "$infos" '' 'condition_array')" + groups_recipients+=',' + done + done + printf '%s\n' "${groups_recipients::-1}" +} + +# This function is used to print all the group infos +# +# @groups_array: the array with the group infos written as: +# groups_array[0]='info1|info2|info3' +# +# Returns: +# nothing +function print_groups_infos() +{ + local -n groups_info="$1" + local columns="$2" + local id_width=8 + local contact_num_width=25 + local created_at_width=20 + local name_width=$(("$columns" - id_width - contact_num_width - created_at_width - 6)) + + printf "%-${id_width}s|%-${name_width}s|%-${contact_num_width}s|%-${created_at_width}s\n" "ID" "Name" "Contacts" "Created at" + printf "%-${columns}s\n" | tr ' ' '-' + + for group in "${!groups_info[@]}"; do + IFS='|' read -r id name created_at <<< "${groups_info[$group]}" + condition_array=(['group_id']="$id") + contact_num="$(select_from "$DATABASE_TABLE_CONTACT_GROUP" 'COUNT(*)' '' 'condition_array')" + printf "%-${id_width}s|%-${name_width}s|%-${contact_num_width}s|%-${created_at_width}s\n" "$id" "$name" "$contact_num" "$created_at" + done + + printf "%-${columns}s\n" | tr ' ' '-' +} + +# This function removes a kw mail contact associations +# from the database. +# +# @contact_email: The email which will be removed +# +# Returns: +# returns 0 if successful, non-zero otherwise +function remove_email_contact() +{ + local group_name="$1" + local contact_email="$2" + local contact_id + local group_id + + if [[ -z "$group_name" ]]; then + complain 'Error, the group name is empty' + return 61 # ENODATA + fi + + if [[ -z "$contact_email" ]]; then + complain 'Error, contact email is empty' + return 61 # EINVAL + fi + + check_existent_group "$group_name" + + group_id="$?" + + if [[ "$group_id" -eq 0 ]]; then + complain 'Error, this group doesnt exist' + return 22 # EINVAL + fi + + condition_array=(['email']="${contact_email}") + contact_id="$(select_from "$DATABASE_TABLE_CONTACT" 'id' '' 'condition_array')" + + if [[ -z "$contact_id" ]]; then + complain 'Error, this email is not associated with a contact' + return 22 # EINVAL + fi + + remove_contact_group "$group_id" "$contact_id" + + if [[ "$?" -ne 0 ]]; then + complain 'Error while removing contact group' + return 22 # EINVAL + fi + + return 0 +} + +# This function removes associated groups from a contact +# +# @contact_id: The id of the contact which will be +# removed +# +# Returns: +# returns 0 if successful, non-zero otherwise +function remove_contact_group() +{ + local group_id="$1" + local contact_id="$2" + + condition_array=(['contact_id']="${contact_id}" ['group_id']="${group_id}") + remove_from "$DATABASE_TABLE_CONTACT_GROUP" 'condition_array' + + return "$?" +} + +# This function removes associated groups from a contact +# +# @contact_id: The id of the contact which will be +# removed +# +# Returns: +# returns 0 if successful, non-zero otherwise +function remove_contact() +{ + local contact_id="$1" + local sql_operation_result + local ret + + condition_array=(['id']="${contact_id}") + + sql_operation_result=$(remove_from "$DATABASE_TABLE_CONTACT" 'condition_array' '' '' 'VERBOSE') + ret="$?" + + if [[ "$ret" -eq 2 || "$ret" -eq 61 ]]; then + complain "$sql_operation_result" + return 22 # EINVAL + elif [[ "$ret" -ne 0 ]]; then + complain "($LINENO): "$'Error while removing contact from the database with the command:\n'"${sql_operation_result}" + return 22 # EINVAL + fi + + return 0 +} + +function parse_manage_contacts_options() +{ + local index + local option + local setup_token=0 + local patch_version='' + local commit_count='' + local short_options='c:,r:,a:,' + local long_options='group-create:,group-remove:,group-rename:,group-add:,group-remove-email:,group-show::,' + local pass_option_to_send_email + + options="$(kw_parse "$short_options" "$long_options" "$@")" + if [[ "$?" != 0 ]]; then + options_values['ERROR']="$(kw_parse_get_errors 'kw manage-contacts' "$short_options" \ + "$long_options" "$@")" + return 22 # EINVAL + fi + + eval "set -- $options" + + options_values['GROUPS']='' + options_values['GROUP']='' + options_values['GROUP_CREATE']='' + options_values['GROUP_REMOVE']='' + options_values['GROUP_RENAME']='' + options_values['GROUP_ADD']='' + options_values['GROUP_REMOVE_EMAIL']='' + options_values['GROUP_REMOVE_EMAIL']='' + options_values['GROUP_SHOW']='' + + while [[ "$#" -gt 0 ]]; do + case "$1" in + --group-create | -c) + options_values['GROUP_CREATE']=1 + options_values['GROUP']="$2" + shift 2 + ;; + --group-remove | -r) + options_values['GROUP_REMOVE']=1 + options_values['GROUP']="$2" + shift 2 + ;; + --group-rename) + options_values['GROUP']=$(printf "%s\n" "$2" | cut -d':' -f1) + options_values['GROUP_RENAME']=$(printf "%s\n" "$2" | cut -d':' -f2-) + shift 2 + ;; + --group-add | -a) + options_values['GROUP']=$(printf "%s\n" "$2" | cut -d':' -f1) + options_values['GROUP_ADD']=$(printf "%s\n" "$2" | cut -d':' -f2-) + shift 2 + ;; + --group-remove-email) + options_values['GROUP']=$(printf "%s\n" "$2" | cut -d':' -f1) + options_values['GROUP_REMOVE_EMAIL']=$(printf "%s\n" "$2" | cut -d':' -f2-) + shift 2 + ;; + --group-show) + option="$(str_strip "${2}")" + options_values['GROUP_SHOW']=1 + options_values['GROUP']="$option" + shift 2 + ;; + --) + shift + ;; + esac + done + + return 0 +} + +function manage_contacts_help() +{ + if [[ "$1" == --help ]]; then + include "${KW_LIB_DIR}/help.sh" + kworkflow_man 'manage-contacts' + exit + fi + printf '%s\n' 'kw manage-contacts:' \ + ' manage-contacts (-c | --group-create) [] - create new group' \ + ' manage-contacts (-r | --group-remove) [] - remove existing group' \ + ' manage-contacts --group-rename []:[] - rename existent group' \ + ' manage-contacts --group-add "[]:[] <[]>, [] <[]>, ..." - add contact to existent group' \ + ' manage-contacts --group-remove-email "[]:[]" - remove contact from existent group' \ + ' manage-contacts --group-show=[] - show existent groups or specific group contacts' +} diff --git a/src/lib/kw_string.sh b/src/lib/kw_string.sh index 7380a4128..6b660c3e5 100644 --- a/src/lib/kw_string.sh +++ b/src/lib/kw_string.sh @@ -217,7 +217,7 @@ function concatenate_with_commas() } # This function check if a string has some special character associated with -# it. By special character, we refer to: !, @, #, $, %, ^, &, (, ), and +. +# it. By special character, we refer to: !, @, #, $, %, ^, &, (, ), (' ), (" ) and +. # # @str: Target string # @@ -227,7 +227,7 @@ function str_has_special_characters() { local str="$*" - [[ "$str" == *['!'@#\$%^\&*\(\)+]* ]] && return 0 + [[ "$str" =~ ['!'@#\$%^\&*\(\)+,\"\'] ]] && return 0 return 1 # EPERM } @@ -302,3 +302,30 @@ function string_to_unix_filename() printf '%s' "$filename" } + +# This function get the position of the first given char in the given string +# +# @string: Target string +# @char: Target char +# +# Return: +# The position of the first occurence of the char in the string, 0 otherwise +function str_get_char_position() +{ + local string="$1" + local char="$2" + local pos + local aux + local length + + aux="${string%%"$char"*}" + pos=$((${#aux} + 1)) + length=${#string} + + if [[ "$length" -lt "$pos" ]]; then + printf '%s' 0 + return + fi + + printf '%s' "$pos" +} diff --git a/src/send_patch.sh b/src/send_patch.sh index 8ab9cb34a..6bb43a72d 100644 --- a/src/send_patch.sh +++ b/src/send_patch.sh @@ -6,6 +6,7 @@ include "${KW_LIB_DIR}/lib/kw_config_loader.sh" include "${KW_LIB_DIR}/lib/kwlib.sh" include "${KW_LIB_DIR}/lib/kw_string.sh" +include "${KW_LIB_DIR}/kw_manage_contacts.sh" # Hash containing user options declare -gA options_values @@ -89,7 +90,9 @@ function mail_send() local flag="$1" local opts="${send_patch_config[send_opts]}" local to_recipients="${options_values['TO']}" + local to_groups_recipients="${options_values['TO_GROUPS']}" local cc_recipients="${options_values['CC']}" + local cc_groups_recipients="${options_values['CC_GROUPS']}" local dryrun="${options_values['SIMULATE']}" local commit_range="${options_values['COMMIT_RANGE']}" local version="${options_values['PATCH_VERSION']}" @@ -104,6 +107,22 @@ function mail_send() [[ -n "$dryrun" ]] && cmd+=" $dryrun" + if [[ -n "$to_groups_recipients" ]]; then + validate_email_group_list "$to_groups_recipients" || exit_msg 'Please review your `--to-groups` list.' + if [[ -n "$to_recipients" ]]; then + to_recipients+=',' + fi + to_recipients+=$(get_groups_contacts_infos "$to_groups_recipients" 'email') + fi + + if [[ -n "$cc_groups_recipients" ]]; then + validate_email_group_list "$cc_groups_recipients" || exit_msg 'Please review your `--cc-groups` list.' + if [[ -n "$cc_recipients" ]]; then + cc_recipients+=',' + fi + cc_recipients+=$(get_groups_contacts_infos "$cc_groups_recipients" 'email') + fi + if [[ -n "$to_recipients" ]]; then validate_email_list "$to_recipients" || exit_msg 'Please review your `--to` list.' cmd+=" --to=\"$to_recipients\"" @@ -951,7 +970,7 @@ function parse_mail_options() local patch_version='' local commit_count='' local short_options='s,t,f,v:,i,l,n,' - local long_options='send,simulate,to:,cc:,setup,local,global,force,verify,verbose,' + local long_options='send,simulate,to:,to-groups:,cc:,cc-groups:,setup,local,global,force,verify,verbose,' long_options+='template::,interactive,no-interactive,list,private,rfc,' local pass_option_to_send_email @@ -974,7 +993,9 @@ function parse_mail_options() # Default values options_values['SEND']='' options_values['TO']='' + options_values['TO_GROUPS']='' options_values['CC']='' + options_values['CC_GROUPS']='' options_values['SIMULATE']='' options_values['SETUP']=0 options_values['FORCE']=0 @@ -1005,10 +1026,18 @@ function parse_mail_options() options_values['TO']="$2" shift 2 ;; + --to-groups) + options_values['TO_GROUPS']="$2" + shift 2 + ;; --cc) options_values['CC']="$2" shift 2 ;; + --cc-groups) + options_values['CC_GROUPS']="$2" + shift 2 + ;; --simulate) options_values['SIMULATE']='--dry-run' shift diff --git a/tests/unit/kw_manage_contacts_test.sh b/tests/unit/kw_manage_contacts_test.sh new file mode 100755 index 000000000..9248cb731 --- /dev/null +++ b/tests/unit/kw_manage_contacts_test.sh @@ -0,0 +1,740 @@ +#!/bin/bash + +include './src/kw_manage_contacts.sh' +include './tests/unit/utils.sh' + +function oneTimeSetUp() +{ + declare -g DB_FILES + + export KW_ETC_DIR="${SHUNIT_TMPDIR}/etc/" + export KW_CACHE_DIR="${SHUNIT_TMPDIR}/cache/" + export KW_DATA_DIR="${SHUNIT_TMPDIR}" + + DB_FILES="$(realpath './tests/unit/samples/db_files')" + KW_DB_DIR="$(realpath './database')" +} + +function setUp() +{ + declare -gA options_values + declare -gA set_confs + + setupDatabase +} + +function tearDown() +{ + unset options_values + unset set_confs + + tearDownDatabase +} + +function setupDatabase() +{ + declare -g TEST_GROUP_NAME='TEST_GROUP' + declare -g TEST_CONTACT_INFOS=('name' 'email') + declare -g TEST_GROUP_ID + + execute_sql_script "${KW_DB_DIR}/kwdb.sql" > /dev/null 2>&1 + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" (name) VALUES (\"${TEST_GROUP_NAME}\");" + TEST_GROUP_ID="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='${TEST_GROUP_NAME}';")" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES (\"${TEST_CONTACT_INFOS[0]}\",\"${TEST_CONTACT_INFOS[1]}\");" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT_GROUP}\" (contact_id, group_id) VALUES (1,1);" + +} + +function tearDownDatabase() +{ + is_safe_path_to_remove "${KW_DATA_DIR}/kw.db" + if [[ "$?" == 0 ]]; then + rm "${KW_DATA_DIR}/kw.db" + fi +} + +function test_validate_group_name() +{ + local expected + local output + local ret + + # invalid values + output=$(validate_group_name '') + ret="$?" + expected='The group name is empty' + assert_equals_helper 'Empty group should not be valid' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 61 + + output=$(validate_group_name '012345678901234567890123456789012345678901234567890') + ret="$?" + expected='The group name must be less than 50 characters' + assert_equals_helper 'Group name length should not be valid' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 75 + + output=$(validate_group_name ',@#$!') + ret="$?" + expected='The group name must not contain special characters' + assert_equals_helper 'Special character in group name should not be valid' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + + output=$(validate_group_name 'validName') + ret="$?" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_check_existent_group() +{ + local expected + local output + local ret + + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" (name) VALUES ('existent_group');" + + # invalid values + output=$(check_existent_group "$TEST_GROUP_NAME") + ret="$?" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" "$TEST_GROUP_ID" + + # valid values + output=$(check_existent_group 'unexistent_name') + ret="$?" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_create_email_group() +{ + local expected + local output + local ret + + # invalid cases + output=$(create_email_group "$TEST_GROUP_NAME") + ret="$?" + expected='This group already exists' + assert_equals_helper 'The group should not have been created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(create_email_group '') + ret="$?" + expected='The group name is empty' + assert_equals_helper 'The group should not have been created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(create_email_group '012345678901234567890123456789012345678901234567890') + ret="$?" + expected='The group name must be less than 50 characters' + assert_equals_helper 'The group should not have been created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(create_email_group ',@#$!') + ret="$?" + expected='The group name must not contain special characters' + assert_equals_helper 'The group should not have been created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + create_email_group 'create_unexistent_email_group_name' + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='create_unexistent_email_group_name';") + expected='create_unexistent_email_group_name' + assert_equals_helper 'The group should have been created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_create_group() +{ + local expected + local output + local ret + + # invalid cases + output=$(create_group "$TEST_GROUP_NAME" 2> /dev/null) + ret="$?" + expected='This group already exists' + expected=$'Error while inserting group into the database with command:\nsqlite3 -init ' + expected+="${KW_DB_DIR}/kw.db ${KW_DATA_DIR}/kw.db" + expected+='-batch "INSERT INTO email_group (name) VALUES ('TEST_GROUP');"' + assertContains 'The group should not have been created' "$output" "$expected" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + create_group 'create_unexistent_group' + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='create_unexistent_group';") + expected='create_unexistent_group' + assert_equals_helper 'The group should have been created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_remove_email_group() +{ + local expected + local output + local ret + + # invalid cases + output=$(remove_email_group 'nonexistent_group') + ret="$?" + expected='Error, this group does not exist' + assert_equals_helper 'Group should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected error' "$LINENO" "$ret" 22 + + # valid values + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" ('name') VALUES ('test_group4') ;" + + remove_email_group 'test_group4' + ret="$?" + expected='' + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT * FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='test_group4' ;") + assert_equals_helper 'Group should have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_remove_group() +{ + local expected + local output + local ret + + # invalid cases + output=$(remove_group "nonexistent_group'" 2> /dev/null) + ret="$?" + expected=$'Error while removing group from the database with command:\nsqlite3 -init ' + expected+="${KW_DB_DIR}/pre_cmd.sql \"${KW_DATA_DIR}/kw.db\" " + expected+="-batch \"DELETE FROM email_group WHERE name='nonexistent_group'' ;\"" + + assert_equals_helper 'Group should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected error' "$LINENO" "$ret" 22 + + # valid values + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" ('name') VALUES ('test_group4') ;" + + remove_group 'test_group4' + ret="$?" + expected='' + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT * FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='test_group4' ;") + assert_equals_helper 'Group should have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_rename_existent_group() +{ + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" (name) VALUES ('old_group_name');" + + # invalid values + output=$(rename_email_group 'unexistent_group' 'new_group_name') + ret="$?" + expected='This group does not exist so it can not be renamed' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(rename_email_group 'old_group_name' '') + ret="$?" + expected='The group name is empty' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(rename_email_group 'old_group_name' '012345678901234567890123456789012345678901234567890') + ret="$?" + expected='The group name must be less than 50 characters' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(rename_email_group 'old_group_name' '!@#$%^&,+') + ret="$?" + expected='The group name must not contain special characters' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(rename_email_group 'old_group_name' "nonexistent_group''") + ret="$?" + expected='The group name must not contain special characters' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + expected=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='old_group_name';") + rename_email_group 'old_group_name' 'new_group_name' + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='new_group_name';") + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_rename_group() +{ + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" (name) VALUES ('old_group_name');" + + # invalid values + output=$(rename_group 'old_group_name' "nonexistent_group'" 2> /dev/null) + ret="$?" + expected=$'Error while removing group from the database with command:\nsqlite3 -init ' + expected+="${KW_DB_DIR}/pre_cmd.sql -cmd \"\" \"${KW_DATA_DIR}/kw.db\" " + expected+="-batch \"UPDATE email_group SET name = 'nonexistent_group'' WHERE name='old_group_name' ;\"" + assertContains 'Expected no error' "$output" "$expected" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + expected=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='old_group_name';") + rename_group 'old_group_name' 'new_group_name' + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='new_group_name';") + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_add_email_contacts() +{ + local expected + local output + local ret + + # invalid values + output=$(add_email_contacts 'add_emmail_ctt ' 'unexistent_group') + ret="$?" + expected='Error, ubable to add contacts to unexistent group' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(add_email_contacts '' "$TEST_GROUP_NAME") + ret="$?" + expected='The contacts list is empty' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 61 + + output=$(add_email_contacts 'add_emmail_ctt ' "$TEST_GROUP_NAME") + ret="$?" + expected='Invalid email: add_ema il_ctt@email.com' + assert_equals_helper 'Expected no error' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + output=$(add_email_contacts 'add_emmail_ctt ' "$TEST_GROUP_NAME") + ret="$?" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_split_contact_infos() +{ + local expected + local output + local ret + local contacts_list + declare -A output_arr + + # invalid values + contacts_list="Test Contact 1 , Test Contact 1 " + output=$(split_contact_infos "$contacts_list" 'output_arr') + ret="$?" + expected='Error, Some of the contacts must have a repeated email' + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + assert_equals_helper 'Contact infos should not have been splitted' "$LINENO" "$expected" "$output" + + contacts_list="Test Contact 1 <>, Test Contact 1 " + output=$(split_contact_infos "$contacts_list" 'output_arr') + ret="$?" + expected='Error, Some of the contact names or emails must be empty' + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + assert_equals_helper 'Contact infos should not have been splitted' "$LINENO" "$expected" "$output" + + contacts_list="Test Contact 1 , " + output=$(split_contact_infos "$contacts_list" 'output_arr') + ret="$?" + expected='Error, Some of the contact names or emails must be empty' + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + assert_equals_helper 'Contact infos should not have been splitted' "$LINENO" "$expected" "$output" + + # valid values + contacts_list="Test Contact 2 , Test Contact 3 " + declare -A expected_arr=( + ["test2@email.com"]="Test Contact 2" + ["test3@email.com"]="Test Contact 3" + ) + + split_contact_infos "$contacts_list" 'output_arr' + ret="$?" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + # compare array values + compare_array_values 'expected_arr' 'output_arr' "$LINENO" + + #compare array keys + expected="(${!expected_arr[*]})" + output="(${!output_arr[*]})" + assert_equals_helper 'Contact keys splitted incorrectly' "$LINENO" "$expected" "$output" +} + +function test_check_infos_sintaxe() +{ + local expected + local output + local ret + + # invalid values + output=$(check_infos_sintaxe 'Test Contact >test@email.com>') + ret="$?" + expected='Syntax error in the contacts list, there is a missing "<" in some of the contacts ' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + + output=$(check_infos_sintaxe 'Test Contact test@email.com<') + ret="$?" + expected='Syntax error in the contacts list, the contact info should be like: name ' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + + output=$(check_infos_sintaxe 'Test Contact <') + ret="$?" + expected='Syntax error in the contacts list, there is a remaining "<" in some of the contacts ' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + + output=$(check_infos_sintaxe 'Test Contact >') + ret="$?" + expected='Syntax error in the contacts list, there is a remaining ">" in some of the contacts ' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + + #valid values + output=$(check_infos_sintaxe 'Test Contact ') + ret="$?" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 0 +} + +function test_validate_contact_infos() +{ + local expected + local output + local ret + + # invalid values + output=$(validate_contact_infos 'email@mail.com' '') + ret="$?" + expected='Error, Some of the contact names or emails must be empty' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 61 + + output=$(validate_contact_infos '' 'Name') + ret="$?" + expected='Error, Some of the contact names or emails must be empty' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 61 + + output=$(validate_contact_infos 'email' 'Name') + ret="$?" + expected='Invalid email: email' + assert_equals_helper 'Contact infos should be wrong' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected an error' "$LINENO" "$ret" 22 + + # valid values + validate_contact_infos 'email@mail.com' 'Name' + ret="$?" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_add_contacts() +{ + local expected + local output + local ret + + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name,email) VALUES ('','testaddctt0@email.com');" + + # invalid values + declare -A _contacts_arr=( + ['testaddctt0@email.com']='Test Add Contact 0' + ) + output=$(add_contacts '_contacts_arr' 2> /dev/null) + ret="$?" + expected=$'Error while trying to insert contact into the database with the command:\nsqlite3 -init ' + expected+="${KW_DB_DIR}/pre_cmd.sql \"${KW_DATA_DIR}/kw.db\" " + expected+="-batch \"INSERT INTO email_contact (name, email) VALUES ('Test Add Contact 0','testaddctt0@email.com');\"" + assertContains 'Contact should not have been created' "$output" "$expected" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + _contacts_arr=( + ['testaddctt1@email.com']='Test Add Contact 1' + ) + + add_contacts '_contacts_arr' + ret="$?" + output="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name, email FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email LIKE 'testaddctt%';")" + expected='|testaddctt0@email.com +Test Add Contact 1|testaddctt1@email.com' + assert_equals_helper 'Contact was not created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + _contacts_arr=( + ['testaddctt2@email.com']='Test Add Contact 2' + ['testaddctt3@email.com']='Test Add Contact 3' + ) + + add_contacts '_contacts_arr' + ret="$?" + output="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name, email FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email LIKE 'testaddctt%';")" + expected='|testaddctt0@email.com +Test Add Contact 1|testaddctt1@email.com +Test Add Contact 2|testaddctt2@email.com +Test Add Contact 3|testaddctt3@email.com' + assert_equals_helper 'Contacts were not created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + _contacts_arr=( + ['testaddctt4@email.com']='Test Add Contact 4' + ['testaddctt4@email.com']='Test Add Contact 4' + ) + add_contacts '_contacts_arr' + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name, email FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email='testaddctt4@email.com';") + expected='Test Add Contact 4|testaddctt4@email.com' + assert_equals_helper 'Contacts were not created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + _contacts_arr=( + ['testaddctt4@email.com']='Test Add Contact 4.1' + ) + + (printf 'y\n' | add_contacts '_contacts_arr') + + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name, email FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email='testaddctt4@email.com';") + expected='Test Add Contact 4|testaddctt4@email.com' + assert_equals_helper 'Contacts were not created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + _contacts_arr=( + ['testaddctt4@email.com']='Test Add Contact 4.2' + ) + + (printf 'n\n' | add_contacts '_contacts_arr') + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT name FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email='testaddctt4@email.com';") + expected='Test Add Contact 4.2' + assert_equals_helper 'Contacts were not created' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_add_contact_group() +{ + declare -A _contacts_arr + local group_id + local expected + local output + local ret + + # valid cases + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" ('name') VALUES ('add_contact_group');" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES ('test contact group', 'testaddcttgp1@email.com');" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES ('test contact group', 'testaddcttgp2@email.com');" + + group_id=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='add_contact_group';") + expected=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_CONTACT}\" WHERE name='test contact group' ;") + + _contacts_arr=( + ['testaddcttgp1@email.com']='test contact group 1' + ['testaddcttgp2@email.com']='test contact group 2' + ) + + add_contact_group _contacts_arr "$group_id" + ret="$?" + + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT contact_id FROM \"${DATABASE_TABLE_CONTACT_GROUP}\" WHERE group_id=\"${group_id}\";") + assert_equals_helper 'Expected successful addition of contacts to group' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + # invalid cases + output=$(add_contact_group _contacts_arr "$group_id") + ret="$?" + expected="" + assert_equals_helper 'Expected no addition as contacts are already in the group' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + _contacts_arr=(['nonexistent@example.com']='') + output=$(add_contact_group _contacts_arr "$group_id" 2> /dev/null) + ret="$?" + expected=$'Error while trying to insert contact group into the database with the command:\nsqlite3 -init ' + expected+="${KW_DB_DIR}/pre_cmd.sql \"${KW_DATA_DIR}/kw.db\" " + expected+="-batch \"INSERT INTO email_contact_group (contact_id, group_id) VALUES ('','2');\"" + assertContains 'Expected sql error - Foreign key contraint failed' "$output" "$expected" + assert_equals_helper 'Expected error' "$LINENO" "$ret" 22 +} + +function test_remove_contact() +{ + local expected + local output + local ret + + local contact_id + + # invalid values + output=$(remove_contact "abc1'" 2> /dev/null) + ret="$?" + expected=$'Error while removing contact from the database with the command:\nsqlite3 -init ' + expected+="${KW_DB_DIR}/pre_cmd.sql \"${KW_DATA_DIR}/kw.db\" " + expected+="-batch \"DELETE FROM email_contact WHERE id='abc1'' ;\"" + assertContains 'Contact was not removed' "$output" "$expected" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + remove_contact 99999999 # Unexistent id + ret="$?" + expected='' + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES ('Remove Contact Group', 'rmcttgroup@email.com') ;" + contact_id="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email='rmcttgroup@email.com' ;")" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT_GROUP}\" (contact_id, group_id) VALUES (\"${contact_id}\", \"${TEST_GROUP_ID}\") ;" + + remove_contact "$contact_id" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT * FROM \"${DATABASE_TABLE_CONTACT}\" WHERE id=\"${contact_id}\" ;") + ret="$?" + expected='' + assert_equals_helper 'Contact was not removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT * FROM \"${DATABASE_TABLE_CONTACT_GROUP}\" WHERE contact_id=\"${contact_id}\" ;") + assert_equals_helper 'Contact was not removed' "$LINENO" "$expected" "$output" +} + +function test_remove_email_contact() +{ + local expected + local output + local ret + + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES ('Remove Contact', 'rmctt@email.com') ;" + contact_id="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email='rmctt@email.com' ;")" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT_GROUP}\" (contact_id, group_id) VALUES (\"${contact_id}\", \"${TEST_GROUP_ID}\") ;" + + # invalid values + output=$(remove_email_contact '' 'rmctt@email.com') + ret="$?" + expected='Error, the group name is empty' + assert_equals_helper 'Contact should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 61 + + output=$(remove_email_contact "$TEST_GROUP_NAME" '') + ret="$?" + expected='Error, contact email is empty' + assert_equals_helper 'Contact should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 61 + + output=$(remove_email_contact 'unexistent_group' 'rmctt@email.com') + ret="$?" + expected='Error, this group doesnt exist' + assert_equals_helper 'Contact should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + output=$(remove_email_contact 'unexistent_group' 'unexistent_contact@email.com') + ret="$?" + expected='Error, this group doesnt exist' + assert_equals_helper 'Contact should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 22 + + # valid values + remove_email_contact "$TEST_GROUP_NAME" 'rmctt@email.com' + ret="$?" + output=$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT * FROM \"${DATABASE_TABLE_CONTACT}\" WHERE email='rmctt@email.com' ;") + expected='' + assert_equals_helper 'Contact should not have been removed' "$LINENO" "$expected" "$output" + assert_equals_helper 'Expected no error' "$LINENO" "$ret" 0 +} + +function test_show_email_groups() +{ + local output + local expected + local ret + local date_now + + date_now="$(date +"%Y-%m-%d")" + + output=$(show_email_groups '' 150) + + expected=$'ID |Name |Contacts |Created at \n' + expected+=$'------------------------------------------------------------------------------------------------------------------------------------------------------\n' + expected+="1 |TEST_GROUP |1 |${date_now} " + expected+=$'\n------------------------------------------------------------------------------------------------------------------------------------------------------' + + assert_equals_helper 'Testing show kw mail groups' "$LINENO" "$output" "$expected" + + output=$(show_email_groups "${TEST_GROUP_NAME}" 150) + expected=$'----------------------------------------------------------------------TEST_GROUP----------------------------------------------------------------------\n' + expected+=$'ID |Name |Email |Associated Groups |Created at \n' + expected+=$'------------------------------------------------------------------------------------------------------------------------------------------------------\n' + expected+="1 |name |email |1 |${date_now} " + expected+=$'\n------------------------------------------------------------------------------------------------------------------------------------------------------' + assert_equals_helper 'Testing show kw mail groups' "$LINENO" "$output" "$expected" +} + +function test_manage_contacts_parser() +{ + local expected + local output + local ret + + parse_manage_contacts_options '--group-create' 'fake_group' + expected='1' + assert_equals_helper 'Set group-create' "$LINENO" "${options_values['GROUP_CREATE']}" "$expected" + expected='fake_group' + assert_equals_helper 'Set group-create' "$LINENO" "${options_values['GROUP']}" "$expected" + + parse_manage_contacts_options '-c' 'fake_group' + expected='1' + assert_equals_helper 'Set group-create' "$LINENO" "${options_values['GROUP_CREATE']}" "$expected" + expected='fake_group' + assert_equals_helper 'Set group-create' "$LINENO" "${options_values['GROUP']}" "$expected" + + parse_manage_contacts_options '--group-remove' 'fake_group' + expected='1' + assert_equals_helper 'Set group-remove' "$LINENO" "${options_values['GROUP_REMOVE']}" "$expected" + expected='fake_group' + assert_equals_helper 'Set group-create' "$LINENO" "${options_values['GROUP']}" "$expected" + + parse_manage_contacts_options '-r' 'fake_group' + expected='1' + assert_equals_helper 'Set group-remove' "$LINENO" "${options_values['GROUP_REMOVE']}" "$expected" + expected='fake_group' + assert_equals_helper 'Set group-create' "$LINENO" "${options_values['GROUP']}" "$expected" + + parse_manage_contacts_options '--group-rename' 'fake_group:new_group' + expected='fake_group' + assert_equals_helper 'Set group-rename' "$LINENO" "${options_values['GROUP']}" "$expected" + expected='new_group' + assert_equals_helper 'Set group-rename' "$LINENO" "${options_values['GROUP_RENAME']}" "$expected" + + parse_manage_contacts_options '--group-add' 'group:ctt1 , ctt2 ' + expected='ctt1 , ctt2 ' + assert_equals_helper 'Set group add' "$LINENO" "${options_values['GROUP_ADD']}" "$expected" + expected='group' + assert_equals_helper 'Set group add' "$LINENO" "${options_values['GROUP']}" "$expected" + + + parse_manage_contacts_options '--group-remove-email' 'group:email' + expected='email' + assert_equals_helper 'Set group remove-email' "$LINENO" "${options_values['GROUP_REMOVE_EMAIL']}" "$expected" + expected='group' + assert_equals_helper 'Set group remove-email' "$LINENO" "${options_values['GROUP']}" "$expected" + + parse_manage_contacts_options '--group-show=' + expected='' + assert_equals_helper 'Set group show' "$LINENO" "${options_values['GROUP']}" "$expected" + expected=1 + assert_equals_helper 'Set group show' "$LINENO" "${options_values['GROUP_SHOW']}" "$expected" + + parse_manage_contacts_options '--group-show=test' + expected='test' + assert_equals_helper 'Set group show' "$LINENO" "${options_values['GROUP']}" "$expected" + expected=1 + assert_equals_helper 'Set group show' "$LINENO" "${options_values['GROUP_SHOW']}" "$expected" +} + +invoke_shunit diff --git a/tests/unit/lib/kw_string_test.sh b/tests/unit/lib/kw_string_test.sh index d6ea0794c..9ee2203ef 100755 --- a/tests/unit/lib/kw_string_test.sh +++ b/tests/unit/lib/kw_string_test.sh @@ -335,6 +335,36 @@ function test_str_has_special_characters() output=$(str_has_special_characters 'We have a special char!') assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char@') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char#') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char$') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char^') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char&') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char()') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char)') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char+') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char%') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" + + output=$(str_has_special_characters 'We have a special char,') + assert_equals_helper 'We expected a special char here' "$LINENO" 0 "$?" } function test_str_get_value_under_double_quotes() @@ -465,4 +495,21 @@ function test_string_to_unix_filename() assert_equals_helper 'Curly braces should be removed' "$LINENO" "$expected" "$output" } +function test_str_get_char_position() +{ + local output + local ret + local expected + + # Valid Cases + output=$(str_get_char_position "get char ^ position" '^') + assert_equals_helper 'Char position should be right' "$LINENO" 10 "$output" + + output=$(str_get_char_position "get char ^ position ^" '^') + assert_equals_helper 'Char position should be right' "$LINENO" 10 "$output" + + output=$(str_get_char_position "get unexsistent char position" '^') + assert_equals_helper 'Char position should be right' "$LINENO" 0 "$output" +} + invoke_shunit diff --git a/tests/unit/send_patch_test.sh b/tests/unit/send_patch_test.sh index 1adbde4aa..7e8830eae 100755 --- a/tests/unit/send_patch_test.sh +++ b/tests/unit/send_patch_test.sh @@ -12,6 +12,10 @@ function oneTimeSetUp() export KW_ETC_DIR="$SHUNIT_TMPDIR/etc/" export KW_CACHE_DIR="$SHUNIT_TMPDIR/cache/" + export KW_DATA_DIR="${SHUNIT_TMPDIR}" + + DB_FILES="$(realpath './tests/unit/samples/db_files')" + KW_DB_DIR="$(realpath './database')" mk_fake_kernel_root "$FAKE_KERNEL" mkdir -p "$KW_ETC_DIR/mail_templates/" @@ -46,12 +50,48 @@ function setUp() { declare -gA options_values declare -gA set_confs + + setupDatabase } function tearDown() { unset options_values unset set_confs + + tearDownDatabase +} + +function setupDatabase() +{ + declare -g TEST_GROUP1_NAME='TEST_GROUP1' + declare -g TEST_GROUP2_NAME='TEST_GROUP2' + declare -g TEST_CONTACT1_INFOS=('name1' 'email1@gmail.com') + declare -g TEST_CONTACT2_INFOS=('name2' 'email2@gmail.com') + declare -g TEST_GROUP1_ID + declare -g TEST_GROUP2_ID + + execute_sql_script "${KW_DB_DIR}/kwdb.sql" > /dev/null 2>&1 + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" (name) VALUES (\"${TEST_GROUP1_NAME}\");" + + TEST_GROUP1_ID="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='${TEST_GROUP1_NAME}';")" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES (\"${TEST_CONTACT1_INFOS[0]}\",\"${TEST_CONTACT1_INFOS[1]}\");" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT_GROUP}\" (contact_id, group_id) VALUES (1,1);" + + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_GROUP}\" (name) VALUES (\"${TEST_GROUP2_NAME}\");" + + TEST_GROUP2_ID="$(sqlite3 "${KW_DATA_DIR}/kw.db" -batch "SELECT id FROM \"${DATABASE_TABLE_GROUP}\" WHERE name='${TEST_GROUP2_NAME}';")" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT}\" (name, email) VALUES (\"${TEST_CONTACT2_INFOS[0]}\",\"${TEST_CONTACT2_INFOS[1]}\");" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT_GROUP}\" (contact_id, group_id) VALUES (2,2);" + sqlite3 "${KW_DATA_DIR}/kw.db" -batch "INSERT INTO \"${DATABASE_TABLE_CONTACT_GROUP}\" (contact_id, group_id) VALUES (1,2);" +} + +function tearDownDatabase() +{ + is_safe_path_to_remove "${KW_DATA_DIR}/kw.db" + if [[ "$?" == 0 ]]; then + rm "${KW_DATA_DIR}/kw.db" + fi } function test_validate_encryption() @@ -494,20 +534,96 @@ function test_mail_send() expected='git send-email --to="mail@test.com" extra_args --other_arg -13 -v2' assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + parse_mail_options "--to-groups=${TEST_GROUP1_NAME}" 'HEAD~' + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT1_INFOS[1]}\" HEAD~" + assert_equals_helper 'Testing send with patch option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP1_NAME}" -13 -v2 extra_args -- --other_arg + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT1_INFOS[1]}\" extra_args --other_arg -13 -v2" + assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP1_NAME}" '--to=mail@test.com' -13 -v2 extra_args -- --other_arg + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"mail@test.com,${TEST_CONTACT1_INFOS[1]}\" extra_args --other_arg -13 -v2" + assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" 'HEAD~' + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" HEAD~" + assert_equals_helper 'Testing send with patch option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" -13 -v2 extra_args -- --other_arg + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" extra_args --other_arg -13 -v2" + assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" '--to=mail@test.com' -13 -v2 extra_args -- --other_arg + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"mail@test.com,${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" extra_args --other_arg -13 -v2" + assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + parse_mail_options '--to=mail@test.com' parse_configuration "$KW_MAIL_CONFIG_SAMPLE" send_patch_config + output=$(mail_send 'TEST_MODE') expected='git send-email --to="mail@test.com" --annotate --no-chain-reply-to --thread @^' assert_equals_helper 'Testing default option' "$LINENO" "$expected" "$output" parse_mail_options '--to=mail@test.com' '@^^' - parse_configuration "$KW_CONFIG_SAMPLE" output=$(mail_send 'TEST_MODE') expected='git send-email --to="mail@test.com" --annotate --cover-letter --no-chain-reply-to --thread @^^' assert_equals_helper 'Testing default option' "$LINENO" "$expected" "$output" + output=$(mail_send 'TEST_MODE') + expected='git send-email --to="mail@test.com" --annotate --cover-letter --no-chain-reply-to --thread @^^' + assert_equals_helper 'Testing default option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP1_NAME}" + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT1_INFOS[1]}\" --annotate --no-chain-reply-to --thread @^" + assert_equals_helper 'Testing default option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP1_NAME}" '@^^' + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT1_INFOS[1]}\" --annotate --cover-letter --no-chain-reply-to --thread @^^" + assert_equals_helper 'Testing default option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" --annotate --no-chain-reply-to --thread @^" + assert_equals_helper 'Testing send with patch option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" '@^^' + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" --annotate --cover-letter --no-chain-reply-to --thread @^^" + assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" '--to=mail@test.com' + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"mail@test.com,${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" --annotate --no-chain-reply-to --thread @^" + assert_equals_helper 'Testing send with patch option' "$LINENO" "$expected" "$output" + + parse_mail_options "--to-groups=${TEST_GROUP2_NAME}" '--to=mail@test.com' '@^^' + + output=$(mail_send 'TEST_MODE') + expected="git send-email --to=\"mail@test.com,${TEST_CONTACT2_INFOS[1]},${TEST_CONTACT1_INFOS[1]}\" --annotate --cover-letter --no-chain-reply-to --thread @^^" + assert_equals_helper 'Testing no options option' "$LINENO" "$expected" "$output" + cd "$ORIGINAL_DIR" || { ret="$?" fail "($LINENO): Failed to move back to original dir"