From 95219783359e4cef522b7069007a549bee932848 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Mon, 14 Oct 2024 20:20:15 +0300 Subject: [PATCH] add to list delete get --- public/content-script.js | 106 +--------- src/App.tsx | 10 +- src/qortalRequests.ts | 28 ++- src/qortalRequests/get.ts | 412 +++++++++++++++++++++++--------------- 4 files changed, 292 insertions(+), 264 deletions(-) diff --git a/public/content-script.js b/public/content-script.js index 183b230..82d97ca 100644 --- a/public/content-script.js +++ b/public/content-script.js @@ -453,22 +453,7 @@ chrome.runtime?.onMessage.addListener(function (message, sender, sendResponse) { } }); -const lastActionTimestamps = {}; - -// Function to debounce actions based on message.action -function debounceAction(action, wait = 500) { - const currentTime = Date.now(); - - // Check if this action has been recently triggered - if (lastActionTimestamps[action] && currentTime - lastActionTimestamps[action] < wait) { - // Ignore this action if it occurred within the debounce time window - return false; - } - - // Update the last timestamp for this action - lastActionTimestamps[action] = currentTime; - return true; -} +const UIQortalRequests = ['GET_USER_ACCOUNT', 'ENCRYPT_DATA', 'DECRYPT_DATA', 'SEND_COIN', 'GET_LIST_ITEMS', 'ADD_LIST_ITEMS', 'DELETE_LIST_ITEM'] if (!window.hasAddedQortalListener) { console.log("Listener added"); @@ -480,91 +465,14 @@ if (!window.hasAddedQortalListener) { event.stopImmediatePropagation(); // Stop other listeners from firing // Verify that the message is from the web page and contains expected data if (event.source !== window || !event.data || !event.data.action) return; - // // Check if this action should be processed (debounced) - // if (!debounceAction(event.data.action)) { - // console.log(`Debounced action: ${event.data.action}`); - // return; - // } - if(event?.data?.requestedHandler !== 'UI') return - if (event.data.action === "GET_USER_ACCOUNT") { - chrome?.runtime?.sendMessage( - { action: "GET_USER_ACCOUNT", type: "qortalRequest" }, - (response) => { - if (response.error) { - event.ports[0].postMessage({ - result: null, - error: response.error, - }); - } else { - event.ports[0].postMessage({ - result: response, - error: null, - }); - } - } - ); - } else if (event.data.action === "SEND_COIN") { - chrome?.runtime?.sendMessage( - { action: "SEND_COIN", type: "qortalRequest", payload: event.data }, - (response) => { - if (response.error) { - event.ports[0].postMessage({ - result: null, - error: response.error, - }); - } else { - event.ports[0].postMessage({ - result: response, - error: null, - }); - } - } - ); - } else if (event.data.action === "ENCRYPT_DATA") { - chrome?.runtime?.sendMessage( - { action: "ENCRYPT_DATA", type: "qortalRequest", payload: event.data }, - (response) => { - if (response.error) { - event.ports[0].postMessage({ - result: null, - error: response.error, - }); - } else { - event.ports[0].postMessage({ - result: response, - error: null, - }); - } - } - ); - } else if (event.data.action === "DECRYPT_DATA") { - chrome?.runtime?.sendMessage( - { action: "DECRYPT_DATA", type: "qortalRequest", payload: event.data }, - (response) => { - if (response.error) { - event.ports[0].postMessage({ - result: null, - error: response.error, - }); - } else { - event.ports[0].postMessage({ - result: response, - error: null, - }); - } - } - ); - } else if (event.data.action === "GET_LIST_ITEMS") { - console.log("message", event); + if(event?.data?.requestedHandler !== 'UI') return + if (UIQortalRequests.includes(event.data.action)) { + chrome?.runtime?.sendMessage( - { - action: "GET_LIST_ITEMS", - type: "qortalRequest", - payload: event.data, - }, + { action: event.data.action, type: "qortalRequest", payload: event.data }, (response) => { - console.log("response", response); + console.log('response', response) if (response.error) { event.ports[0].postMessage({ result: null, @@ -578,7 +486,7 @@ if (!window.hasAddedQortalListener) { } } ); - } + } }; window.addEventListener("message", listener); } diff --git a/src/App.tsx b/src/App.tsx index a119d20..a8a1a51 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1816,7 +1816,8 @@ function App() { {messageQortalRequest?.text1} @@ -1825,8 +1826,10 @@ function App() { {messageQortalRequest?.text2} @@ -1838,6 +1841,7 @@ function App() { lineHeight: 1.2, fontSize: "16px", fontWeight: 700, + maxWidth: '90%' }} > {messageQortalRequest?.text3} diff --git a/src/qortalRequests.ts b/src/qortalRequests.ts index 388ccf9..08a2612 100644 --- a/src/qortalRequests.ts +++ b/src/qortalRequests.ts @@ -1,4 +1,4 @@ -import { decryptData, encryptData, getListItems, getUserAccount, sendCoin } from "./qortalRequests/get"; +import { addListItems, decryptData, deleteListItems, encryptData, getListItems, getUserAccount, sendCoin } from "./qortalRequests/get"; chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { if (request) { @@ -53,6 +53,32 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { break; } + case "ADD_LIST_ITEMS": { + const data = request.payload; + + addListItems(data) + .then((res) => { + sendResponse(res); + }) + .catch((error) => { + sendResponse({ error: error.message }); + }); + + break; + } + case "DELETE_LIST_ITEM": { + const data = request.payload; + + deleteListItems(data) + .then((res) => { + sendResponse(res); + }) + .catch((error) => { + sendResponse({ error: error.message }); + }); + + break; + } case "SEND_COIN": { const data = request.payload; const requiredFields = ["coin", "destinationAddress", "amount"]; diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index 62a5da8..62efe2d 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -1,4 +1,9 @@ -import { createEndpoint, getKeyPair, getSaveWallet, removeDuplicateWindow } from "../background"; +import { + createEndpoint, + getKeyPair, + getSaveWallet, + removeDuplicateWindow, +} from "../background"; import Base58 from "../deps/Base58"; import { base64ToUint8Array, @@ -11,121 +16,113 @@ import { import { fileToBase64 } from "../utils/fileReading"; async function getUserPermission(payload: any) { - - - function waitForWindowReady(windowId) { - return new Promise((resolve) => { - const checkInterval = setInterval(() => { - chrome.windows.get(windowId, (win) => { - if (chrome.runtime.lastError) { - clearInterval(checkInterval); // Stop polling if there's an error - resolve(false); - } else if (win.state === 'normal' || win.state === 'maximized') { - clearInterval(checkInterval); // Window is ready - resolve(true); - } - }); - }, 100); // Check every 100ms - }); - } - - await new Promise((res)=> { - const popupUrl = chrome.runtime.getURL( - "index.html?secondary=true" - ); - console.log('popupUrl', popupUrl) - chrome.windows.getAll( - { populate: true, windowTypes: ["popup"] }, - (windows) => { - console.log('windows', windows) - // Attempt to find an existing popup window that has a tab with the correct URL - const existingPopup = windows.find( - (w) => - w.tabs && - w.tabs.some( - (tab) => tab.url && tab.url.startsWith(popupUrl) - ) - ); - if (existingPopup) { - // If the popup exists but is minimized or not focused, focus it - chrome.windows.update(existingPopup.id, { - focused: true, - state: "normal", - }); - res(null) - } else { - // No existing popup found, create a new one - chrome.system.display.getInfo((displays) => { - // Assuming the primary display is the first one (adjust logic as needed) - const primaryDisplay = displays[0]; - const screenWidth = primaryDisplay.bounds.width; - const windowHeight = 500; // Your window height - const windowWidth = 400; // Your window width - - // Calculate left position for the window to appear on the right of the screen - const leftPosition = screenWidth - windowWidth; - - // Calculate top position for the window, adjust as desired - const topPosition = - (primaryDisplay.bounds.height - windowHeight) / 2; - - chrome.windows.create( - { - url: popupUrl, - type: "popup", - width: windowWidth, - height: windowHeight, - left: leftPosition, - top: 0, - }, - async (newWindow) => { - removeDuplicateWindow(popupUrl); - await waitForWindowReady(newWindow.id); - - res(null) - } - ); - - }); - } - - - - - } - ); - }) - - await new Promise((res)=> { - setTimeout(() => { - chrome.runtime.sendMessage({ - action: "SET_COUNTDOWN", - payload: 15, - }); - res(true) - }, 450); - }) + function waitForWindowReady(windowId) { return new Promise((resolve) => { - // Set a timeout for 1 second - const timeout = setTimeout(() => { - resolve(false); // No response within 10 second, assume not focused - }, 15000); - - // Send message to the content script to check focus - console.log('send msg') - chrome.runtime.sendMessage({ action: "QORTAL_REQUEST_PERMISSION", payload }, (response) => { - console.log('permission response', response) - if(response === undefined) return + const checkInterval = setInterval(() => { + chrome.windows.get(windowId, (win) => { + if (chrome.runtime.lastError) { + clearInterval(checkInterval); // Stop polling if there's an error + resolve(false); + } else if (win.state === "normal" || win.state === "maximized") { + clearInterval(checkInterval); // Window is ready + resolve(true); + } + }); + }, 100); // Check every 100ms + }); + } + + await new Promise((res) => { + const popupUrl = chrome.runtime.getURL("index.html?secondary=true"); + console.log("popupUrl", popupUrl); + chrome.windows.getAll( + { populate: true, windowTypes: ["popup"] }, + (windows) => { + console.log("windows", windows); + // Attempt to find an existing popup window that has a tab with the correct URL + const existingPopup = windows.find( + (w) => + w.tabs && + w.tabs.some((tab) => tab.url && tab.url.startsWith(popupUrl)) + ); + if (existingPopup) { + // If the popup exists but is minimized or not focused, focus it + chrome.windows.update(existingPopup.id, { + focused: true, + state: "normal", + }); + res(null); + } else { + // No existing popup found, create a new one + chrome.system.display.getInfo((displays) => { + // Assuming the primary display is the first one (adjust logic as needed) + const primaryDisplay = displays[0]; + const screenWidth = primaryDisplay.bounds.width; + const windowHeight = 500; // Your window height + const windowWidth = 400; // Your window width + + // Calculate left position for the window to appear on the right of the screen + const leftPosition = screenWidth - windowWidth; + + // Calculate top position for the window, adjust as desired + const topPosition = + (primaryDisplay.bounds.height - windowHeight) / 2; + + chrome.windows.create( + { + url: popupUrl, + type: "popup", + width: windowWidth, + height: windowHeight, + left: leftPosition, + top: 0, + }, + async (newWindow) => { + removeDuplicateWindow(popupUrl); + await waitForWindowReady(newWindow.id); + + res(null); + } + ); + }); + } + } + ); + }); + + await new Promise((res) => { + setTimeout(() => { + chrome.runtime.sendMessage({ + action: "SET_COUNTDOWN", + payload: 30, + }); + res(true); + }, 700); + }); + return new Promise((resolve) => { + // Set a timeout for 1 second + const timeout = setTimeout(() => { + resolve(false); // No response within 10 second, assume not focused + }, 30000); + + // Send message to the content script to check focus + console.log("send msg"); + chrome.runtime.sendMessage( + { action: "QORTAL_REQUEST_PERMISSION", payload }, + (response) => { + console.log("permission response", response); + if (response === undefined) return; clearTimeout(timeout); // Clear the timeout if we get a response - + if (chrome.runtime.lastError) { resolve(false); // Error occurred, assume not focused } else { resolve(response); // Resolve based on the response } - }); - }); - } + } + ); + }); +} export const getUserAccount = async () => { try { @@ -171,7 +168,6 @@ export const encryptData = async (data) => { export const decryptData = async (data) => { const { encryptedData, publicKey } = data; - if (!encryptedData) { throw new Error(`Missing fields: encryptedData`); } @@ -210,61 +206,155 @@ export const decryptData = async (data) => { throw new Error("Unable to decrypt"); }; - - export const getListItems = async (data) => { - const requiredFields = ['list_name'] - const missingFields: string[] = [] - requiredFields.forEach((field) => { - if (!data[field]) { - missingFields.push(field) - } - }) - if (missingFields.length > 0) { - const missingFieldsString = missingFields.join(', ') - const errorMsg = `Missing fields: ${missingFieldsString}` - throw new Error(errorMsg) - } - let skip = false - // if (window.parent.reduxStore.getState().app.qAPPAutoLists) { - // skip = true - // } - let resPermission - if (!skip) { - // res1 = await showModalAndWait( - // actions.GET_LIST_ITEMS, - // { - // list_name: data.list_name - // } - // ) + const requiredFields = ["list_name"]; + const missingFields: string[] = []; + requiredFields.forEach((field) => { + if (!data[field]) { + missingFields.push(field); + } + }); + if (missingFields.length > 0) { + const missingFieldsString = missingFields.join(", "); + const errorMsg = `Missing fields: ${missingFieldsString}`; + throw new Error(errorMsg); + } + let skip = false; + // if (window.parent.reduxStore.getState().app.qAPPAutoLists) { + // skip = true + // } + let resPermission; + if (!skip) { + // res1 = await showModalAndWait( + // actions.GET_LIST_ITEMS, + // { + // list_name: data.list_name + // } + // ) - resPermission = await getUserPermission({ - text1: 'Do you give this application permission to', - text2: 'Access the list', - text3: data.list_name - }) + resPermission = await getUserPermission({ + text1: "Do you give this application permission to", + text2: "Access the list", + text3: data.list_name, + }); + } + console.log("resPermission", resPermission); + if (resPermission || skip) { + const url = await createEndpoint(`/lists/${data.list_name}`); + console.log("url", url); + const response = await fetch(url); + console.log("response", response); + if (!response.ok) throw new Error("Failed to fetch"); - } - console.log('resPermission', resPermission) - if (resPermission || skip) { - try { - - const url = await createEndpoint(`/lists/${data.list_name}`); - console.log('url', url) - const response = await fetch(url); - console.log('response', response) - if (!response.ok) throw new Error("Failed to fetch"); - - const list = await response.json(); - return list + const list = await response.json(); + return list; + } else { + throw new Error("User declined to share list"); + } +}; - } catch (error) { - throw new Error("Error in retrieving list") - } - } else { - const data = {} - throw new Error("User declined to share list") - } +export const addListItems = async (data) => { + const requiredFields = ["list_name", "items"]; + const missingFields: string[] = []; + requiredFields.forEach((field) => { + if (!data[field]) { + missingFields.push(field); + } + }); + if (missingFields.length > 0) { + const missingFieldsString = missingFields.join(", "); + const errorMsg = `Missing fields: ${missingFieldsString}`; + throw new Error(errorMsg); + } + + const items = data.items; + const list_name = data.list_name; + + const resPermission = await getUserPermission({ + text1: "Do you give this application permission to", + text2: `Add the following to the list ${list_name}:`, + text3: items.join(', ') + }); + + if (resPermission) { + const url = await createEndpoint(`/lists/${list_name}`); + console.log("url", url); + const body = { + items: items, + }; + const bodyToString = JSON.stringify(body); + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: bodyToString, + }); + + console.log("response", response); + if (!response.ok) throw new Error("Failed to add to list"); + let res; + try { + res = await response.clone().json(); + } catch (e) { + res = await response.text(); + } + return res + } else { + throw new Error("User declined add to list"); + } +}; + +export const deleteListItems = async (data) => { + const requiredFields = ['list_name', 'item'] + const missingFields: string[] = []; + requiredFields.forEach((field) => { + if (!data[field]) { + missingFields.push(field); + } + }); + if (missingFields.length > 0) { + const missingFieldsString = missingFields.join(", "); + const errorMsg = `Missing fields: ${missingFieldsString}`; + throw new Error(errorMsg); + } + + const item = data.item; + const list_name = data.list_name; + + const resPermission = await getUserPermission({ + text1: "Do you give this application permission to", + text2: `Remove the following from the list ${list_name}:`, + text3: item + }); + + if (resPermission) { + const url = await createEndpoint(`/lists/${list_name}`); + console.log("url", url); + const body = { + items: [item], + }; + const bodyToString = JSON.stringify(body); + const response = await fetch(url, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: bodyToString, + }); + + console.log("response", response); + if (!response.ok) throw new Error("Failed to add to list"); + let res; + try { + res = await response.clone().json(); + } catch (e) { + res = await response.text(); + } + return res + } else { + throw new Error("User declined add to list"); + } }; export const sendCoin = async () => {