diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3375849..022ed4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,7 @@ name: "Deploy" on: release: + types: [ published ] jobs: deploy: name: "Deploy Release" diff --git a/handlers.js b/handlers.js index 65a94c4..fa23dc2 100644 --- a/handlers.js +++ b/handlers.js @@ -10,7 +10,8 @@ import {buildActionResponse} from './helpers/response.js'; */ export async function updateWinnerCardHandler(requestBody) { const names = requestBody.names; - const winner = getRandomWinners(names); + const winnerCount = requestBody.count ?? 1; + const winner = getRandomWinners(names, winnerCount); const messageText = `Congratulations! We have shuffled the list of names and the winner is *${winner.join(',')}*.`; const message = buildMessageBody(buildNameListWinnerSection(names, winner), messageText); const request = { @@ -25,9 +26,10 @@ export async function updateWinnerCardHandler(requestBody) { * @param {array} names - list of name that will be shuffled * @param {string} space - google chat space name * @param {string} thread - chat thread/parent + * @param {integer} count - winner count * @returns {Promise} will post the message to google API */ -export async function createMessageFromNameListHandler(names, space, thread = null) { +export async function createMessageFromNameListHandler(names, space, thread = null, count = 1) { const cardSection = buildNameListSection(names); const message = buildMessageBody(cardSection); @@ -43,6 +45,7 @@ export async function createMessageFromNameListHandler(names, space, thread = nu const payload = { messageId, names: names, + count, }; await delayUpdateMessage(JSON.stringify(payload)); } @@ -55,8 +58,8 @@ export function helpCommandHandler(event) { const message = `Hi ${event.user.displayName} Here are the list of available commands: */random* Opens a dialog where you can input the items/names to be shuffled. By default, it is pre-filled with the list of members in the current space. - */random_members* Quickly get a member of the current space. It's using a simple animation during randomizing - */random_gpt* Get quick random staff using GPT command + */random_members {count}* Quickly get a member of the current space. It's using a simple animation during randomizing + */random_gpt {your_prompt}* Get quick random staff using GPT command example 1: */random_gpt number from 1 to 100* it will return a number between 1 to 100 (e.g 12) example 2: */random_gpt place to visit in Egypt* it will return a random place in Egypt example 3: */random_gpt joke about programmer* it will return a joke related to programmer @@ -66,6 +69,7 @@ export function helpCommandHandler(event) { Discover the power of randomization by mentioning this app. By enclosing your request within double quotes, you can retrieve a random staff from the chat message. Alternatively, without double quotes, the app will utilize your message as a GPT command to generate a staff for you. example 1(with double quote): *@Randombot "Zubair Manta" "Hasan Star" "Kawasaki Honda"* will shuffle the list given example 2(without double quote): *@Randombot number between 10 and 20* just like */random_gpt* command, it will return a number between 10 and 20 + example 3: *@Randombot number between 10 and 20* just like */random_gpt* command, it will return a number between 10 and 20 `; return { thread: event.message.thread, diff --git a/helpers/utils.js b/helpers/utils.js index 94c5646..299255c 100644 --- a/helpers/utils.js +++ b/helpers/utils.js @@ -15,7 +15,7 @@ export function getRandomWinners(names, winnerCount = 1) { * @param {string} string - text that will be extracted * @returns {array} list of extracted text */ -export function extractMessage(string) { +export function extractMessageByDoubleQuote(string) { const regex = /"[^"]+"/g; const extracted = string.match(regex); if (extracted) { @@ -23,3 +23,23 @@ export function extractMessage(string) { } return []; } + +/** + * @param {string} string - text that will be extracted + * @returns {array} list of extracted text + */ +export function extractMessageAndConfig(string) { + const regex = /"[^"]+"|[^\s]+/g; + return string.match(regex).map((s) => s.replace(/"(.+)"/, '$1')); +} + +/** + * Config means anything else beside string inside quote + * @param {string} argumentText - + * @param {array} messages - extracted messages + * @returns {array} extracted command + */ +export function extractConfig(argumentText, messages) { + const extractedTextCommands = extractMessageAndConfig(argumentText); + return extractedTextCommands.filter((val) => !messages.includes(val)); +} diff --git a/index.js b/index.js index b1ef8d1..cf968af 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,7 @@ import { helpCommandHandler, updateWinnerCardHandler, } from './handlers.js'; -import {extractMessage} from './helpers/utils.js'; +import {extractConfig, extractMessageByDoubleQuote} from './helpers/utils.js'; import {buildInputForm} from './helpers/components.js'; import {getRandomFromGpt} from './helpers/gpt.js'; @@ -43,7 +43,18 @@ export async function app(req, res) { } else if (message.slashCommand?.commandId === '2') { // /random_members command const members = await getMembers(event.space.name); const memberNames = members.map((a) => a.member.displayName); - await createMessageFromNameListHandler(memberNames, event.space.name, event.threadKey); + const winnerCount = parseInt(event.message.argumentText) || 1; + if (winnerCount > memberNames.length) { + reply = { + thread: event.message.thread, + actionResponse: { + type: 'NEW_MESSAGE', + }, + text: 'Your space members is not enough', + }; + } else { + await createMessageFromNameListHandler(memberNames, event.space.name, event.threadKey, winnerCount); + } } else if (message.slashCommand?.commandId === '3') { // /help command reply = helpCommandHandler(event); } else if (message.slashCommand?.commandId === '4') { // /config command @@ -59,9 +70,18 @@ export async function app(req, res) { }; } else if (message.text) { const argumentText = event.message?.argumentText; - const extractedText = extractMessage(argumentText); + const extractedText = extractMessageByDoubleQuote(argumentText); if (extractedText.length > 1) { - await createMessageFromNameListHandler(extractedText, event.space.name, event.threadKey); + let winnerCount = 1; + const configs = extractConfig(argumentText, extractedText); + configs.forEach((config) => { + const winnerConfig = parseInt(config); + // If the argument is a number, we will assume it is a config indicating the number of winners to choose. + if (winnerConfig && winnerConfig < extractedText.length) { + winnerCount = winnerConfig; + } + }); + await createMessageFromNameListHandler(extractedText, event.space.name, event.threadKey, winnerCount); } else { const answer = await getRandomFromGpt(argumentText ?? 'whatever'); reply = { @@ -78,8 +98,8 @@ export async function app(req, res) { if (action === 'create_shuffle') { const formValues = event.common?.formInputs; const items = formValues?.['items']?.stringInputs.value[0]?.trim(); - await createMessageFromNameListHandler(items.split('\n'), event.uspace.name, event.threadKey); - reply = buildActionResponseStatus('Your items/names are being shffle'); + await createMessageFromNameListHandler(items.split('\n'), event.space.name, event.threadKey); + reply = buildActionResponseStatus('Your items/names are being shuffle'); } } else if (event.type === 'ADDED_TO_SPACE') { const message = `Hi ${event.user.displayName ?? 'there'}, Thanks for installing our app diff --git a/tests/utils.test.js b/tests/utils.test.js index 4191574..88df763 100644 --- a/tests/utils.test.js +++ b/tests/utils.test.js @@ -1,4 +1,9 @@ -import {extractMessage, getRandomWinners} from '../helpers/utils.js'; +import { + extractConfig, + extractMessageAndConfig, + extractMessageByDoubleQuote, + getRandomWinners, +} from '../helpers/utils.js'; test('get the winner', () => { const names = ['Ibrahim', 'Isa', 'Moses', 'Ismail']; @@ -17,15 +22,63 @@ const dataSet = [ '"anu kae" "super" "sekali kae lo"', [ 'anu kae', 'super', 'sekali kae lo', ]], + [ + '"Indonesia" "Malaysia" Bali', ['Indonesia', 'Malaysia'], + ], [ 'nganu kae', [], ], [ 'z', [], ], + [ + '', [], + ], +]; +it.each(dataSet)('Extract message using inside quote only', (input, expectedValue) => { + const extractedStrings = extractMessageByDoubleQuote(input); + + expect(extractedStrings).toEqual(expectedValue); +}); + +const dataSet2 = [ + [ + '"anu kae" "super" "sekali kae lo"', [ + 'anu kae', 'super', 'sekali kae lo', + ]], + [ + '"Indonesia" "Malaysia" Bali', ['Indonesia', 'Malaysia', 'Bali'], + ], + [ + 'nganu kae', ['nganu', 'kae'], + ], + [ + 'z', ['z'], + '', [], + ], +]; +it.each(dataSet2)('Extract message and command', (input, expectedValue) => { + const extractedStrings = extractMessageAndConfig(input); + + expect(extractedStrings).toEqual(expectedValue); +}); + +const dataSet3 = [ + [ + '"anu kae" "super" "sekali kae lo"', []], + [ + '"Indonesia" "Malaysia" Bali', ['Bali'], + ], + [ + 'nganu kae', ['nganu', 'kae'], + ], + [ + 'z', ['z'], + '', [], + ], ]; -it.each(dataSet)('Extract message using regex', (input, expectedValue) => { - const extractedStrings = extractMessage(input); +it.each(dataSet3)('Extract message and command', (input, expectedValue) => { + const extractedStrings = extractConfig(input, extractMessageByDoubleQuote(input)); expect(extractedStrings).toEqual(expectedValue); });