From 45a15b3823bf7defa54b3fb73d91243b091b8131 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Mon, 25 Nov 2024 08:59:42 +0200 Subject: [PATCH] fixed rating, added open new tab qortal request --- src/background-cases.ts | 63 +++++++ src/background.ts | 8 + src/components/Apps/AppRating.tsx | 29 ++-- .../Apps/useQortalMessageListener.tsx | 2 +- src/components/Chat/MessageDisplay.tsx | 2 +- src/qortalRequests.ts | 24 ++- src/qortalRequests/get.ts | 159 ++++++++++++++---- 7 files changed, 234 insertions(+), 53 deletions(-) diff --git a/src/background-cases.ts b/src/background-cases.ts index cd1196a..ae266e0 100644 --- a/src/background-cases.ts +++ b/src/background-cases.ts @@ -57,6 +57,7 @@ import { import { decryptGroupEncryption, encryptAndPublishSymmetricKeyGroupChat, publishGroupEncryptedResource, publishOnQDN } from "./backgroundFunctions/encryption"; import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from "./constants/codes"; import { encryptSingle } from "./qdn/encryption/group-encryption"; +import { _createPoll, _voteOnPoll } from "./qortalRequests/get"; import { getData, storeData } from "./utils/chromeStorage"; export function versionCase(request, event) { @@ -1800,4 +1801,66 @@ export async function publishGroupEncryptedResourceCase(request, event) { event.origin ); } + } + + export async function createPollCase(request, event) { + try { + console.log('request', event) + const { pollName, pollDescription, pollOptions } = request.payload; + const resCreatePoll = await _createPoll( + { + pollName, + pollDescription, + options: pollOptions, + }, + true, + true // skip permission + ); + + event.source.postMessage( + { + requestId: request.requestId, + action: "registerName", + payload: resCreatePoll, + type: "backgroundMessageResponse", + }, + event.origin + ); + } catch (error) { + event.source.postMessage( + { + requestId: request.requestId, + action: "registerName", + error: error?.message, + type: "backgroundMessageResponse", + }, + event.origin + ); + } + } + export async function voteOnPollCase(request, event) { + try { + const res = await _voteOnPoll(request.payload, true, true); + + + event.source.postMessage( + { + requestId: request.requestId, + action: "registerName", + payload: res, + type: "backgroundMessageResponse", + }, + event.origin + ); + } catch (error) { + event.source.postMessage( + { + requestId: request.requestId, + action: "registerName", + error: error?.message, + type: "backgroundMessageResponse", + }, + event.origin + ); + } } \ No newline at end of file diff --git a/src/background.ts b/src/background.ts index 1c651cb..75460cd 100644 --- a/src/background.ts +++ b/src/background.ts @@ -96,6 +96,8 @@ import { userInfoCase, validApiCase, versionCase, + createPollCase, + voteOnPollCase, } from "./background-cases"; import { getData, removeKeysAndLogout, storeData } from "./utils/chromeStorage"; import {BackgroundFetch} from '@transistorsoft/capacitor-background-fetch'; @@ -2858,6 +2860,12 @@ function setupMessageListener() { case "sendChatGroup": sendChatGroupCase(request, event); break; + case "createPoll": + createPollCase(request, event); + break; + case "voteOnPoll": + voteOnPollCase(request, event); + break; case "sendChatDirect": sendChatDirectCase(request, event); break; diff --git a/src/components/Apps/AppRating.tsx b/src/components/Apps/AppRating.tsx index 0ac5fa0..4b1d23e 100644 --- a/src/components/Apps/AppRating.tsx +++ b/src/components/Apps/AppRating.tsx @@ -103,28 +103,30 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => { getRating(app?.name, app?.service); }, [getRating, app?.name]); - const rateFunc = async (event, newValue) => { + const rateFunc = async (event, chosenValue, currentValue) => { try { + const newValue = chosenValue || currentValue + console.log('event', newValue) if (!myName) throw new Error("You need a name to rate."); if (!app?.name) return; - const fee = await getFee("ARBITRARY"); + const fee = await getFee("CREATE_POLL"); await show({ - message: `Would you like to rate this app a rating of ${newValue}?`, + message: `Would you like to rate this app a rating of ${newValue}?. It will create a POLL tx.`, publishFee: fee.fee + " QORT", }); - + console.log('hasPublishedRating', hasPublishedRating) if (hasPublishedRating === false) { const pollName = `app-library-${app.service}-rating-${app.name}`; const pollOptions = [`1, 2, 3, 4, 5, initialValue-${newValue}`]; await new Promise((res, rej) => { - window.sendMessage("CREATE_POLL", { - payload: { + window.sendMessage("createPoll", { + pollName: pollName, pollDescription: `Rating for ${app.service} ${app.name}`, pollOptions: pollOptions, pollOwnerAddress: myName, - }, + }, 60000) .then((response) => { if (response.error) { @@ -147,17 +149,19 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => { }); } else { const pollName = `app-library-${app.service}-rating-${app.name}`; + const optionIndex = pollInfo?.pollOptions.findIndex( (option) => +option.optionName === +newValue ); + console.log('optionIndex', optionIndex, newValue) if (isNaN(optionIndex) || optionIndex === -1) throw new Error("Cannot find rating option"); await new Promise((res, rej) => { - window.sendMessage("VOTE_ON_POLL", { - payload: { + window.sendMessage("voteOnPoll", { + pollName: pollName, optionIndex, - }, + }, 60000) .then((response) => { if (response.error) { @@ -180,9 +184,10 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => { }); } } catch (error) { + console.log('error', error) setInfoSnack({ type: "error", - message: error.message || "An error occurred while trying to rate.", + message: error?.message || "Unable to rate", }); setOpenSnack(true); } @@ -212,7 +217,7 @@ export const AppRating = ({ app, myName, ratingCountPosition = "right" }) => { rateFunc(event, rating, value)} precision={1} readOnly={hasPublishedRating === null} size="small" diff --git a/src/components/Apps/useQortalMessageListener.tsx b/src/components/Apps/useQortalMessageListener.tsx index 37e54f6..be82cf0 100644 --- a/src/components/Apps/useQortalMessageListener.tsx +++ b/src/components/Apps/useQortalMessageListener.tsx @@ -184,7 +184,7 @@ const UIQortalRequests = [ 'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE', 'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER', 'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER', - 'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY', 'ADMIN_ACTION' + 'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY', 'ADMIN_ACTION', 'OPEN_NEW_TAB' ]; diff --git a/src/components/Chat/MessageDisplay.tsx b/src/components/Chat/MessageDisplay.tsx index 85013d8..43d978d 100644 --- a/src/components/Chat/MessageDisplay.tsx +++ b/src/components/Chat/MessageDisplay.tsx @@ -4,7 +4,7 @@ import './styles.css'; import { executeEvent } from '../../utils/events'; import { Browser } from '@capacitor/browser'; -const extractComponents = (url) => { +export const extractComponents = (url) => { if (!url || !url.startsWith("qortal://")) { // Check if url exists and starts with "qortal://" return null; } diff --git a/src/qortalRequests.ts b/src/qortalRequests.ts index 8c39b73..01389f0 100644 --- a/src/qortalRequests.ts +++ b/src/qortalRequests.ts @@ -1,5 +1,5 @@ import { gateways, getApiKeyFromStorage } from "./background"; -import { addForeignServer, addListItems, adminAction, cancelSellOrder, createBuyOrder, createPoll, decryptData, deleteListItems, deployAt, encryptData, getCrossChainServerInfo, getDaySummary, getForeignFee, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get"; +import { addForeignServer, addListItems, adminAction, cancelSellOrder, createBuyOrder, createPoll, decryptData, deleteListItems, deployAt, encryptData, getCrossChainServerInfo, getDaySummary, getForeignFee, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, openNewTab, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get"; import { getData, storeData } from "./utils/chromeStorage"; @@ -277,7 +277,7 @@ export const isRunningGateway = async ()=> { case "SEND_CHAT_MESSAGE": { try { - const res = await sendChatMessage(request.payload, isFromExtension); + const res = await sendChatMessage(request.payload, isFromExtension, appInfo); event.source.postMessage({ requestId: request.requestId, action: request.action, @@ -674,6 +674,26 @@ export const isRunningGateway = async ()=> { } break; } + + case "OPEN_NEW_TAB": { + try { + const res = await openNewTab(request.payload, isFromExtension) + event.source.postMessage({ + requestId: request.requestId, + action: request.action, + payload: res, + type: "backgroundMessageResponse", + }, event.origin); + } catch (error) { + event.source.postMessage({ + requestId: request.requestId, + action: request.action, + error: error?.message, + type: "backgroundMessageResponse", + }, event.origin); + } + break; + } default: break; diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index 13fd108..e81e05d 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -35,6 +35,8 @@ import { mimeToExtensionMap } from "../utils/memeTypes"; import TradeBotCreateRequest from "../transactions/TradeBotCreateRequest"; import DeleteTradeOffer from "../transactions/TradeBotDeleteRequest"; import signTradeBotTransaction from "../transactions/signTradeBotTransaction"; +import { executeEvent } from "../utils/events"; +import { extractComponents } from "../components/Chat/MessageDisplay"; const btcFeePerByte = 0.00000100 const ltcFeePerByte = 0.00000030 @@ -54,19 +56,28 @@ function roundUpToDecimals(number, decimals = 8) { return Math.ceil(+number * factor) / factor; } -const _createPoll = async ({pollName, pollDescription, options}, isFromExtension) => { +export const _createPoll = async ( + { pollName, pollDescription, options }, + isFromExtension, skipPermission +) => { const fee = await getFee("CREATE_POLL"); + let resPermission = {} + if(!skipPermission){ + resPermission = await getUserPermission( + { + text1: "You are requesting to create the poll below:", + text2: `Poll: ${pollName}`, + text3: `Description: ${pollDescription}`, + text4: `Options: ${options?.join(", ")}`, + fee: fee.fee, + }, + isFromExtension + ); + } + + const { accepted = false } = resPermission; - const resPermission = await getUserPermission({ - text1: "You are requesting to create the poll below:", - text2: `Poll: ${pollName}`, - text3: `Description: ${pollDescription}`, - text4: `Options: ${options?.join(", ")}`, - fee: fee.fee, - }, isFromExtension); - const { accepted } = resPermission; - - if (accepted) { + if (accepted || skipPermission) { const wallet = await getSaveWallet(); const address = wallet.address0; const resKeyPair = await getKeyPair(); @@ -90,7 +101,9 @@ const _createPoll = async ({pollName, pollDescription, options}, isFromExtension const signedBytes = Base58.encode(tx.signedBytes); const res = await processTransactionVersion2(signedBytes); if (!res?.signature) - throw new Error(res?.message || "Transaction was not able to be processed"); + throw new Error( + res?.message || "Transaction was not able to be processed" + ); return res; } else { throw new Error("User declined request"); @@ -155,18 +168,27 @@ const _deployAt = async ( } }; -const _voteOnPoll = async ({pollName, optionIndex, optionName}, isFromExtension) => { +export const _voteOnPoll = async ( + { pollName, optionIndex, optionName }, + isFromExtension, skipPermission +) => { const fee = await getFee("VOTE_ON_POLL"); + let resPermission = {} + if(!skipPermission){ + resPermission = await getUserPermission( + { + text1: "You are being requested to vote on the poll below:", + text2: `Poll: ${pollName}`, + text3: `Option: ${optionName}`, + fee: fee.fee, + }, + isFromExtension + ); + } + + const { accepted = false } = resPermission; - const resPermission = await getUserPermission({ - text1: "You are being requested to vote on the poll below:", - text2: `Poll: ${pollName}`, - text3: `Option: ${optionName}`, - fee: fee.fee, - }, isFromExtension); - const { accepted } = resPermission; - - if (accepted) { + if (accepted || skipPermission) { const wallet = await getSaveWallet(); const address = wallet.address0; const resKeyPair = await getKeyPair(); @@ -189,7 +211,9 @@ const _voteOnPoll = async ({pollName, optionIndex, optionName}, isFromExtension) const signedBytes = Base58.encode(tx.signedBytes); const res = await processTransactionVersion2(signedBytes); if (!res?.signature) - throw new Error(res?.message || "Transaction was not able to be processed"); + throw new Error( + res?.message || "Transaction was not able to be processed" + ); return res; } else { throw new Error("User declined request"); @@ -971,19 +995,40 @@ export const createPoll = async (data, isFromExtension) => { } }; -export const sendChatMessage = async (data, isFromExtension) => { - const message = data.message; +export const sendChatMessage = async (data, isFromExtension, appInfo) => { + const message = data?.message; + const fullMessageObject = data?.fullMessageObject const recipient = data.destinationAddress; const groupId = data.groupId; const isRecipient = !groupId; - const resPermission = await getUserPermission({ - text1: "Do you give this application permission to send this chat message?", - text2: `To: ${isRecipient ? recipient : `group ${groupId}`}`, - text3: `${message?.slice(0, 25)}${message?.length > 25 ? "..." : ""}`, - }, isFromExtension); - const { accepted } = resPermission; - if (accepted) { + const value = + (await getPermission(`qAPPSendChatMessage-${appInfo?.name}`)) || false; +let skip = false; +if (value) { + skip = true; +} +let resPermission; +if (!skip) { + resPermission = await getUserPermission( + { + text1: + "Do you give this application permission to send this chat message?", + text2: `To: ${isRecipient ? recipient : `group ${groupId}`}`, + text3: `${message?.slice(0, 25)}${message?.length > 25 ? "..." : ""}`, + checkbox1: { + value: false, + label: "Always allow chat messages from this app", + }, + }, + isFromExtension + ); + } + const { accepted = false, checkbox1 = false } = resPermission || {}; + if (resPermission && accepted) { + setPermission(`qAPPSendChatMessage-${appInfo?.name}`, checkbox1); + } + if (accepted || skip) { const tiptapJson = { type: "doc", content: [ @@ -998,13 +1043,13 @@ export const sendChatMessage = async (data, isFromExtension) => { }, ], }; - const messageObject = { + const messageObject = fullMessageObject ? fullMessageObject : { messageText: tiptapJson, images: [""], repliedTo: "", version: 3, }; - + const stringifyMessageObject = JSON.stringify(messageObject); const balance = await getBalanceInfo(); @@ -1072,9 +1117,14 @@ export const sendChatMessage = async (data, isFromExtension) => { isEncrypted: 1, isText: 1, }); + const chatBytes = tx.chatBytes; const difficulty = 8; - const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty); + const { nonce, chatBytesArray } = await performPowTask( + chatBytes, + difficulty + ); + let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair); if (_response?.error) { throw new Error(_response?.message); @@ -1094,7 +1144,6 @@ export const sendChatMessage = async (data, isFromExtension) => { publicKey: uint8PublicKey, }; - const txBody = { timestamp: Date.now(), groupID: Number(groupId), @@ -1112,9 +1161,14 @@ export const sendChatMessage = async (data, isFromExtension) => { // if (!hasEnoughBalance) { // throw new Error("Must have at least 4 QORT to send a chat message"); // } + const chatBytes = tx.chatBytes; const difficulty = 8; - const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty); + const { nonce, chatBytesArray } = await performPowTask( + chatBytes, + difficulty + ); + let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair); if (_response?.error) { throw new Error(_response?.message); @@ -2795,4 +2849,35 @@ export const adminAction = async (data, isFromExtension) => { throw new Error("User declined request"); } +}; + +export const openNewTab = async (data, isFromExtension) => { + const requiredFields = [ + "qortalLink", + ]; + 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 res = extractComponents(data.qortalLink); + if (res) { + const { service, name, identifier, path } = res; + if(!service && !name) throw new Error('Invalid qortal link') + executeEvent("addTab", { data: { service, name, identifier, path } }); + executeEvent("open-apps-mode", { }); + return true + } else { + throw new Error("Invalid qortal link") + } + + + }; \ No newline at end of file