From 35e6595311e23eff3490932d319124f6a6b4888a Mon Sep 17 00:00:00 2001 From: crowetic Date: Fri, 31 Jan 2025 16:37:16 -0800 Subject: [PATCH] EMERGENCY UPDATE 1.06b --- assets/js/AdminBoard.js | 109 ++++++-------------------------------- assets/js/MinterBoard.js | 33 +++++++++--- assets/js/Q-Mintership.js | 2 +- assets/js/QortalApi.js | 11 ++-- assets/js/Shared.js | 30 +++++++++-- index.html | 4 +- 6 files changed, 78 insertions(+), 111 deletions(-) diff --git a/assets/js/AdminBoard.js b/assets/js/AdminBoard.js index f461032..a53c370 100644 --- a/assets/js/AdminBoard.js +++ b/assets/js/AdminBoard.js @@ -198,65 +198,6 @@ const loadAdminBoardPage = async () => { await fetchAllEncryptedCards() } -// const fetchAllKicKBanTxData = async () => { -// const kickTxType = "GROUP_KICK" -// const banTxType = "GROUP_BAN" - -// // Helper function to filter transactions -// const filterTransactions = (rawTransactions) => { -// // Group transactions by member -// const memberTxMap = rawTransactions.reduce((map, tx) => { -// if (!map[tx.member]) { -// map[tx.member] = [] -// } -// map[tx.member].push(tx) -// return map -// }, {}) - -// // Filter out members with both pending and non-pending transactions -// return Object.values(memberTxMap) -// .filter(txs => txs.every(tx => tx.approvalStatus !== 'PENDING')) -// .flat() -// // .filter((txs) => !(txs.some(tx => tx.approvalStatus === 'PENDING') && -// // txs.some(tx => tx.approvalStatus !== 'PENDING'))) -// // .flat() -// } - -// // Fetch ban transactions -// const rawBanTransactions = await searchTransactions({ -// txTypes: [banTxType], -// address: '', -// confirmationStatus: 'CONFIRMED', -// limit: 0, -// reverse: true, -// offset: 0, -// startBlock: 1990000, -// blockLimit: 0, -// txGroupId: 0, -// }) - -// // Filter transactions for bans -// banTransactions = filterTransactions(rawBanTransactions) -// console.warn('banTxData (filtered):', banTransactions) - -// // Fetch kick transactions -// const rawKickTransactions = await searchTransactions({ -// txTypes: [kickTxType], -// address: '', -// confirmationStatus: 'CONFIRMED', -// limit: 0, -// reverse: true, -// offset: 0, -// startBlock: 1990000, -// blockLimit: 0, -// txGroupId: 0, -// }) - -// // Filter transactions for kicks -// kickTransactions = filterTransactions(rawKickTransactions) -// console.warn('kickTxData (filtered):', kickTransactions) -// } - // Example: fetch and save admin public keys and count const updateOrSaveAdminGroupsDataLocally = async () => { @@ -299,7 +240,7 @@ const loadOrFetchAdminGroupsData = async () => { adminMemberCount = parsedData.keysCount adminPublicKeys = parsedData.publicKeys - console.log(typeof adminPublicKeys); // Should be "object" + console.log(typeof adminPublicKeys) // Should be "object" console.log(Array.isArray(adminPublicKeys)) console.log(`Loaded admins 'keysCount'=${adminMemberCount}, publicKeys=`, adminPublicKeys) @@ -1221,7 +1162,6 @@ const handleBanMinter = async (minterName) => { alert(`No valid address found for minter name: ${minterName}, this should NOT have happened, please report to developers...`) return } - const adminPublicKey = await getPublicKeyByName(userState.accountName) const reason = 'Banned by Minter Admins' const fee = 0.01 @@ -1232,14 +1172,13 @@ const handleBanMinter = async (minterName) => { action: "SIGN_TRANSACTION", unsignedBytes: rawBanTransaction }) + if (!signedBanTransaction) { console.warn(`this only happens if the SIGN_TRANSACTION qortalRequest failed... are you using the legacy UI prior to this qortalRequest being added?`) alert(`this only happens if the SIGN_TRANSACTION qortalRequest failed... are you using the legacy UI prior to this qortalRequest being added? Please talk to developers.`) return } - let txToProcess = signedBanTransaction - const processedTx = await processTransaction(txToProcess) if (typeof processedTx === 'object') { @@ -1304,6 +1243,18 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co showTopic = false } } + let publishedMinterAddress = minterAddress + + if (publishedMinterAddress === 'notYetAdded' || publishedMinterAddress === 'undefined' || publishedMinterAddress === null || !publishedMinterAddress) { + console.warn(`minterAddress is not published in the card data... will have to extract from minterName...`) + publishedMinterAddress = null + } else { + const publishedMinterAddressInfo = await getAddressInfo(publishedMinterAddress) + if (publishedMinterAddressInfo) { + console.log(`minterAddress found in published data, and verified. Using published address for further checks.`) + publishedMinterAddress = publishedMinterAddressInfo.address + } + } let cardColorCode = showTopic ? '#0e1b15' : '#151f28' @@ -1329,7 +1280,7 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co const verifiedName = await validateMinterName(minterName) let levelText = '' const addressVerification = await getAddressInfo(minterName) - const verifiedAddress = addressVerification.address + const verifiedAddress = publishedMinterAddress ? publishedMinterAddress : addressVerification.address if (verifiedName || verifiedAddress) { let accountInfo @@ -1337,7 +1288,7 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co accountInfo = await getNameInfo(verifiedName) } - const accountAddress = verifiedAddress ? addressVerification.address : accountInfo.owner + const accountAddress = verifiedAddress ? addressVerification.address : accountInfo.owner const addressInfo = verifiedAddress ? addressVerification : await getAddressInfo(accountAddress) const minterGroupAddresses = minterGroupMembers.map(m => m.member) const adminAddresses = minterAdmins.map(m => m.member) @@ -1399,34 +1350,6 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co } } - // if (banTransactions.some((banTx) => banTx.groupId === 694 && banTx.offender === accountAddress)){ - // console.warn(`account was already banned, displaying as such...`) - // cardColorCode = 'rgb(24, 3, 3)' - // altText = `

