From d2913b9ec9a17c2559be3c47ca31d77f4debfdbc Mon Sep 17 00:00:00 2001 From: Bing Wen Tan Date: Sun, 1 Sep 2024 15:55:24 +0800 Subject: [PATCH 1/4] changed voting categories --- checkers-app/src/components/myvotes/index.tsx | 12 +- .../src/components/vote/VoteCategories.tsx | 105 ++++++++++++++---- .../src/components/vote/VoteResult.tsx | 22 ++-- .../src/components/vote/VotingChart.tsx | 16 ++- checkers-app/src/components/vote/index.tsx | 3 + .../src/components/vote/nvcOptions.tsx | 62 +++++++++++ checkers-app/src/services/api.ts | 7 +- .../src/definitions/api/handlers/getVote.ts | 12 ++ .../api/handlers/patchVoteRequest.ts | 34 +++++- .../api/handlers/postVoteRequest.ts | 1 + functions/src/definitions/api/interfaces.ts | 4 + functions/src/definitions/common/counters.ts | 69 +++++++++--- .../definitions/common/parameters/others.json | 4 + .../common/parameters/userResponses.json | 22 ++-- .../src/definitions/common/responseUtils.ts | 11 ++ .../definitions/common/sendTelegramMessage.ts | 2 +- .../src/definitions/common/statistics.ts | 13 ++- functions/src/definitions/common/utils.ts | 13 ++- .../eventHandlers/onInstanceCreate.ts | 1 + .../eventHandlers/onVoteRequestUpdate.ts | 99 +++++++++++++---- .../definitions/eventHandlers/userHandlers.ts | 2 + functions/src/types.ts | 6 + 22 files changed, 430 insertions(+), 90 deletions(-) create mode 100644 checkers-app/src/components/vote/nvcOptions.tsx create mode 100644 functions/src/definitions/common/parameters/others.json diff --git a/checkers-app/src/components/myvotes/index.tsx b/checkers-app/src/components/myvotes/index.tsx index f8ea06b0..fd9bd9c9 100644 --- a/checkers-app/src/components/myvotes/index.tsx +++ b/checkers-app/src/components/myvotes/index.tsx @@ -8,18 +8,20 @@ export default function MyVotes() { const location = useLocation(); useEffect(() => { - console.log(location) if (location.state) { if (location.state.status) { - setActiveTab(location.state.status) + setActiveTab(location.state.status); } } - }, [location, activeTab]) - + }, [location, activeTab]); + return (
- + {/* */}
diff --git a/checkers-app/src/components/vote/VoteCategories.tsx b/checkers-app/src/components/vote/VoteCategories.tsx index b4558af6..3a34fed0 100644 --- a/checkers-app/src/components/vote/VoteCategories.tsx +++ b/checkers-app/src/components/vote/VoteCategories.tsx @@ -15,12 +15,25 @@ import { useUser } from "../../providers/UserContext"; import { TooltipWithHelperIcon } from "../common/ToolTip"; import InfoOptions from "./InfoOptions"; +import NVCOptions from "./nvcOptions"; interface PropType { messageId: string | null; voteRequestId: string | null; currentCategory: string | null; currentTruthScore: number | null; + currentTags: string[] | null; +} + +function getSelectedCategory(primaryCategory: string | null, tags: string[]) { + switch (primaryCategory) { + case "irrelevant": //INCORRECT USAGE + return tags.includes("incorrect") ? "incorrect" : "nvc"; + case "legitimate": + return "nvc"; + default: + return primaryCategory; + } } const CATEGORIES = [ @@ -42,7 +55,7 @@ const CATEGORIES = [ icon: , display: "News/Info/Opinion", description: - "Messages intended to inform/convince/mislead a broad base of people", + "Content intended to inform/convince/mislead a broad base of people", }, { name: "satire", @@ -53,27 +66,28 @@ const CATEGORIES = [ { name: "spam", icon: , - display: "Spam", - description: "Unsolicited spam, such as marketing messages", + display: "Marketing/Spam", + description: + "Content intended to (i) promote or publicise a non-malicious product, service or event or (ii) convince recipient to spread non-malicious messages to others", }, { - name: "legitimate", + name: "nvc", icon: , - display: "Legitimate", + display: "No Verifiable Content", description: - "Legitimate source but can't be assessed, e.g. transactional messages", + "Content that isn't capable of being checked using publicly-available information due to its nature", }, { - name: "irrelevant", + name: "incorrect", icon: , - display: "Trivial", - description: "Trivial/banal messages with nothing to assess", + display: "Incorrect Usage", + description: "User trying to chat or send in queries", }, { name: "unsure", icon: , display: "Unsure", - description: "Insufficient information to decide", + description: "Insufficient information to assess", }, { name: "pass", @@ -89,13 +103,20 @@ export default function VoteCategories(Prop: PropType) { const currentCategory = Prop.currentCategory; const currentTruthScore = Prop.currentTruthScore; + const currentTags = Prop.currentTags ?? []; const messageId = Prop.messageId; const voteRequestId = Prop.voteRequestId; - const [category, setCategory] = useState(currentCategory); + const [selectedCategory, setSelectedCategory] = useState( + getSelectedCategory(currentCategory, currentTags) + ); + const [voteCategory, setVoteCategory] = useState( + currentCategory + ); //take global values from user context const [truthScore, setTruthScore] = useState( currentTruthScore ); + const [tags, setTags] = useState(currentTags); const handleTruthScoreChange = ( event: React.ChangeEvent @@ -103,19 +124,53 @@ export default function VoteCategories(Prop: PropType) { setTruthScore(Number(event.target.value)); }; - const handleVote = (categoryName: string) => { - setCategory(categoryName); + const handleL2VoteChange = (event: React.ChangeEvent) => { + handleVoteCategoryChange(event.target.value); + }; + + const handleVoteCategoryChange = (category: string) => { + console.log("current tags:" + currentTags); + switch (category) { + case "incorrect": + setVoteCategory("irrelevant"); + setTags(["incorrect"]); + break; + default: + setVoteCategory(category); + setTags([]); + break; + } + }; + + const handleSelection = (categoryName: string) => { + setSelectedCategory(categoryName); + + switch (categoryName) { + case "nvc": + break; + case "incorrect": + handleVoteCategoryChange("incorrect"); + break; + default: + handleVoteCategoryChange(categoryName); + break; + } }; //function to update vote request in firebase - const handleSubmitVote = (category: string, truthScore: number | null) => { + const handleSubmitVote = ( + category: string, + truthScore: number | null, + tags: string[] | null + ) => { if (messageId && voteRequestId) { //call api to update vote patchVote( messageId, voteRequestId, category, - category === "info" ? truthScore : null + category === "info" ? truthScore : null, + tags ) .then(() => { incrementSessionVotedCount(); @@ -134,10 +189,12 @@ export default function VoteCategories(Prop: PropType) { {/* Conditionally render InfoOptions right after the "info" button if it has been selected */} - {category === "info" && cat.name === "info" && ( + {selectedCategory === "info" && cat.name === "info" && ( )} + {selectedCategory === "nvc" && cat.name === "nvc" && ( + + )} ))} - {category ? ( + {voteCategory ? (
diff --git a/checkers-app/src/components/vote/VoteResult.tsx b/checkers-app/src/components/vote/VoteResult.tsx index 0a78ecfd..18ce37ff 100644 --- a/checkers-app/src/components/vote/VoteResult.tsx +++ b/checkers-app/src/components/vote/VoteResult.tsx @@ -1,9 +1,10 @@ import { Typography } from "@material-tailwind/react"; import { XMarkIcon } from "@heroicons/react/24/solid"; import { ShieldExclamationIcon } from "@heroicons/react/24/solid"; -import { FaceFrownIcon } from "@heroicons/react/24/solid"; -import { CheckCircleIcon } from "@heroicons/react/24/solid"; +import { MegaphoneIcon } from "@heroicons/react/24/solid"; import { HandThumbUpIcon } from "@heroicons/react/20/solid"; +import { NoSymbolIcon } from "@heroicons/react/24/solid"; +import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/solid"; import { QuestionMarkCircleIcon } from "@heroicons/react/20/solid"; import { NewspaperIcon } from "@heroicons/react/20/solid"; import { FaceSmileIcon } from "@heroicons/react/20/solid"; @@ -11,6 +12,7 @@ import { FaceSmileIcon } from "@heroicons/react/20/solid"; interface PropType { category: string | null; truthScore: number | null; + tags: string[]; } export default function VoteResult(Prop: PropType) { @@ -33,15 +35,21 @@ export default function VoteResult(Prop: PropType) { catIcon = ; break; case "spam": - catName = "Spam"; - catIcon = ; + catName = "Marketing/Spam"; + catIcon = ; break; case "irrelevant": - catName = "Trivial"; - catIcon = ; + if (Prop.tags?.includes("incorrect")) { + //INCORRECT USAGE + catName = "Incorrect Usage"; + catIcon = ; + } else { + catName = "NVC-Can't Tell"; + catIcon = ; + } break; case "legitimate": - catName = "Legitimate"; + catName = "NVC-Credible"; catIcon = ; break; case "satire": diff --git a/checkers-app/src/components/vote/VotingChart.tsx b/checkers-app/src/components/vote/VotingChart.tsx index f8d76641..312ed5f4 100644 --- a/checkers-app/src/components/vote/VotingChart.tsx +++ b/checkers-app/src/components/vote/VotingChart.tsx @@ -35,6 +35,9 @@ export default function VotingChart(Props: VotingChartProps) { 5: assessedInfo.infoCount["5"], }; + const irrelevantCount = assessedInfo.irrelevantCount; + const incorrectCount = assessedInfo.tagCounts.incorrect ?? 0; //INCORRECT USAGE + const data = [ { name: "Scam", @@ -50,16 +53,17 @@ export default function VotingChart(Props: VotingChartProps) { count: assessedInfo.satireCount, }, { - name: "Spam", + name: "Marketing/Spam", count: assessedInfo.spamCount, }, { - name: "Trivial", - count: assessedInfo.irrelevantCount, + name: "No Verifiable Content", + credible: assessedInfo.legitimateCount, + notsure: irrelevantCount - incorrectCount, }, { - name: "Legit", - count: assessedInfo.legitimateCount, + name: "Incorrect Usage", + count: incorrectCount, }, { name: "Unsure", @@ -90,6 +94,8 @@ export default function VotingChart(Props: VotingChartProps) { + + ); diff --git a/checkers-app/src/components/vote/index.tsx b/checkers-app/src/components/vote/index.tsx index 8825c7f8..0477e9c9 100644 --- a/checkers-app/src/components/vote/index.tsx +++ b/checkers-app/src/components/vote/index.tsx @@ -73,6 +73,7 @@ export default function VotePage() { voteRequestId={voteRequestId ?? null} currentCategory={vote.category} currentTruthScore={vote.truthScore} + currentTags={vote.tags} /> ) : ( @@ -88,6 +89,7 @@ export default function VotePage() {
@@ -100,6 +102,7 @@ export default function VotePage() {
diff --git a/checkers-app/src/components/vote/nvcOptions.tsx b/checkers-app/src/components/vote/nvcOptions.tsx new file mode 100644 index 00000000..36202f03 --- /dev/null +++ b/checkers-app/src/components/vote/nvcOptions.tsx @@ -0,0 +1,62 @@ +import { + Radio, + Typography, + Card, + ListItem, + List, +} from "@material-tailwind/react"; + +interface nvcOptionsProps { + selectedCategory: string | null; + onChange: (event: React.ChangeEvent) => void; +} + +//0-5 truth score radio buttons selection +export default function nvcOptions(Prop: nvcOptionsProps) { + const optionList = [ + { + category: "legitimate", + display: "Yes", + }, + { + category: "irrelevant", + display: "Cannot Tell", + }, + ]; + + return ( +
+ + Please assess the veracity of the claim(s) in the message on a scale + from 1 (entirely false) to 5 (entirely true). + + + + {optionList.map((option) => ( + + + {option.display} + + } + value={option.category} + onChange={Prop.onChange} + checked={Prop.selectedCategory === option.category} + crossOrigin="anonymous" + color="orange" + /> + + ))} + + +
+ ); +} diff --git a/checkers-app/src/services/api.ts b/checkers-app/src/services/api.ts index 09e54b81..6de666a6 100644 --- a/checkers-app/src/services/api.ts +++ b/checkers-app/src/services/api.ts @@ -142,7 +142,8 @@ export const patchVote = async ( messageId: string, voteRequestId: string, category: string, - truthScore: number | null + truthScore: number | null, + tags: string[] | null ) => { if (!messageId || !voteRequestId) { throw new Error("Message Id or Vote Request Id missing."); @@ -150,12 +151,16 @@ export const patchVote = async ( if (category === "info" && truthScore == null) { throw new Error("Truth score required for info vote."); } + if (tags === null) { + tags = []; + } return ( await axiosInstance.patch( `/api/messages/${messageId}/voteRequests/${voteRequestId}`, { category, truthScore, + tags, } ) ).data; diff --git a/functions/src/definitions/api/handlers/getVote.ts b/functions/src/definitions/api/handlers/getVote.ts index 68f5b791..a82e5521 100644 --- a/functions/src/definitions/api/handlers/getVote.ts +++ b/functions/src/definitions/api/handlers/getVote.ts @@ -61,6 +61,14 @@ const getVoteHandler = async (req: Request, res: Response) => { voteRequestSnap.get("truthScore") === undefined && voteRequestSnap.get("vote") !== undefined + const tags = voteRequestSnap.get("tags") ?? {} + const parentTags = messageSnap.get("tags") ?? {} + + //loop through tags, check that value is true, if so add to array + const tagArray = Object.keys(tags).filter((tag) => tags[tag]) + const parentTagArray = Object.keys(parentTags).filter( + (tag) => parentTags[tag] + ) const { irrelevantCount, scamCount, @@ -71,6 +79,7 @@ const getVoteHandler = async (req: Request, res: Response) => { unsureCount, satireCount, validResponsesCount, + tagCounts, } = await getVoteCounts(messageRef) //get counts from each truthScore @@ -147,13 +156,16 @@ const getVoteHandler = async (req: Request, res: Response) => { irrelevantCount: irrelevantCount, legitimateCount: legitimateCount, unsureCount: unsureCount, + tagCounts: tagCounts, truthScore: isLegacy ? messageSnap.get("legacyTruthScore") : messageSnap.get("truthScore"), + tags: parentTagArray, primaryCategory: messageSnap.get("primaryCategory"), rationalisation: messageSnap.get("rationalisation"), } : null, + tags: tagArray, } return res.status(200).send(returnData) } catch { diff --git a/functions/src/definitions/api/handlers/patchVoteRequest.ts b/functions/src/definitions/api/handlers/patchVoteRequest.ts index e5414b73..be958433 100644 --- a/functions/src/definitions/api/handlers/patchVoteRequest.ts +++ b/functions/src/definitions/api/handlers/patchVoteRequest.ts @@ -1,7 +1,7 @@ import { Request, Response } from "express" import { updateVoteRequest } from "../interfaces" import { Timestamp } from "firebase-admin/firestore" -import { VoteRequest } from "../../../types" +import { getTags } from "../../common/utils" import * as admin from "firebase-admin" if (!admin.apps.length) { @@ -19,7 +19,8 @@ const patchVoteRequestHandler = async (req: Request, res: Response) => { return res.status(400).send("Message Id or vote request Id missing.") } //confirm category in body - const { category, truthScore, reasoning } = req.body as updateVoteRequest + const { category, truthScore, reasoning, tags } = + req.body as updateVoteRequest if (!category) { return res.status(400).send("A category is required in the body") } @@ -55,6 +56,22 @@ const patchVoteRequestHandler = async (req: Request, res: Response) => { return res.status(400).send(`${category} is not a valid category`) } + const allowedTags = await getTags() + if (Array.isArray(tags)) { + const allElementsValid = tags.every( + (tag) => typeof tag === "string" && allowedTags.includes(tag) + ) + if (!allElementsValid) { + //check if tags are valid + return res + .status(400) + .send( + `Tags must be an array of strings, and each string must be one of ${allowedTags.join( + ", " + )}` + ) + } + } //check if vote request exists in firestore const voteRequestRef = db .collection("messages") @@ -65,12 +82,21 @@ const patchVoteRequestHandler = async (req: Request, res: Response) => { if (!voteRequestSnap.exists) { return res.status(404).send("vote request not found") } - await voteRequestRef.update({ + const updateObj = { category: category, truthScore: truthScore ?? null, votedTimestamp: Timestamp.fromDate(new Date()), reasoning: reasoning ?? null, - }) + tags: {} as { [key: string]: boolean }, + } + + // Add tags dynamically to the 'tags' field + if (tags) { + for (const tag of tags) { + updateObj.tags[tag] = true + } + } + await voteRequestRef.update(updateObj) return res.status(200).send({ success: true, }) diff --git a/functions/src/definitions/api/handlers/postVoteRequest.ts b/functions/src/definitions/api/handlers/postVoteRequest.ts index df141a3b..b7c6cafd 100644 --- a/functions/src/definitions/api/handlers/postVoteRequest.ts +++ b/functions/src/definitions/api/handlers/postVoteRequest.ts @@ -82,6 +82,7 @@ const postVoteRequestHandler = async (req: Request, res: Response) => { category: null, truthScore: null, reasoning: null, + tags: {}, createdTimestamp: Timestamp.fromDate(new Date()), acceptedTimestamp: Timestamp.fromDate(new Date()), votedTimestamp: null, diff --git a/functions/src/definitions/api/interfaces.ts b/functions/src/definitions/api/interfaces.ts index e211c3b3..930ae8a3 100644 --- a/functions/src/definitions/api/interfaces.ts +++ b/functions/src/definitions/api/interfaces.ts @@ -19,6 +19,7 @@ interface updateVoteRequest { category: string truthScore?: number //between 1 and 5 reasoning?: string + tags?: string[] } interface createChecker { @@ -137,6 +138,7 @@ interface Vote { truthScore: number | null isAssessed: boolean //if the message is assessed finalStats: AssessedInfo | null + tags: string[] } interface Last30DaysStats { @@ -166,6 +168,7 @@ interface AssessedInfo { 4?: number | null 5?: number | null } + tagCounts: { [key: string]: number } satireCount: number spamCount: number irrelevantCount: number @@ -173,6 +176,7 @@ interface AssessedInfo { unsureCount: number truthScore: number primaryCategory: string + tags: string[] rationalisation: string | null } diff --git a/functions/src/definitions/common/counters.ts b/functions/src/definitions/common/counters.ts index 141dccae..6872c074 100644 --- a/functions/src/definitions/common/counters.ts +++ b/functions/src/definitions/common/counters.ts @@ -1,7 +1,7 @@ import { FieldValue } from "@google-cloud/firestore" import { DocumentReference } from "firebase-admin/firestore" import * as admin from "firebase-admin" -import { getThresholds } from "./utils" +import { getThresholds, getTags } from "./utils" const db = admin.firestore() @@ -36,10 +36,35 @@ const getVoteCounts = async function ( messageRef: DocumentReference, isLegacy = false ) { + const tags = (await getTags()) as string[] const totalVoteRequestQuery = messageRef .collection("voteRequests") .count() .get() + // Create an array of promises for the tags + const tagPromises = tags.map((tag) => getCount(messageRef, tag)) + const otherPromises = [ + getCount(messageRef, "responses"), + getCount(messageRef, "pass"), + getCount(messageRef, "irrelevant"), + getCount(messageRef, "scam"), + getCount(messageRef, "illicit"), + getCount(messageRef, "info"), + getCount(messageRef, "spam"), + getCount(messageRef, "legitimate"), + getCount(messageRef, "unsure"), + getCount(messageRef, "satire"), + getCount(messageRef, "totalVoteScore"), + totalVoteRequestQuery, + getThresholds(), + ] + const allPromises = [ + ...otherPromises, // spread the other fixed promises + ...tagPromises, // spread the tag promises + ] + const results = await Promise.all(allPromises) + // Extract the tag counts first + const tagCounts = results.slice(otherPromises.length) as number[] const [ responsesCount, passCount, @@ -54,21 +79,28 @@ const getVoteCounts = async function ( voteTotal, voteRequestCountSnapshot, thresholds, - ] = await Promise.all([ - getCount(messageRef, "responses"), - getCount(messageRef, "pass"), - getCount(messageRef, "irrelevant"), - getCount(messageRef, "scam"), - getCount(messageRef, "illicit"), - getCount(messageRef, "info"), - getCount(messageRef, "spam"), - getCount(messageRef, "legitimate"), - getCount(messageRef, "unsure"), - getCount(messageRef, "satire"), - getCount(messageRef, "totalVoteScore"), - totalVoteRequestQuery, - getThresholds(), - ]) + ] = results.slice(0, otherPromises.length) as [ + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + number, + admin.firestore.AggregateQuerySnapshot< + { + count: admin.firestore.AggregateField + }, + admin.firestore.DocumentData, + admin.firestore.DocumentData + >, + any + ] // slice the results to get the fixed promises + const totalVoteRequestsCount = voteRequestCountSnapshot.data().count ?? 0 const factCheckerCount = totalVoteRequestsCount - passCount //don't count "error" votes in number of fact checkers, as this will slow the replies unnecessarily. const validResponsesCount = responsesCount - passCount //can remove in future and replace with nonErrorCount @@ -85,6 +117,10 @@ const getVoteCounts = async function ( harmlessCount += infoCount } } + const tagCountMap = tags.reduce((acc, tag, index) => { + acc[tag] = tagCounts[index] + return acc + }, {} as { [key: string]: number }) return { responsesCount, passCount, @@ -103,6 +139,7 @@ const getVoteCounts = async function ( harmfulCount, harmlessCount, factCheckerCount, + tagCounts: tagCountMap, } } diff --git a/functions/src/definitions/common/parameters/others.json b/functions/src/definitions/common/parameters/others.json new file mode 100644 index 00000000..a71f590b --- /dev/null +++ b/functions/src/definitions/common/parameters/others.json @@ -0,0 +1,4 @@ +{ + "supportedTypes": ["text", "image"], + "tags": ["incorrect", "generated"] +} diff --git a/functions/src/definitions/common/parameters/userResponses.json b/functions/src/definitions/common/parameters/userResponses.json index 21b71e42..6333c9a7 100644 --- a/functions/src/definitions/common/parameters/userResponses.json +++ b/functions/src/definitions/common/parameters/userResponses.json @@ -32,8 +32,8 @@ "cn": "{{thanks}}{{methodology}}很可疑!🚨{{image_caveat}}\n\n建议您停止交流⛔️⛔️\n\n查友会代表您向ScamShield (https://scamshield.org.sg) 举报这条可疑的短信。\n\n如果您不想举报此短信,请选择\"不举报\"。" }, "SPAM": { - "en": "{{thanks}}{{methodology}}*spam*!🚧{{image_caveat}}\n\nIt's likely harmless, but you should always make sure 🧐\n\n{{reporting_nudge}}Thank you for keeping Singapore safe!", - "cn": "{{thanks}}{{methodology}}是垃圾信息!🚧{{image_caveat}}\n\n虽然它看似无害,但请仍然保持警惕 🧐\n\n{{reporting_nudge}}感谢您对新加坡网络安全的支持和贡献!" + "en": "{{thanks}}{{methodology}}*marketing/viral content*!📣{{image_caveat}}\n\nIt's likely harmless, but you should always make sure 🧐\n\n{{reporting_nudge}}Thank you for keeping Singapore safe!", + "cn": "{{thanks}}{{methodology}}是营销/病毒式信息!📣{{image_caveat}}\n\n虽然它看似无害,但请仍然保持警惕 🧐\n\n{{reporting_nudge}}感谢您对新加坡网络安全的支持和贡献!" }, "LEGITIMATE": { "en": "{{thanks}}{{methodology}}*from a legitimate source*.✅{{image_caveat}}\n\n{{reporting_nudge}}Thank you for keeping Singapore safe!", @@ -60,7 +60,7 @@ "cn": "感谢您的耐心等待!" }, "IMAGE_CAVEAT": { - "en": "This assessment refers to the claims made within the captions, if any.", + "en": "This assessment refers to the claims made within the accompanying message.", "cn": "我们的评估基于图片标题中的内容。" }, "METHODOLOGY_HUMAN": { @@ -124,7 +124,7 @@ "cn": "我们不会将您的短信发送给ScamShield。感谢您与我们分享这条短信,也感谢您对新加坡网络安全的支持和贡献。" }, "MENU": { - "en": "{{prefix}}\n\nSelect \"Menu\" below to see what CheckMate can do! 👈\n\nDo note that CheckMate *is designed to check dubious messages you send in. It cannot converse freely with you*.\n\nAnytime you need a refresher on what CheckMate can do, type \"menu\" to get here again! 😊", + "en": "{{prefix}}\n\nSelect \"Menu\" below to see what CheckMate can do! 👈\n\nDo note that CheckMate *checks dubious messages and tells you whether you can trust them. It cannot converse with you or answer questions*.\n\nAnytime you need a refresher on what CheckMate can do, type \"menu\" to get here again! 😊", "cn": "{{prefix}}\n\n请点击“菜单\"查看查友的功能!👈\n\n请注意,查友只评估您发送的短信,它无法与您进行对话。\n\n您只需输入\"菜单\"即可随时返回这里,查看查友的功能!😊" }, "NEW_USER_PREFIX_EN": { @@ -140,13 +140,17 @@ "cn": "{{new_user_en}}\n\nPlease select your preferred language.\n\n{{new_user_cn}}请选择语言。" }, "IRRELEVANT_MENU_PREFIX": { - "en": "Thanks for waiting!🙏🏻 Our CheckMates didn't find anything to assess in this message.😕", + "en": "Thanks for waiting!🙏🏻 Our volunteer checkers were unable to assess this message.😕\n\nSorry about that!", "cn": "感谢您的耐心等待!🙏🏻 我们的查哥查妹没有在这条短信中找到可以评估的内容。😕" }, "IRRELEVANT_AUTO_MENU_PREFIX": { - "en": "Hmm...There doesn't seem to be anything to assess in this message.😕", + "en": "Hmm...we couldn't assess this message.😕\n\nSorry about that!", "cn": "嗯...这条短信似乎没有可以评估的内容。😕" }, + "INCORRECT": { + "en": "At this point, CheckMate is unable to answer questions directly, or converse freely with you. 😕\n\nTo use CheckMate, simply send us messages that you require checking. We will let you know whether the message can be trusted. There is no need to specially ask about it.\n\nWe apologise for the misunderstanding.", + "cn": "此时,查友无法直接回答问题或与您自由交谈。😕\n\n使用查友,只需发送您希望检查的消息,无需特别询问。我们会告诉您该消息是否可信。\n\n对因此造成的误解,我们深表歉意。" + }, "MENU_PREFIX": { "en": "Hi! Thanks for using CheckMate. 🙏🏻", "cn": "您好!感谢您使用查友。🙏🏻" @@ -388,8 +392,8 @@ "cn": "是准确的✅" }, "PLACEHOLDER_SPAM": { - "en": "spam🚧", - "cn": "是垃圾信息🚧" + "en": "marketing/viral content", + "cn": "是营销/病毒式信息📣" }, "PLACEHOLDER_LEGITIMATE": { "en": "legitimate✅", @@ -407,4 +411,4 @@ "en": "too difficult to assess", "cn": "很难做评估" } -} +} \ No newline at end of file diff --git a/functions/src/definitions/common/responseUtils.ts b/functions/src/definitions/common/responseUtils.ts index 71531173..296dfb6e 100644 --- a/functions/src/definitions/common/responseUtils.ts +++ b/functions/src/definitions/common/responseUtils.ts @@ -662,6 +662,7 @@ async function respondToInstance( const hasCaption = data?.caption != null const isMatched = data?.isMatched ?? false const primaryCategory = parentMessageSnap.get("primaryCategory") + const isIncorrect = parentMessageSnap.get("tags.incorrect") ?? false function getFinalResponseText(responseText: string) { return responseText @@ -766,6 +767,11 @@ async function respondToInstance( let responseText switch (category) { case "irrelevant_auto": + if (isIncorrect) { + responseText = getFinalResponseText(responses.INCORRECT) + await sendTextMessage("user", from, responseText, data.id) + break + } await sendMenuMessage( from, "IRRELEVANT_AUTO_MENU_PREFIX", @@ -775,6 +781,11 @@ async function respondToInstance( ) break case "irrelevant": + if (isIncorrect) { + responseText = getFinalResponseText(responses.INCORRECT) + await sendTextMessage("user", from, responseText, data.id) + break + } await sendMenuMessage( from, "IRRELEVANT_MENU_PREFIX", diff --git a/functions/src/definitions/common/sendTelegramMessage.ts b/functions/src/definitions/common/sendTelegramMessage.ts index ecbd9d69..adfc0c54 100644 --- a/functions/src/definitions/common/sendTelegramMessage.ts +++ b/functions/src/definitions/common/sendTelegramMessage.ts @@ -82,7 +82,7 @@ const updateTelegramReplyMarkup = async function ( "Content-Type": "application/json", }, }).catch((error) => { - functions.logger.log(error.response) + functions.logger.log(error.response?.data) throw "error with updating telegram reply markup" }) return response diff --git a/functions/src/definitions/common/statistics.ts b/functions/src/definitions/common/statistics.ts index 3bcf84cb..3612fed0 100644 --- a/functions/src/definitions/common/statistics.ts +++ b/functions/src/definitions/common/statistics.ts @@ -9,10 +9,12 @@ function checkAccuracy( parentMessageSnap: admin.firestore.DocumentSnapshot, voteRequestSnap: admin.firestore.DocumentSnapshot ) { - const db = admin.firestore() const isLegacy = voteRequestSnap.get("truthScore") === undefined const isParentMessageAssessed = parentMessageSnap.get("isAssessed") ?? false const parentMessageCategory = parentMessageSnap.get("primaryCategory") ?? null + //INCORRECT USAGE + const parentMessageTags = parentMessageSnap.get("tags") ?? {} + const voteRequestTags = voteRequestSnap.get("tags") ?? {} const parentMessageTruthScore = isLegacy ? parentMessageSnap.get("legacyTruthScore") ?? null : parentMessageSnap.get("truthScore") ?? null @@ -49,6 +51,15 @@ function checkAccuracy( return null } return Math.abs(parentMessageTruthScore - voteRequestTruthScore) <= 1 + } else if (voteRequestCategory === "irrelevant") { + //INCORRECT USAGE + const isParentMessageIncorrectUsage = parentMessageTags.incorrect ?? false + const isVoteRequestIncorrectUsage = voteRequestTags.incorrect ?? false + if (parentMessageCategory === "irrelevant") { + return isParentMessageIncorrectUsage === isVoteRequestIncorrectUsage + } else { + return false + } //END INCORRECT USAGE } else { return parentMessageCategory === voteRequestCategory } diff --git a/functions/src/definitions/common/utils.ts b/functions/src/definitions/common/utils.ts index c754fd28..6c463da6 100644 --- a/functions/src/definitions/common/utils.ts +++ b/functions/src/definitions/common/utils.ts @@ -1,4 +1,5 @@ import thresholds from "./parameters/thresholds.json" +import others from "./parameters/others.json" import * as admin from "firebase-admin" import { findPhoneNumbersInText } from "libphonenumber-js" import { createHash } from "crypto" @@ -19,7 +20,7 @@ function isNumeric(str: string) { return !isNaN(Number(str)) } -const getThresholds = async function () { +async function getThresholds() { const db = admin.firestore() const theresholdsRef = db.doc("systemParameters/thresholds") const theresholdsSnap = await theresholdsRef.get() @@ -31,6 +32,15 @@ const getThresholds = async function () { return returnThresholds } +async function getTags() { + const db = admin.firestore() + const tagsRef = db.doc("systemParameters/tags") + const tagsSnap = await tagsRef.get() + const returnTags = tagsSnap.get("tags") ?? others.tags + //return array of keys + return returnTags +} + function normalizeSpaces(str: string) { return str.replace(/\u00A0/g, " ") } @@ -146,4 +156,5 @@ export { checkUrlPresence, checkTemplate, isNumeric, + getTags, } diff --git a/functions/src/definitions/eventHandlers/onInstanceCreate.ts b/functions/src/definitions/eventHandlers/onInstanceCreate.ts index c60810b6..a683ad5c 100644 --- a/functions/src/definitions/eventHandlers/onInstanceCreate.ts +++ b/functions/src/definitions/eventHandlers/onInstanceCreate.ts @@ -247,6 +247,7 @@ async function sendTemplateMessageAndCreateVoteRequest( category: null, truthScore: null, reasoning: null, + tags: {}, createdTimestamp: Timestamp.fromDate(new Date()), acceptedTimestamp: null, votedTimestamp: null, diff --git a/functions/src/definitions/eventHandlers/onVoteRequestUpdate.ts b/functions/src/definitions/eventHandlers/onVoteRequestUpdate.ts index 79673697..588a9ca2 100644 --- a/functions/src/definitions/eventHandlers/onVoteRequestUpdate.ts +++ b/functions/src/definitions/eventHandlers/onVoteRequestUpdate.ts @@ -1,6 +1,6 @@ import * as admin from "firebase-admin" import * as functions from "firebase-functions" -import { getThresholds } from "../common/utils" +import { getThresholds, getTags } from "../common/utils" import { sendVotingMessage, sendL2OthersCategorisationMessage, @@ -13,6 +13,7 @@ import { onDocumentUpdated } from "firebase-functions/v2/firestore" import { tabulateVoteStats } from "../common/statistics" import { updateTelegramReplyMarkup } from "../common/sendTelegramMessage" import { logger } from "firebase-functions/v2" +import { MessageData } from "../../types" // Define some parameters const numVoteShards = defineInt("NUM_SHARDS_VOTE_COUNT") @@ -49,6 +50,9 @@ const onVoteRequestUpdateV2 = onDocumentUpdated( return } const messageSnap = await messageRef.get() + const beforeTags = preChangeData?.tags ?? {} + const afterTags = postChangeData?.tags ?? {} + const { addedTags, removedTags } = getChangedTags(beforeTags, afterTags) if ( preChangeData.triggerL2Vote !== true && postChangeData.triggerL2Vote === true @@ -62,13 +66,18 @@ const onVoteRequestUpdateV2 = onDocumentUpdated( } else if ( preChangeData.truthScore != postChangeData.truthScore || preChangeData.category != postChangeData.category || - preChangeData.vote != postChangeData.vote + preChangeData.vote != postChangeData.vote || + addedTags.length > 0 || + removedTags.length > 0 ) { - const isLegacy = - postChangeData.truthScore === undefined && - postChangeData.vote !== undefined await Promise.all([ - updateCounts(messageRef, preChangeData, postChangeData), + updateCounts( + messageRef, + preChangeData, + postChangeData, + addedTags, + removedTags + ), updateCheckerVoteCount(preChangeData, postChangeData), ]) @@ -90,6 +99,7 @@ const onVoteRequestUpdateV2 = onDocumentUpdated( truthScore, harmfulCount, harmlessCount, + tagCounts, } = await getVoteCounts(messageRef) const isBigSus = susCount > thresholds.isBigSus * validResponsesCount @@ -180,7 +190,10 @@ const onVoteRequestUpdateV2 = onDocumentUpdated( primaryCategory = "error" functions.logger.error("Error in primary category determination") } - await messageRef.update({ + + const updateObj: Partial & { + [key: string]: FieldValue | boolean | number | string | null + } = { truthScore: truthScore, isScam: isScam, isIllicit: isIllicit, @@ -194,7 +207,22 @@ const onVoteRequestUpdateV2 = onDocumentUpdated( isHarmful: isHarmful, isHarmless: isHarmless, primaryCategory: primaryCategory, - }) + } + + // Loop through tagCounts and check if they exceed the threshold + + for (const tag in tagCounts) { + if (tagCounts.hasOwnProperty(tag)) { + const count = tagCounts[tag] + if (count > 0.5 * validResponsesCount) { + updateObj[`tags.${tag}`] = true + } else { + updateObj[`tags.${tag}`] = FieldValue.delete() + } + } + } + + await messageRef.update(updateObj) if (messageSnap.get("isAssessed") === true) { const { isCorrect, score, duration } = tabulateVoteStats( messageSnap, @@ -232,12 +260,16 @@ const onVoteRequestUpdateV2 = onDocumentUpdated( ], ], } - await updateTelegramReplyMarkup( - "factChecker", - postChangeData.platformId, - postChangeData.sentMessageId, - replyMarkup - ) + try { + await updateTelegramReplyMarkup( + "factChecker", + postChangeData.platformId, + postChangeData.sentMessageId, + replyMarkup + ) + } catch (e) { + functions.logger.warn("Error updating telegram reply markup", e) + } } if (postChangeData.votedTimestamp !== preChangeData.votedTimestamp) { const factCheckerDocRef = await switchLegacyCheckerRef( @@ -266,19 +298,22 @@ async function updateCounts( messageRef: admin.firestore.DocumentReference, before: admin.firestore.DocumentData, after: admin.firestore.DocumentData, - isLegacy: boolean = false + addedTags: string[], + removedTags: string[] ) { const previousCategory = before.category const currentCategory = after.category - //START REMOVE IN APRIL// let previousScore = before.truthScore let currentScore = after.truthScore - if (isLegacy) { - previousScore = before.vote - currentScore = after.vote + for (const tag of addedTags) { + await incrementCounter(messageRef, tag, numVoteShards.value()) + } + + for (const tag of removedTags) { + await incrementCounter(messageRef, tag, numVoteShards.value(), -1) } - //END REMOVE IN APRIL// + if (previousCategory === null) { if (currentCategory !== null) { await incrementCounter(messageRef, "responses", numVoteShards.value()) @@ -454,4 +489,28 @@ async function switchLegacyCheckerRef( } } +function getChangedTags( + beforeTags: { [key: string]: boolean }, + afterTags: { [key: string]: boolean } +) { + const addedTags: string[] = [] + const removedTags: string[] = [] + + // Check for added or modified tags + for (const tag in afterTags) { + if (!beforeTags.hasOwnProperty(tag) || beforeTags[tag] !== afterTags[tag]) { + addedTags.push(tag) + } + } + + // Check for removed tags + for (const tag in beforeTags) { + if (!afterTags.hasOwnProperty(tag)) { + removedTags.push(tag) + } + } + + return { addedTags, removedTags } +} + export { onVoteRequestUpdateV2 } diff --git a/functions/src/definitions/eventHandlers/userHandlers.ts b/functions/src/definitions/eventHandlers/userHandlers.ts index 3b8ecbe7..7047da7b 100644 --- a/functions/src/definitions/eventHandlers/userHandlers.ts +++ b/functions/src/definitions/eventHandlers/userHandlers.ts @@ -331,6 +331,7 @@ async function newTextInstanceHandler({ isSatire: null, isHarmful: null, isHarmless: null, + tags: {}, primaryCategory: isMachineAssessed ? machineCategory.split("_")[0] //in case of irrelevant_length, we want to store irrelevant : null, @@ -594,6 +595,7 @@ async function newImageInstanceHandler({ isSatire: null, isHarmful: null, isHarmless: null, + tags: {}, primaryCategory: isMachineAssessed ? machineCategory.split("_")[0] //in case of irrelevant_length, we want to store irrelevant : null, diff --git a/functions/src/types.ts b/functions/src/types.ts index b027d6e3..9a838587 100644 --- a/functions/src/types.ts +++ b/functions/src/types.ts @@ -38,6 +38,10 @@ export type WhatsappMessageObject = { image?: { caption: string; id: string; mime_type: string } } +type TagsMap = { + [tag: string]: boolean +} + export type MessageData = { machineCategory: string isMachineCategorised: boolean @@ -64,6 +68,7 @@ export type MessageData = { isSatire: boolean | null isHarmful: boolean | null // whether the sum of scam + illicit + untrue votes > harmful threshold isHarmless: boolean | null // whether the sum of legitimate + accurate + spam votes > harmless threshold + tags: TagsMap primaryCategory: string | null customReply: string | null instanceCount: number @@ -252,6 +257,7 @@ export type VoteRequest = { votedTimestamp: Timestamp | null isCorrect: boolean | null score: number | null + tags: TagsMap duration: number | null //duration in minutes } From 00d235b0e9d20826040a572ebac9c96bc8413bcd Mon Sep 17 00:00:00 2001 From: Bing Wen Tan Date: Sun, 1 Sep 2024 16:35:36 +0800 Subject: [PATCH 2/4] fixed tests --- functions/.secret.local.test | 9 ++++-- .../common/parameters/userResponses.json | 4 +-- integration-tests/env.json | 30 ++++++++++++------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/functions/.secret.local.test b/functions/.secret.local.test index d2f77eb3..2ab563f6 100644 --- a/functions/.secret.local.test +++ b/functions/.secret.local.test @@ -2,11 +2,14 @@ WHATSAPP_USER_BOT_PHONE_NUMBER_ID=WHATSAPP_TEST_USER_BOT_PHONE_NUMBER_ID WHATSAPP_CHECKERS_BOT_PHONE_NUMBER_ID=WHATSAPP_TEST_CHECKER_BOT_PHONE_NUMBER_ID WHATSAPP_TOKEN=WHATSAPP_TOKEN TELEGRAM_CHECKER_BOT_TOKEN=TELEGRAM_CHECKER_BOT_TOKEN +TELEGRAM_ADMIN_BOT_TOKEN=TELEGRAM_ADMIN_BOT_TOKEN TELEGRAM_REPORT_BOT_TOKEN=TELEGRAM_REPORT_BOT_TOKEN VERIFY_TOKEN=VERIFY_TOKEN -OPENAI_API_KEY=OPEN_API_KEY TYPESENSE_TOKEN=TYPESENSE_TOKEN ML_SERVER_TOKEN=ML_SERVER_TOKEN +OPENAI_API_KEY=OPENAI_API_KEY TELEGRAM_BOT_TOKEN=TELEGRAM_BOT_TOKEN -WHATSAPP_USERS_WABA_ID=WHATSAPP_TEST_USER_WABA_ID -WHATSAPP_CHECKERS_WABA_ID=WHATSAPP_TEST_CHECKER_WABA_ID \ No newline at end of file +WHATSAPP_USERS_WABA_ID=WHATSAPP_USERS_WABA_ID +WHATSAPP_CHECKERS_WABA_ID=WHATSAPP_CHECKERS_WABA_ID +TELEGRAM_WEBHOOK_TOKEN=TELEGRAM_WEBHOOK_TOKEN +TYPEFORM_SECRET_TOKEN=TYPEFORM_SECRET_TOKEN \ No newline at end of file diff --git a/functions/src/definitions/common/parameters/userResponses.json b/functions/src/definitions/common/parameters/userResponses.json index 6333c9a7..c35c6f82 100644 --- a/functions/src/definitions/common/parameters/userResponses.json +++ b/functions/src/definitions/common/parameters/userResponses.json @@ -392,7 +392,7 @@ "cn": "是准确的✅" }, "PLACEHOLDER_SPAM": { - "en": "marketing/viral content", + "en": "marketing/viral content📣", "cn": "是营销/病毒式信息📣" }, "PLACEHOLDER_LEGITIMATE": { @@ -411,4 +411,4 @@ "en": "too difficult to assess", "cn": "很难做评估" } -} \ No newline at end of file +} diff --git a/integration-tests/env.json b/integration-tests/env.json index a26a6862..428fe729 100644 --- a/integration-tests/env.json +++ b/integration-tests/env.json @@ -230,12 +230,12 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.SPAM.en", - "value": "{{thanks}}{{methodology}}*spam*!🚧{{image_caveat}}\n\nIt's likely harmless, but you should always make sure 🧐\n\n{{reporting_nudge}}Thank you for keeping Singapore safe!", + "value": "{{thanks}}{{methodology}}*marketing/viral content*!📣{{image_caveat}}\n\nIt's likely harmless, but you should always make sure 🧐\n\n{{reporting_nudge}}Thank you for keeping Singapore safe!", "enabled": true }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.SPAM.cn", - "value": "{{thanks}}{{methodology}}是垃圾信息!🚧{{image_caveat}}\n\n虽然它看似无害,但请仍然保持警惕 🧐\n\n{{reporting_nudge}}感谢您对新加坡网络安全的支持和贡献!", + "value": "{{thanks}}{{methodology}}是营销/病毒式信息!📣{{image_caveat}}\n\n虽然它看似无害,但请仍然保持警惕 🧐\n\n{{reporting_nudge}}感谢您对新加坡网络安全的支持和贡献!", "enabled": true }, { @@ -380,7 +380,7 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.IRRELEVANT_MENU_PREFIX.en", - "value": "Thanks for waiting!🙏🏻 Our CheckMates didn't find anything to assess in this message.😕", + "value": "Thanks for waiting!🙏🏻 Our volunteer checkers were unable to assess this message.😕\n\nSorry about that!", "enabled": true }, { @@ -390,7 +390,7 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.IRRELEVANT_AUTO_MENU_PREFIX.en", - "value": "Hmm...There doesn't seem to be anything to assess in this message.😕", + "value": "Hmm...we couldn't assess this message.😕\n\nSorry about that!", "enabled": true }, { @@ -540,7 +540,7 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.IMAGE_CAVEAT.en", - "value": "This assessment refers to the claims made within the captions, if any.", + "value": "This assessment refers to the claims made within the accompanying message.", "enabled": true }, { @@ -860,12 +860,12 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.PLACEHOLDER_SPAM.en", - "value": "spam🚧", + "value": "marketing/viral content", "enabled": true }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.PLACEHOLDER_SPAM.cn", - "value": "是垃圾信息🚧", + "value": "是营销/病毒式信息📣", "enabled": true }, { @@ -900,7 +900,7 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.MENU.en", - "value": "{{prefix}}\n\nSelect \"Menu\" below to see what CheckMate can do! 👈\n\nDo note that CheckMate *is designed to check dubious messages you send in. It cannot converse freely with you*.\n\nAnytime you need a refresher on what CheckMate can do, type \"menu\" to get here again! 😊", + "value": "{{prefix}}\n\nSelect \"Menu\" below to see what CheckMate can do! 👈\n\nDo note that CheckMate *checks dubious messages and tells you whether you can trust them. It cannot converse with you or answer questions*.\n\nAnytime you need a refresher on what CheckMate can do, type \"menu\" to get here again! 😊", "enabled": true }, { @@ -1160,7 +1160,7 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.REFERRAL_PREPOPULATED_PREFIX_1.cn", - "value": "S/N: {{code}}\n\nSimply send this message to get started! (只需按发送按钮!) 👉", + "value": "S/N: {{code}}\n\nSimply send this message to get started! (按发送按钮!) 👉", "enabled": true }, { @@ -1182,9 +1182,19 @@ "key": "__CONSTANTS__.USER_BOT_RESPONSES.HARMFUL.cn", "value": "{{thanks}}{{methodology}}不可信任!🔴{{image_caveat}}\n\n建议您停止交流⛔️⛔️\n\n{{reporting_nudge}}感谢您对新加坡网络安全的支持和贡献!", "enabled": true + }, + { + "key": "__CONSTANTS__.USER_BOT_RESPONSES.INCORRECT.en", + "value": "At this point, CheckMate is unable to answer questions directly, or converse freely with you. 😕\n\nTo use CheckMate, simply send us messages that you require checking. We will let you know whether the message can be trusted. There is no need to specially ask about it.\n\nWe apologise for the misunderstanding.", + "enabled": true + }, + { + "key": "__CONSTANTS__.USER_BOT_RESPONSES.INCORRECT.cn", + "value": "此时,查友无法直接回答问题或与您自由交谈。😕\n\n使用查友,只需发送您希望检查的消息,无需特别询问。我们会告诉您该消息是否可信。\n\n对因此造成的误解,我们深表歉意。", + "enabled": true } ], "_postman_variable_scope": "environment", "_postman_exported_at": "2023-04-30T14:17:56.196Z", "_postman_exported_using": "Postman/10.13.0" -} +} \ No newline at end of file From 7ca6b57f215ef57d1ad591241fce252abf3b800e Mon Sep 17 00:00:00 2001 From: Bing Wen Tan Date: Sun, 1 Sep 2024 18:04:35 +0800 Subject: [PATCH 3/4] fixed tests --- functions/.secret.local.test | 4 +- .../checkmate.postman_collection.json | 14 +- integration-tests/env.json | 2 +- integration-tests/package-lock.json | 462 +++++++++++------- integration-tests/package.json | 2 +- 5 files changed, 285 insertions(+), 199 deletions(-) diff --git a/functions/.secret.local.test b/functions/.secret.local.test index 2ab563f6..ccf66471 100644 --- a/functions/.secret.local.test +++ b/functions/.secret.local.test @@ -9,7 +9,7 @@ TYPESENSE_TOKEN=TYPESENSE_TOKEN ML_SERVER_TOKEN=ML_SERVER_TOKEN OPENAI_API_KEY=OPENAI_API_KEY TELEGRAM_BOT_TOKEN=TELEGRAM_BOT_TOKEN -WHATSAPP_USERS_WABA_ID=WHATSAPP_USERS_WABA_ID -WHATSAPP_CHECKERS_WABA_ID=WHATSAPP_CHECKERS_WABA_ID +WHATSAPP_USERS_WABA_ID=WHATSAPP_TEST_USER_WABA_ID +WHATSAPP_CHECKERS_WABA_ID=WHATSAPP_TEST_CHECKER_WABA_ID TELEGRAM_WEBHOOK_TOKEN=TELEGRAM_WEBHOOK_TOKEN TYPEFORM_SECRET_TOKEN=TYPEFORM_SECRET_TOKEN \ No newline at end of file diff --git a/integration-tests/checkmate.postman_collection.json b/integration-tests/checkmate.postman_collection.json index 397b8075..29a2c4ff 100644 --- a/integration-tests/checkmate.postman_collection.json +++ b/integration-tests/checkmate.postman_collection.json @@ -3075,9 +3075,10 @@ " const USER_1_NUMBER = pm.variables.get(\"USER_1_NUMBER\")\r", " const INTERIM_TEMPLATE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.INTERIM_TEMPLATE.en\");\r", " const BUTTON_ANOTHER_UPDATE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.BUTTON_ANOTHER_UPDATE.en\");\r", + " const PLACEHOLDER_SPAM = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.PLACEHOLDER_SPAM.en\")\r", " const wamid = pm.variables.get(\"whatsapp_id_11\")\r", " const instanceId = pm.variables.get(\"spamInstanceId\")\r", - " const interimResponse = INTERIM_TEMPLATE.replace(\"{{%voted}}\", \"33.3\").replace(\"{{prelim_assessment}}\",\"spam🚧\").replace(\"{{info_placeholder}}\",\"\")\r", + " const interimResponse = INTERIM_TEMPLATE.replace(\"{{%voted}}\", \"33.3\").replace(\"{{prelim_assessment}}\",PLACEHOLDER_SPAM).replace(\"{{info_placeholder}}\",\"\")\r", " const expected = {\r", " \"hostname\": \"resultserver\",\r", " \"path\": \"/v15.0/WHATSAPP_TEST_USER_BOT_PHONE_NUMBER_ID/messages\",\r", @@ -3222,9 +3223,10 @@ " const USER_1_NUMBER = pm.variables.get(\"USER_1_NUMBER\")\r", " const INTERIM_TEMPLATE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.INTERIM_TEMPLATE.en\");\r", " const BUTTON_ANOTHER_UPDATE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.BUTTON_ANOTHER_UPDATE.en\")\r", + " const PLACEHOLDER_SPAM = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.PLACEHOLDER_SPAM.en\")\r", " const instanceId = pm.variables.get(\"spamInstanceId\")\r", " const wamid = pm.variables.get(\"whatsapp_id_11\")\r", - " const interimResponse = INTERIM_TEMPLATE.replace(\"{{%voted}}\", \"33.3\").replace(\"{{prelim_assessment}}\",\"spam🚧\").replace(\"{{info_placeholder}}\",\"\").replace(\"{{get_feedback}}\",\"\")\r", + " const interimResponse = INTERIM_TEMPLATE.replace(\"{{%voted}}\", \"33.3\").replace(\"{{prelim_assessment}}\",PLACEHOLDER_SPAM).replace(\"{{info_placeholder}}\",\"\").replace(\"{{get_feedback}}\",\"\")\r", " const expected = {\r", " \"hostname\": \"resultserver\",\r", " \"path\": \"/v15.0/WHATSAPP_TEST_USER_BOT_PHONE_NUMBER_ID/messages\",\r", @@ -4958,13 +4960,14 @@ "pm.test(\"STATS_TEMPLATE sent to user 1\", function () {\r", " const USER_1_NUMBER = pm.variables.get(\"USER_1_NUMBER\")\r", " const wamid = pm.variables.get(\"whatsapp_id_11\")\r", + " \r", " //we not using the template for this, its hardcoded.\r", " const expected = {\r", " \"hostname\": \"resultserver\",\r", " \"path\": \"/v15.0/WHATSAPP_TEST_USER_BOT_PHONE_NUMBER_ID/messages\",\r", " \"body\": {\r", " \"text\": {\r", - " \"body\": \"66.7% of our CheckMates felt this was *spam🚧*. 33.3% felt this was *satirical in nature🙃*.\",\r", + " \"body\": \"66.7% of our CheckMates felt this was *marketing/viral content📣*. 33.3% felt this was *satirical in nature🙃*.\",\r", " \"preview_url\": false\r", " },\r", " \"to\": USER_1_NUMBER,\r", @@ -6108,9 +6111,10 @@ " const INTERIM_TEMPLATE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.INTERIM_TEMPLATE.en\");\r", " const INFO_PLACEHOLDER = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.INFO_PLACEHOLDER.en\")\r", " const BUTTON_ANOTHER_UPDATE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.BUTTON_ANOTHER_UPDATE.en\")\r", + " const PLACEHOLDER_UNTRUE = pm.variables.get(\"__CONSTANTS__.USER_BOT_RESPONSES.PLACEHOLDER_UNTRUE.en\")\r", " const instanceId = pm.variables.get(\"infoInstanceId\")\r", " const wamid = pm.variables.get(\"whatsapp_id_19\")\r", - " const interimResponse = INTERIM_TEMPLATE.replace(\"{{%voted}}\", \"33.3\").replace(\"{{prelim_assessment}}\",\"untrue❌\").replace(\"{{info_placeholder}}\",INFO_PLACEHOLDER.replace(\"{{score}}\",\"1.0\"))\r", + " const interimResponse = INTERIM_TEMPLATE.replace(\"{{%voted}}\", \"33.3\").replace(\"{{prelim_assessment}}\",PLACEHOLDER_UNTRUE).replace(\"{{info_placeholder}}\",INFO_PLACEHOLDER.replace(\"{{score}}\",\"1.0\"))\r", " const expected = {\r", " \"hostname\": \"resultserver\",\r", " \"path\": \"/v15.0/WHATSAPP_TEST_USER_BOT_PHONE_NUMBER_ID/messages\",\r", @@ -10578,7 +10582,7 @@ " \"path\": \"/v15.0/WHATSAPP_TEST_USER_BOT_PHONE_NUMBER_ID/messages\",\r", " \"body\": {\r", " \"text\": {\r", - " \"body\": \"33.3% of our CheckMates felt this was *spam🚧*. 33.3% felt this was *misleading⚠️*, with an average score of 3.0 on a scale of 1-5 (5 = completely true).\",\r", + " \"body\": \"33.3% of our CheckMates felt this was *marketing/viral content📣*. 33.3% felt this was *misleading⚠️*, with an average score of 3.0 on a scale of 1-5 (5 = completely true).\",\r", " \"preview_url\": false\r", " },\r", " \"to\": USER_1_NUMBER,\r", diff --git a/integration-tests/env.json b/integration-tests/env.json index 428fe729..b8fdbe57 100644 --- a/integration-tests/env.json +++ b/integration-tests/env.json @@ -860,7 +860,7 @@ }, { "key": "__CONSTANTS__.USER_BOT_RESPONSES.PLACEHOLDER_SPAM.en", - "value": "marketing/viral content", + "value": "marketing/viral content📣", "enabled": true }, { diff --git a/integration-tests/package-lock.json b/integration-tests/package-lock.json index d946befe..7a8841b0 100644 --- a/integration-tests/package-lock.json +++ b/integration-tests/package-lock.json @@ -10,13 +10,22 @@ "license": "ISC", "dependencies": { "lodash": "^4.17.21", - "newman": "^5.3.2" + "newman": "^6.2.1" }, "devDependencies": { "@types/lodash": "^4.14.197", "ts-node": "^10.9.1" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -29,6 +38,11 @@ "node": ">=12" } }, + "node_modules/@faker-js/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==" + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", @@ -67,10 +81,24 @@ "node": ">= 6" } }, + "node_modules/@postman/tough-cookie": { + "version": "4.1.3-postman.1", + "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", + "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@postman/tunnel-agent": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", - "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.4.tgz", + "integrity": "sha512-CJJlq8V7rNKhAw4sBfjixKpJW00SHqebqNUQKxMoepgeWZIbdPcD+rguRcivGhS4N12PymDcKgUgSD4rVC+RjQ==", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -182,9 +210,9 @@ } }, "node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -200,9 +228,9 @@ } }, "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -250,9 +278,9 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, "node_modules/chardet": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz", - "integrity": "sha512-NpwMDdSIprbYx1CLnfbxEIarI0Z+s9MssEgggMNheGM+WD68yOhV7IEA/3r6tr0yTRgQD0HuZJDw32s99i6L+A==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.0.0.tgz", + "integrity": "sha512-xVgPpulCooDjY6zH4m9YW3jbkaBe3FKIAvF5sj5t7aBNsVl2ljIE+xwJ4iNgiDZHFQvNIpjdKdVOQvvk5ZfxbQ==" }, "node_modules/charset": { "version": "1.0.1", @@ -263,20 +291,20 @@ } }, "node_modules/cli-progress": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", - "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", "dependencies": { - "string-width": "^4.2.0" + "string-width": "^4.2.3" }, "engines": { "node": ">=4" } }, "node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", "dependencies": { "string-width": "^4.2.0" }, @@ -284,7 +312,7 @@ "node": "10.* || >= 12.*" }, "optionalDependencies": { - "colors": "1.4.0" + "@colors/colors": "1.5.0" } }, "node_modules/colors": { @@ -307,11 +335,11 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "engines": { - "node": ">= 10" + "node": ">=16" } }, "node_modules/core-util-is": { @@ -349,6 +377,15 @@ "node": ">=0.4.0" } }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -372,11 +409,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -390,11 +422,6 @@ "node >=0.6.0" ] }, - "node_modules/faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -414,17 +441,17 @@ } }, "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.4.tgz", + "integrity": "sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==", "engines": { - "node": ">= 0.4.0" + "node": ">= 10.4.0" } }, "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==" + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==" }, "node_modules/forever-agent": { "version": "0.6.1", @@ -443,12 +470,12 @@ } }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -502,21 +529,33 @@ } }, "node_modules/httpntlm": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.7.tgz", - "integrity": "sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==", + "version": "1.8.13", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz", + "integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==", + "funding": [ + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=2CKNJLZJBW8ZC" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/samdecrock" + } + ], "dependencies": { + "des.js": "^1.0.1", "httpreq": ">=0.4.22", + "js-md4": "^0.3.2", "underscore": "~1.12.1" }, "engines": { - "node": ">=0.8.0" + "node": ">=10.4.0" } }, "node_modules/httpreq": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.5.2.tgz", - "integrity": "sha512-2Jm+x9WkExDOeFRrdBCBSpLPT5SokTcRHkunV3pjKmX/cx6av8zQ0WtHUMDrYb6O4hBFzNU6sxJEypvRUVYKnw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", + "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", "engines": { "node": ">= 6.15.1" } @@ -537,14 +576,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "engines": { - "node": ">=4" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -563,10 +594,23 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==" + }, "node_modules/js-sha512": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", - "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.9.0.tgz", + "integrity": "sha512-mirki9WS/SUahm+1TbAPkqvbCiCfOAAsyXeHxK1UkullnJVVqoJG2pL9ObvT05CN+tM7fxhfYm0NbXn+1hWoZg==" }, "node_modules/jsbn": { "version": "0.1.1", @@ -633,9 +677,9 @@ "dev": true }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } @@ -649,16 +693,21 @@ } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -668,14 +717,17 @@ } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "bin": { - "mkdirp": "bin/cmd.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/neo-async": { @@ -684,37 +736,45 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/newman": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/newman/-/newman-5.3.2.tgz", - "integrity": "sha512-cWy8pV0iwvMOZLTw3hkAHcwo2ZA0GKkXm8oUMn1Ltii3ZI2nKpnrg9QGdIT0hGHChRkX6prY5e3Aar7uykMGNg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/newman/-/newman-6.2.1.tgz", + "integrity": "sha512-Zq8Sr5GFF+OXs5yIbyglLMKMh1WNMjYVV0yZaSBZ+DIgQOIWcxT8QTfbrl/YUGrLyT4rjpu+yZ/Z+kozw79GEA==", "dependencies": { - "async": "3.2.3", - "chardet": "1.4.0", - "cli-progress": "3.10.0", - "cli-table3": "0.6.1", + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.5", + "chardet": "2.0.0", + "cli-progress": "3.12.0", + "cli-table3": "0.6.5", "colors": "1.4.0", - "commander": "7.2.0", + "commander": "11.1.0", "csv-parse": "4.16.3", - "eventemitter3": "4.0.7", - "filesize": "8.0.7", + "filesize": "10.1.4", + "liquid-json": "0.3.1", "lodash": "4.17.21", - "mkdirp": "1.0.4", - "postman-collection": "4.1.1", - "postman-collection-transformer": "4.1.6", - "postman-request": "2.88.1-postman.31", - "postman-runtime": "7.29.0", + "mkdirp": "3.0.1", + "postman-collection": "4.4.0", + "postman-collection-transformer": "4.1.8", + "postman-request": "2.88.1-postman.34", + "postman-runtime": "7.39.1", "pretty-ms": "7.0.1", - "semver": "7.3.5", + "semver": "7.6.3", "serialised-error": "1.1.3", - "tough-cookie": "3.0.1", - "word-wrap": "1.2.3", + "word-wrap": "1.2.5", "xmlbuilder": "15.1.1" }, "bin": { "newman": "bin/newman.js" }, "engines": { - "node": ">=10" + "node": ">=16" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" } }, "node_modules/node-oauth1": { @@ -752,20 +812,20 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/postman-collection": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.1.1.tgz", - "integrity": "sha512-ODpJtlf8r99DMcTU7gFmi/yvQYckFzcuE6zL/fWnyrFT34ugdCBFlX+DN7M+AnP6lmR822fv5s60H4DnL4+fAg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.4.0.tgz", + "integrity": "sha512-2BGDFcUwlK08CqZFUlIC8kwRJueVzPjZnnokWPtJCd9f2J06HBQpGL7t2P1Ud1NEsK9NHq9wdipUhWLOPj5s/Q==", "dependencies": { - "faker": "5.5.3", + "@faker-js/faker": "5.5.3", "file-type": "3.9.0", "http-reasons": "0.1.0", "iconv-lite": "0.6.3", "liquid-json": "0.3.1", "lodash": "4.17.21", "mime-format": "2.0.1", - "mime-types": "2.1.34", + "mime-types": "2.1.35", "postman-url-encoder": "3.0.5", - "semver": "7.3.5", + "semver": "7.5.4", "uuid": "8.3.2" }, "engines": { @@ -773,14 +833,14 @@ } }, "node_modules/postman-collection-transformer": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.6.tgz", - "integrity": "sha512-xvdQb6sZoWcG9xZXUPSuxocjcd6WCZlINlGGiuHdSfxhgiwQhj9qhF0JRFbagZ8xB0+pYUairD5MiCENc6DEVA==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.8.tgz", + "integrity": "sha512-smJ6X7Z7kbg6hp7JZPFixrSN3J3WkQed7DrWCC5tF7IxOMpFLqhtTtGssY8nD1inP8+mJf+N72Pf2ttUAHgBKw==", "dependencies": { "commander": "8.3.0", "inherits": "2.0.4", "lodash": "4.17.21", - "semver": "7.3.5", + "semver": "7.5.4", "strip-json-comments": "3.1.1" }, "bin": { @@ -798,16 +858,45 @@ "node": ">= 12" } }, + "node_modules/postman-collection-transformer/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/postman-request": { - "version": "2.88.1-postman.31", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.31.tgz", - "integrity": "sha512-OJbYqP7ItxQ84yHyuNpDywCZB0HYbpHJisMQ9lb1cSL3N5H3Td6a2+3l/a74UMd3u82BiGC5yQyYmdOIETP/nQ==", + "version": "2.88.1-postman.34", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.34.tgz", + "integrity": "sha512-GkolJ4cIzgamcwHRDkeZc/taFWO1u2HuGNML47K9ZAsFH2LdEkS5Yy8QanpzhjydzV3WWthl9v60J8E7SjKodQ==", "dependencies": { "@postman/form-data": "~3.1.1", + "@postman/tough-cookie": "~4.1.3-postman.1", "@postman/tunnel-agent": "^0.6.3", "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "brotli": "~1.3.2", + "aws4": "^1.12.0", + "brotli": "^1.3.3", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", @@ -817,79 +906,61 @@ "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", + "mime-types": "^2.1.35", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.5.3", "safe-buffer": "^5.1.2", "stream-length": "^1.0.2", - "tough-cookie": "~2.5.0", - "uuid": "^3.3.2" + "uuid": "^8.3.2" }, "engines": { "node": ">= 6" } }, - "node_modules/postman-request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/postman-request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/postman-runtime": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.29.0.tgz", - "integrity": "sha512-eXxHREE/fUpohkGPRgBY1YccSGx9cyW3mtGiPyIE4zD5fYzasgBHqW6kbEND3Xrd3yf/uht/YI1H8O7J1+A1+w==", + "version": "7.39.1", + "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.39.1.tgz", + "integrity": "sha512-IRNrBE0l1K3ZqQhQVYgF6MPuqOB9HqYncal+a7RpSS+sysKLhJMkC9SfUn1HVuOpokdPkK92ykvPzj8kCOLYAg==", "dependencies": { - "async": "3.2.3", - "aws4": "1.11.0", - "handlebars": "4.7.7", - "httpntlm": "1.7.7", - "js-sha512": "0.8.0", + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.5", + "aws4": "1.12.0", + "handlebars": "4.7.8", + "httpntlm": "1.8.13", + "jose": "4.14.4", + "js-sha512": "0.9.0", "lodash": "4.17.21", - "mime-types": "2.1.34", + "mime-types": "2.1.35", + "node-forge": "1.3.1", "node-oauth1": "1.3.0", "performance-now": "2.1.0", - "postman-collection": "4.1.1", - "postman-request": "2.88.1-postman.31", - "postman-sandbox": "4.0.6", + "postman-collection": "4.4.0", + "postman-request": "2.88.1-postman.34", + "postman-sandbox": "4.7.1", "postman-url-encoder": "3.0.5", "serialised-error": "1.1.3", - "tough-cookie": "3.0.1", + "strip-json-comments": "3.1.1", "uuid": "8.3.2" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/postman-runtime/node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, "node_modules/postman-sandbox": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.0.6.tgz", - "integrity": "sha512-PPRanSNEE4zy3kO7CeSBHmAfJnGdD9ecHY/Mjh26CQuZZarGkNO8c0U/n+xX3+5M1BRNc82UYq6YCtdsSDqcng==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.7.1.tgz", + "integrity": "sha512-H2wYSLK0mB588IaxoLrLoPbpmxsIcwFtgaK2c8gAsAQ+TgYFePwb4qdeVcYDMqmwrLd77/ViXkjasP/sBMz1sQ==", "dependencies": { "lodash": "4.17.21", + "postman-collection": "4.4.0", "teleport-javascript": "1.0.0", - "uvm": "2.0.2" + "uvm": "2.1.1" }, "engines": { "node": ">=10" @@ -926,9 +997,9 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { "node": ">=6" } @@ -941,6 +1012,16 @@ "node": ">=0.6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -966,12 +1047,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -1007,9 +1085,9 @@ } }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -1086,19 +1164,6 @@ "resolved": "https://registry.npmjs.org/teleport-javascript/-/teleport-javascript-1.0.0.tgz", "integrity": "sha512-j1llvWVFyEn/6XIFDfX5LAU43DXe0GCt3NfXDwJ8XpRRMkS+i50SAkonAONBy+vxwPFBd50MFU8a2uj8R/ccLg==" }, - "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -1162,9 +1227,9 @@ } }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -1178,6 +1243,14 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1186,6 +1259,15 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -1195,11 +1277,11 @@ } }, "node_modules/uvm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.0.2.tgz", - "integrity": "sha512-Ra+aPiS5GXAbwXmyNExqdS42sTqmmx4XWEDF8uJlsTfOkKf9Rd9xNgav1Yckv4HfVEZg4iOFODWHFYuJ+9Fzfg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.1.1.tgz", + "integrity": "sha512-BZ5w8adTpNNr+zczOBRpaX/hH8UPKAf7fmCnidrcsqt3bn8KT9bDIfuS7hgRU9RXgiN01su2pwysBONY6w8W5w==", "dependencies": { - "flatted": "3.1.1" + "flatted": "3.2.6" }, "engines": { "node": ">=10" @@ -1225,9 +1307,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "engines": { "node": ">=0.10.0" } diff --git a/integration-tests/package.json b/integration-tests/package.json index 24d39a08..8f451e27 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -11,7 +11,7 @@ "license": "ISC", "dependencies": { "lodash": "^4.17.21", - "newman": "^5.3.2" + "newman": "^6.2.1" }, "devDependencies": { "@types/lodash": "^4.14.197", From 632f8fe1e37c794953035e4e35207ffdcef03e26 Mon Sep 17 00:00:00 2001 From: Bing Wen Tan Date: Sun, 1 Sep 2024 19:43:43 +0800 Subject: [PATCH 4/4] minor changes --- checkers-app/src/components/vote/VoteCategories.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/checkers-app/src/components/vote/VoteCategories.tsx b/checkers-app/src/components/vote/VoteCategories.tsx index 3a34fed0..4e252c4f 100644 --- a/checkers-app/src/components/vote/VoteCategories.tsx +++ b/checkers-app/src/components/vote/VoteCategories.tsx @@ -15,7 +15,7 @@ import { useUser } from "../../providers/UserContext"; import { TooltipWithHelperIcon } from "../common/ToolTip"; import InfoOptions from "./InfoOptions"; -import NVCOptions from "./nvcOptions"; +import NVCOptions from "./NvcOptions"; interface PropType { messageId: string | null; @@ -129,7 +129,6 @@ export default function VoteCategories(Prop: PropType) { }; const handleVoteCategoryChange = (category: string) => { - console.log("current tags:" + currentTags); switch (category) { case "incorrect": setVoteCategory("irrelevant");