BANNED From MINTER Group

` - // showRemoveHtml = '' - // if (!adminBoardState.bannedCards.has(cardIdentifier)){ - // adminBoardState.bannedCards.add(cardIdentifier) - // } - // if (!showKickedBanned){ - // console.warn(`kick/bank checkbox is unchecked, and card is banned, not displaying...`) - // return '' - // } - // } - - // if (kickTransactions.some((kickTx) => kickTx.groupId === 694 && kickTx.member === accountAddress)){ - // console.warn(`account was already kicked, displaying as such...`) - // cardColorCode = 'rgb(29, 7, 4)' - // altText = `

KICKED From MINTER Group

` - // showRemoveHtml = '' - // if (!adminBoardState.kickedCards.has(cardIdentifier)){ - // adminBoardState.kickedCards.add(cardIdentifier) - // } - // if (!showKickedBanned) { - // console.warn(`kick/ban checkbox is unchecked, card is kicked, not displaying...`) - // return '' - // } - // } - } else { console.log(`name could not be validated, assuming topic card (or some other issue with name validation) for removalActions`) showRemoveHtml = '' diff --git a/assets/js/MinterBoard.js b/assets/js/MinterBoard.js index 4c7f0c0..196cc01 100644 --- a/assets/js/MinterBoard.js +++ b/assets/js/MinterBoard.js @@ -1468,14 +1468,22 @@ const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) => const minterAddress = minterNameInfo.owner // fetch all final KICK/BAN tx const { finalKickTxs, finalBanTxs } = await fetchAllKickBanTxData() + const { finalInviteTxs, pendingInviteTxs } = await fetchAllInviteTransactions() // check if there's a final (non-pending) KICK or BAN for this user const priorKick = finalKickTxs.some(tx => tx.member === minterAddress) const priorBan = finalBanTxs.some(tx => tx.offender === minterAddress) + const existingInvite = finalInviteTxs.some(tx => tx.invitee === minterAddress) + const pendingInvite = pendingInviteTxs.some(tx => tx.invitee === minterAddress) const priorBanOrKick = (priorBan || priorKick) console.warn(`PriorBanOrKick determination for ${minterAddress}:`, priorBanOrKick) // build the normal invite button & groupApprovalHtml - const inviteButtonHtml = isSomeTypaAdmin ? createInviteButtonHtml(creator, cardIdentifier) : "" + let inviteButtonHtml = "" + if (existingInvite || pendingInvite){ + console.warn(`There is an EXISTING INVITE for this user! No invite button being created... existing: (${existingInvite}, pending: ${pendingInvite})`) + inviteButtonHtml = '' + } + inviteButtonHtml = isSomeTypaAdmin ? createInviteButtonHtml(creator, cardIdentifier) : "" const groupApprovalHtml = await checkGroupApprovalAndCreateButton(minterAddress, cardIdentifier, "GROUP_INVITE") // if user had no prior KICK/BAN @@ -1501,7 +1509,7 @@ const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) => const findPendingApprovalTxForAddress = async (address, txType, limit = 0, offset = 0) => { // 1) Fetch all pending transactions - const pendingTxs = await searchPendingTransactions(limit, offset) + const pendingTxs = await searchPendingTransactions(limit, offset, false) // if a txType is passed, return the results related to that type, if not, then return any pending tx of the potential types. let relevantTypes if (txType) { @@ -1530,31 +1538,42 @@ const findPendingApprovalTxForAddress = async (address, txType, limit = 0, offse } }) console.warn(`matchedTxs:`,matchedTxs) - + //Sort oldest→newest by timestamp, so matchedTxs[0] is the oldest + matchedTxs.sort((a, b) => a.timestamp - b.timestamp) return matchedTxs // Array of matching pending transactions } const checkGroupApprovalAndCreateButton = async (address, cardIdentifier, transactionType) => { + // We are going to be verifying that the address isn't already a minter, before showing GROUP_APPROVAL buttons potentially... + if (transactionType === "GROUP_INVITE") { + console.log(`This is a GROUP_INVITE check for group approval... Checking that user isn't already a minter...`) + const minterMembers = await fetchMinterGroupMembers() + const minterGroupAddresses = minterMembers.map(m => m.member) + if (minterGroupAddresses.includes(address)) { + console.warn(`User is already a minter, will not be creating group_approval buttons`) + return null + } + } + const approvalSearchResults = await searchTransactions({ txTypes: ['GROUP_APPROVAL'], confirmationStatus: 'CONFIRMED', limit: 0, - reverse: true, + reverse: false, offset: 0, startBlock: 1990000, blockLimit: 0, txGroupId: 0 }) - const pendingApprovals = await findPendingApprovalTxForAddress(address, transactionType) + const pendingApprovals = await findPendingApprovalTxForAddress(address, transactionType, 0, 0) let isSomeTypaAdmin = userState.isAdmin || userState.isMinterAdmin - // If no pending transaction found, return null if (!pendingApprovals || pendingApprovals.length === 0) { console.warn("no pending approval transactions found, returning null...") return null } const txSig = pendingApprovals[0].signature - // Among the already-confirmed GROUP_APPROVAL, filter for those referencing this txSig + // Find the relevant signature. (First approval) const relevantApprovals = approvalSearchResults.filter( (approvalTx) => approvalTx.pendingSignature === txSig ) diff --git a/assets/js/Q-Mintership.js b/assets/js/Q-Mintership.js index 41ad593..f233acb 100644 --- a/assets/js/Q-Mintership.js +++ b/assets/js/Q-Mintership.js @@ -1,4 +1,4 @@ -const Q_MINTERSHIP_VERSION = "1.05.2" +const Q_MINTERSHIP_VERSION = "1.06" const messageIdentifierPrefix = `mintership-forum-message` const messageAttachmentIdentifierPrefix = `mintership-forum-attachment` diff --git a/assets/js/QortalApi.js b/assets/js/QortalApi.js index 1991d9d..bbde701 100644 --- a/assets/js/QortalApi.js +++ b/assets/js/QortalApi.js @@ -782,7 +782,7 @@ const searchAllWithOffset = async (service, query, limit, offset, room) => { // NOTE - This function does a search and will return EITHER AN ARRAY OR A SINGLE OBJECT. if you want to guarantee a single object, pass 1 as limit. i.e. await searchSimple(service, identifier, "", 1) will return a single object. const searchSimple = async (service, identifier, name, limit=1500, offset=0, room='', reverse=true, prefixOnly=true, after=0) => { try { - let urlSuffix = `service=${service}&identifier=${identifier}&name=${name}&prefix=true&limit=${limit}&offset=${offset}&reverse=${reverse}&prefix=${prefixOnly}&fter=${after}` + let urlSuffix = `service=${service}&identifier=${identifier}&name=${name}&prefix=true&limit=${limit}&offset=${offset}&reverse=${reverse}&prefix=${prefixOnly}&after=${after}` if (name && !identifier && !room) { console.log('name only searchSimple', name) @@ -1840,13 +1840,14 @@ const searchTransactions = async ({ } } -const searchPendingTransactions = async (limit = 20, offset = 0) => { +const searchPendingTransactions = async (limit=20, offset=0, reverse=false) => { try { const queryParams = [] if (limit) queryParams.push(`limit=${limit}`) if (offset) queryParams.push(`offset=${offset}`) + if (reverse) queryParams.push(`reverse=${reverse}`) - const queryString = queryParams.join('&'); + const queryString = queryParams.join('&') const url = `${baseUrl}/transactions/pending${queryString ? `?${queryString}` : ''}` const response = await fetch(url, { @@ -1855,11 +1856,11 @@ const searchPendingTransactions = async (limit = 20, offset = 0) => { }) if (!response.ok) { - const errorText = await response.text(); + const errorText = await response.text() throw new Error(`Failed to search pending transactions: HTTP ${response.status}, ${errorText}`) } - const result = await response.json(); + const result = await response.json() if (!Array.isArray(result)) { throw new Error("Expected an array for pending transactions, but got something else.") } diff --git a/assets/js/Shared.js b/assets/js/Shared.js index b03885d..61480fe 100644 --- a/assets/js/Shared.js +++ b/assets/js/Shared.js @@ -163,9 +163,9 @@ const fetchAllKickBanTxData = async () => { finalBanTxs, pendingBanTxs, } - } +} - const partitionTransactions = (txSearchResults) => { +const partitionTransactions = (txSearchResults) => { const finalTx = [] const pendingTx = [] @@ -178,7 +178,31 @@ const fetchAllKickBanTxData = async () => { } return { finalTx, pendingTx }; - } +} +const fetchAllInviteTransactions = async () => { + const inviteTxType = "GROUP_INVITE" + + const allInviteTx = await searchTransactions({ + txTypes: [inviteTxType], + confirmationStatus: 'CONFIRMED', + limit: 0, + reverse: true, + offset: 0, + startBlock: 1990000, + blockLimit: 0, + txGroupId: 0, + }) + + const { finalTx: finalInviteTxs, pendingTx: pendingInviteTxs } = partitionTransactions(allInviteTx) + + console.log('Final kickTxs:', finalInviteTxs) + console.log('Pending kickTxs:', pendingInviteTxs) + + return { + finalInviteTxs, + pendingInviteTxs, + } +} \ No newline at end of file diff --git a/index.html b/index.html index 2c89bd8..79741c7 100644 --- a/index.html +++ b/index.html @@ -201,13 +201,13 @@

- v1.05.1beta 01-29-2025

+ v1.06beta 01-31-2025

- v1.05.1b Fixes- This section will be moving - See post in the FORUM for RELEASE NOTES, too many to list here. This updates section will be getting moved to a section of the forum in the future. This version is simply a bump to resolve a typo in a variable on the MinterBoard. The majority of the changes took place in 1.05b. + v1.06b Fixes- EMERGENCY UPDATE - See post in the FORUM for RELEASE NOTES, This is an emergency update that is meant to prevent the issue that took place yesterday and ended up stalling quite a few nodes. This means that Q-Mintership should be the ONLY APP UTILIZED FOR THE FUNCTIONALITY IT PROVIDES.