diff --git a/assets/js/ARBoard.js b/assets/js/ARBoard.js index 05e7fed..e19b702 100644 --- a/assets/js/ARBoard.js +++ b/assets/js/ARBoard.js @@ -59,6 +59,13 @@ const loadAddRemoveAdminPage = async () => {

Existing Promotion/Demotion Proposals

+
@@ -80,8 +87,8 @@ const loadAddRemoveAdminPage = async () => { // proposeButton.style.display === 'flex' ? 'none' : 'flex' } catch (error) { - console.error("Error checking for existing card:", error) - alert("Failed to check for existing card. Please try again.") + console.error("Error opening propose form", error) + alert("Failed to open proposal form. Please try again.") } }) @@ -126,79 +133,79 @@ const toggleProposeButton = () => { proposeButton.style.display === 'flex' ? 'none' : 'flex' } -let addAdminTxs -let remAdminTxs - const fetchAllARTxData = async () => { const addAdmTx = "ADD_GROUP_ADMIN" const remAdmTx = "REMOVE_GROUP_ADMIN" - const filterAddTransactions = (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() - } - - const filterRemoveTransactions = (rawTransactions) => { - // Group transactions by member - const adminTxMap = rawTransactions.reduce((map, tx) => { - if (!map[tx.admin]) { - map[tx.admin] = [] - } - map[tx.admin].push(tx) - return map - }, {}) - - // Filter out members with both pending and non-pending transactions - return Object.values(adminTxMap) - .filter((txs) => !(txs.some(tx => tx.approvalStatus === 'PENDING') && - txs.some(tx => tx.approvalStatus !== 'PENDING'))) - .flat() - } - - // Fetch ban transactions const allAddTxs = await searchTransactions({ - txTypes: [addAdmTx], - confirmationStatus: 'CONFIRMED', - limit: 0, - reverse: true, - offset: 0, - startBlock: 1990000, - blockLimit: 0, - txGroupId: 694, - }) - // Filter out 'PENDING' - addAdminTxs = filterAddTransactions(allAddTxs) - console.warn('addAdminTxData (no PENDING nor past+PENDING):', addAdminTxs) + txTypes: [addAdmTx], + confirmationStatus: 'CONFIRMED', + limit: 0, + reverse: true, + offset: 0, + startBlock: 1990000, + blockLimit: 0, + txGroupId: 694, + }) + + const allRemTxs = await searchTransactions({ + txTypes: [remAdmTx], + confirmationStatus: 'CONFIRMED', + limit: 0, + reverse: true, + offset: 0, + startBlock: 1990000, + blockLimit: 0, + txGroupId: 694, + }) + + const { finalAddTxs, pendingAddTxs } = partitionAddTransactions(allAddTxs) + const { finalRemTxs, pendingRemTxs } = partitionRemoveTransactions(allRemTxs) + + // We are going to keep all transactions in order to filter more accurately for display purposes. + console.log('Final addAdminTxs:', finalAddTxs); + console.log('Pending addAdminTxs:', pendingAddTxs); + console.log('Final remAdminTxs:', finalRemTxs); + console.log('Pending remAdminTxs:', pendingRemTxs); + + return { + finalAddTxs, + pendingAddTxs, + finalRemTxs, + pendingRemTxs, + } +} + +function partitionAddTransactions(rawTransactions) { + const finalAddTxs = [] + const pendingAddTxs = [] + + for (const tx of rawTransactions) { + if (tx.approvalStatus === 'PENDING') { + pendingAddTxs.push(tx) + } else { + finalAddTxs.push(tx) + } + } + + return { finalAddTxs, pendingAddTxs }; +} + +function partitionRemoveTransactions(rawTransactions) { + const finalRemTxs = [] + const pendingRemTxs = [] + + for (const tx of rawTransactions) { + if (tx.approvalStatus === 'PENDING') { + pendingRemTxs.push(tx) + } else { + finalRemTxs.push(tx) + } + } + + return { finalRemTxs, pendingRemTxs } +} - // Fetch kick transactions - const allRemTxs = await searchTransactions({ - txTypes: [remAdmTx], - confirmationStatus: 'CONFIRMED', - limit: 0, - reverse: true, - offset: 0, - startBlock: 1990000, - blockLimit: 0, - txGroupId: 694, - }) - // Filter out 'PENDING' - remAdminTxs = filterRemoveTransactions(allRemTxs) - console.warn('remAdminTxData (no PENDING nor past+PENDING):', remAdminTxs) - } const displayExistingMinterAdmins = async () => { const adminListContainer = document.getElementById("admin-list-container") @@ -309,9 +316,10 @@ const handleProposeDemotion = async (adminName, adminAddress) => { // Notify the user to fill out the rest alert(`Admin "${adminName}" has been selected for demotion. Please fill out the rest of the form.`) - } +} + - const fetchExistingARCard = async (cardIdentifierPrefix, minterName) => { +const fetchExistingARCard = async (cardIdentifierPrefix, minterName) => { try { const response = await searchSimple( 'BLOG_POST', @@ -381,7 +389,7 @@ const handleProposeDemotion = async (adminName, adminAddress) => { console.error("Error fetching existing AR card:", error) return null } - } +} const publishARCard = async (cardIdentifierPrefix) => { @@ -726,8 +734,8 @@ const fallbackMinterCheck = async (minterName, minterGroupMembers, minterAdmins) } -const createARCardHTML = async (cardData, pollResults, cardIdentifier, commentCount) => { - const { minterName, header, content, links, creator, timestamp, poll, promotionCard } = cardData +const createARCardHTML = async (cardData, pollResults, cardIdentifier, commentCount, cardUpdatedTime, bgColor, cardPublisherAddress, illegalDuplicate) => { + const { minterName, minterAddress='priorToAddition', header, content, links, creator, timestamp, poll, promotionCard } = cardData const formattedDate = new Date(timestamp).toLocaleString() const minterAvatar = await getMinterAvatar(minterName) const creatorAvatar = await getMinterAvatar(creator) @@ -744,7 +752,7 @@ const createARCardHTML = async (cardData, pollResults, cardIdentifier, commentCo // showPromotionCard = await fallbackMinterCheck(minterName, minterGroupMembers, minterAdmins) if (typeof promotionCard === 'boolean') { - showPromotionCard = promotionCard; + showPromotionCard = promotionCard } else if (typeof promotionCard === 'string') { // Could be "true" or "false" or something else const lower = promotionCard.trim().toLowerCase() @@ -790,41 +798,63 @@ const createARCardHTML = async (cardData, pollResults, cardIdentifier, commentCo let altText = '' const verifiedName = await validateMinterName(minterName) - if (verifiedName) { + if (verifiedName && !illegalDuplicate) { const accountInfo = await getNameInfo(verifiedName) const accountAddress = accountInfo.owner + const minterGroupAddresses = minterGroupMembers.map(m => m.member) + const adminAddresses = minterAdmins.map(m => m.member) + const existingAdmin = adminAddresses.includes(accountAddress) + const existingMinter = minterGroupAddresses.includes(accountAddress) console.log(`name is validated, utilizing for removal features...${verifiedName}`) const actionsHtmlCheck = await checkAndDisplayActions(adminYes, verifiedName, cardIdentifier) actionsHtml = actionsHtmlCheck - if (!addAdminTxs || !remAdminTxs) { - await fetchAllARTxData() - } + const { finalAddTxs, pendingAddTxs, finalRemTxs, pendingRemTxs } = await fetchAllARTxData() - if (addAdminTxs.some((addTx) => addTx.groupId === 694 && addTx.member === accountAddress)){ - console.warn(`account was already adminified(PROMOTED), displaying as such...`) + const confirmedAdd = finalAddTxs.some( + (tx) => tx.groupId === 694 && tx.member === accountAddress + ) + const userPendingAdd = pendingAddTxs.some( + (tx) => tx.groupId === 694 && tx.member === accountAddress + ) + const confirmedRemove = finalRemTxs.some( + (tx) => tx.groupId === 694 && tx.admin === accountAddress + ) + const userPendingRemove = pendingRemTxs.some( + (tx) => tx.groupId === 694 && tx.admin === accountAddress + ) + + // If user is definitely admin (finalAdd) and not pending removal + if (confirmedAdd && !userPendingRemove && existingAdmin) { + console.warn(`account was already admin, final. no add/remove pending.`); cardColorCode = 'rgb(3, 11, 24)' - altText = `

PROMOTED to ADMIN

` + altText = `

PROMOTED to ADMIN

`; actionsHtml = '' - // =============================================================== if 'showPromotedDemoted' is wanted to be added. - // if (!showPromotedDemoted){ - // console.warn(`promoted/demoted show checkbox is unchecked, and card is promoted, not displaying...`) - // return '' - // } + } + + if (confirmedAdd && userPendingRemove && existingAdmin) { + console.warn(`user is a previously approved an admin, but now has pending removals. Keeping html`) } - if (remAdminTxs.some((remTx) => remTx.groupId === 694 && remTx.admin === accountAddress)){ - console.warn(`account was already UNadminified(DEMOTED), displaying as such...`) + // If user has a final "remove" and no pending additions or removals + if (confirmedRemove && !userPendingAdd && existingMinter) { + console.warn(`account was demoted, final. no add pending, existingMinter.`); cardColorCode = 'rgb(29, 4, 6)' altText = `

DEMOTED from ADMIN

` actionsHtml = '' - - // if (!showPromotedDemoted) { - // console.warn(`promoted/demoted show checkbox is unchecked, card is demoted, not displaying...`) - // return '' - // } } + // If user has both final remove and pending add, do something else + if (confirmedRemove && userPendingAdd && existingMinter) { + console.warn(`account was previously demoted, but also a pending re-add, allowing actions to show...`) + // Possibly show "DEMOTED but re-add in progress" or something + } + + } else if ( verifiedName && illegalDuplicate) { + console.warn(`illegalDuplicate detected (this card was somehow allowed to be published twice, keeping newest as active to prevent issues with old cards and updates, but displaying without actions...)`) + cardColorCode = 'rgb(82, 81, 81)' + altText = `

DUPLICATE (diplayed for data only)

` + actionsHtml = '' } else { console.warn(`name could not be validated, not setting actionsHtml`) actionsHtml = '' diff --git a/assets/js/AdminBoard.js b/assets/js/AdminBoard.js index cc82ffa..375d83a 100644 --- a/assets/js/AdminBoard.js +++ b/assets/js/AdminBoard.js @@ -83,6 +83,13 @@ const loadAdminBoardPage = async () => { +
@@ -327,8 +334,20 @@ const fetchAllEncryptedCards = async (isRefresh = false) => { const encryptedCardsContainer = document.getElementById("encrypted-cards-container") encryptedCardsContainer.innerHTML = "

Loading cards...

" + let afterTime = null + const timeRangeSelect = document.getElementById("time-range-select") + if (timeRangeSelect) { + const days = parseInt(timeRangeSelect.value, 10) + if (days > 0) { + const now = Date.now() + const dayMs = 24 * 60 * 60 * 1000 + afterTime = now - days * dayMs // e.g. last X days + console.log(`afterTime for last ${days} days = ${new Date(afterTime).toLocaleString()}`) + } + } + try { - const response = await searchSimple('MAIL_PRIVATE', `${encryptedCardIdentifierPrefix}`, '', 0) + const response = await searchSimple('MAIL_PRIVATE', `${encryptedCardIdentifierPrefix}`, '', 0, 0, '', false, true, afterTime) if (!response || !Array.isArray(response) || response.length === 0) { encryptedCardsContainer.innerHTML = "

No cards found.

" @@ -379,12 +398,13 @@ const fetchAllEncryptedCards = async (isRefresh = false) => { const latestCardsMap = new Map() validCardsWithData.forEach(({ card, decryptedCardData }) => { - const timestamp = card.updated || card.created || 0 + const timestamp = card.created || 0 const existingCard = latestCardsMap.get(card.identifier) - if (!existingCard || timestamp > (existingCard.card.updated || existingCard.card.created || 0)) { + if (!existingCard || timestamp < (existingCard.card.updated || existingCard.card.created || 0)) { latestCardsMap.set(card.identifier, { card, decryptedCardData }) - } + } + }) const uniqueValidCards = Array.from(latestCardsMap.values()) @@ -396,13 +416,11 @@ const fetchAllEncryptedCards = async (isRefresh = false) => { const obtainedMinterName = decryptedCardData.minterName // Only check for cards that are NOT topic-based cards if ((!decryptedCardData.isTopic) || decryptedCardData.isTopic === 'false') { - const cardTimestamp = card.updated || card.created || 0 if (obtainedMinterName) { const existingEntry = mostRecentCardsMap.get(obtainedMinterName) - // Replace only if the current card is more recent - if (!existingEntry || cardTimestamp > (existingEntry.card.updated || existingEntry.card.created || 0)) { + if (!existingEntry) { mostRecentCardsMap.set(obtainedMinterName, { card, decryptedCardData }) } } @@ -414,7 +432,7 @@ const fetchAllEncryptedCards = async (isRefresh = false) => { }) // Convert the map into an array of final cards - const finalCards = Array.from(mostRecentCardsMap.values()); + const finalCards = Array.from(mostRecentCardsMap.values()) let selectedSort = 'newest' const sortSelect = document.getElementById('sort-select') @@ -1037,7 +1055,7 @@ const processQortalLinkForRendering = async (link) => { return link } -const checkAndDisplayRemoveActions = async (adminYes, name, cardIdentifier) => { +const checkAndDisplayRemoveActions = async (adminYes, name, cardIdentifier, nameIsActuallyAddress = false) => { const latestBlockInfo = await getLatestBlockInfo() const isBlockPassed = latestBlockInfo.height >= GROUP_APPROVAL_FEATURE_TRIGGER_HEIGHT let minAdminCount @@ -1052,10 +1070,15 @@ const checkAndDisplayRemoveActions = async (adminYes, name, cardIdentifier) => { minAdminCount = Math.round(fortyPercent) console.warn(`this is another check to ensure minterAdmin group has more than 1 admin. IF so we will calculate the 40% needed for GROUP_APPROVAL, that number is: ${minAdminCount}`) } - if (isBlockPassed && userState.isMinterAdmin) { + if (isBlockPassed && (userState.isMinterAdmin || userState.isAdmin)) { console.warn(`feature trigger has passed, checking for approval requirements`) - const addressInfo = await getNameInfo(name) - const address = addressInfo.owner + let address + if (!nameIsActuallyAddress){ + const nameInfo = await getNameInfo(name) + address = nameInfo.owner + } else { + address = name + } const kickApprovalHtml = await checkGroupApprovalAndCreateButton(address, cardIdentifier, "GROUP_KICK") const banApprovalHtml = await checkGroupApprovalAndCreateButton(address, cardIdentifier, "GROUP_BAN") @@ -1068,7 +1091,7 @@ const checkAndDisplayRemoveActions = async (adminYes, name, cardIdentifier) => { } } - if (adminYes >= minAdminCount && userState.isMinterAdmin) { + if (adminYes >= minAdminCount && (userState.isMinterAdmin || userState.isAdmin)) { const removeButtonHtml = createRemoveButtonHtml(name, cardIdentifier) return removeButtonHtml } else{ @@ -1098,6 +1121,8 @@ const createRemoveButtonHtml = (name, cardIdentifier) => { const handleKickMinter = async (minterName) => { try { + isAddress = await getAddressInfo(minterName) + // Optional block check let txGroupId = 0 // const { height: currentHeight } = await getLatestBlockInfo() @@ -1108,8 +1133,14 @@ const handleKickMinter = async (minterName) => { } // Get the minter address from name info - const minterNameInfo = await getNameInfo(minterName) - const minterAddress = minterNameInfo?.owner + let minterAddress + if (!isAddress){ + const minterNameInfo = await getNameInfo(minterName) + minterAddress = minterNameInfo?.owner + } else { + minterAddress = minterName + } + if (!minterAddress) { alert(`No valid address found for minter name: ${minterName}, this should NOT have happened, please report to developers...`) return @@ -1150,6 +1181,7 @@ const handleKickMinter = async (minterName) => { } const handleBanMinter = async (minterName) => { + isAddress = await getAddressInfo(minterName) try { let txGroupId = 0 // const { height: currentHeight } = await getLatestBlockInfo() @@ -1161,9 +1193,13 @@ const handleBanMinter = async (minterName) => { console.log(`featureTrigger block is passed, using txGroupId 694`) txGroupId = 694 } - - const minterNameInfo = await getNameInfo(minterName) - const minterAddress = minterNameInfo?.owner + let minterAddress + if (!isAddress) { + const minterNameInfo = await getNameInfo(minterName) + const minterAddress = minterNameInfo?.owner + } else { + minterAddress = minterName + } if (!minterAddress) { alert(`No valid address found for minter name: ${minterName}, this should NOT have happened, please report to developers...`) @@ -1236,7 +1272,7 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co const showKickedBanned = document.getElementById('admin-show-kicked-banned-checkbox')?.checked ?? false const showHiddenAdminCards = document.getElementById('admin-show-hidden-checkbox')?.checked ?? false - const isUndefinedUser = (minterName === 'undefined') + const isUndefinedUser = (minterName === 'undefined' || minterName === 'null') const hasTopicMode = Object.prototype.hasOwnProperty.call(cardData, 'topicMode') @@ -1254,7 +1290,7 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co let cardColorCode = showTopic ? '#0e1b15' : '#151f28' const minterOrTopicHtml = ((showTopic) || (isUndefinedUser)) ? ` -
REGARDING (Topic):
+
REGARDING (Topic / Address):

${minterName}` : `
REGARDING (Name):
@@ -1274,16 +1310,23 @@ const createEncryptedCardHTML = async (cardData, pollResults, cardIdentifier, co let adjustmentText = '' const verifiedName = await validateMinterName(minterName) let levelText = '

' + const addressVerification = await getAddressInfo(minterName) + const verifiedAddress = addressVerification.address - if (verifiedName) { - const accountInfo = await getNameInfo(verifiedName) - const accountAddress = accountInfo.owner - const addressInfo = await getAddressInfo(accountAddress) + if (verifiedName || verifiedAddress) { + let accountInfo + if (!verifiedAddress){ + accountInfo = await getNameInfo(verifiedName) + } + + const accountAddress = verifiedAddress ? addressVerification.address : accountInfo.owner + const addressInfo = verifiedAddress ? addressVerification : await getAddressInfo(accountAddress) + levelText = ` - Level ${addressInfo.level}` console.log(`name is validated, utilizing for removal features...${verifiedName}`) penaltyText = addressInfo.blocksMintedPenalty == 0 ? '' : '

(has Blocks Penalty)

' adjustmentText = addressInfo.blocksMintedAdjustment == 0 ? '' : '

(has Blocks Adjustment)

' - const removeActionsHtml = await checkAndDisplayRemoveActions(adminYes, verifiedName, cardIdentifier) + const removeActionsHtml = verifiedAddress ? await checkAndDisplayRemoveActions(adminYes, verifiedAddress, cardIdentifier) : await checkAndDisplayRemoveActions(adminYes, verifiedName, cardIdentifier) showRemoveHtml = removeActionsHtml if (userVote === 0) { cardColorCode = "rgba(1, 65, 39, 0.41)"; // or any green you want diff --git a/assets/js/AdminTools.js b/assets/js/AdminTools.js index f5c3907..0a0177e 100644 --- a/assets/js/AdminTools.js +++ b/assets/js/AdminTools.js @@ -28,10 +28,10 @@ async function loadMinterAdminToolsPage() { User Avatar ${userState.accountName || 'Guest'}

-

No Functionality Here Yet

+

COMING SOON...

-

This page is still under development. Until the final Mintership proposal modifications are made, and the MINTER group is transferred to null, there is no need for this page's functionality. The page will be updated when the final modifications are made.

-

This page until then is simply a placeholder.

+

This page will have functionality to assist the Minter Admins in performing their duties. It will display all pending transactions (of any kind they can approve/deny) along with that ability. It can also be utilized to obtain more in-depth information about existing accounts.

+

The page will be getting a significant overhaul in the near(ish) future, as the MINTER group is now owned by null, and we are past the 'temporary state' we were in for much longer than planned.

diff --git a/assets/js/MinterBoard.js b/assets/js/MinterBoard.js index 788b8b5..5e635d5 100644 --- a/assets/js/MinterBoard.js +++ b/assets/js/MinterBoard.js @@ -37,6 +37,13 @@ const loadMinterBoardPage = async () => { +
@@ -61,12 +61,12 @@ - Q-Mintership v1.02b
+ Q-Mintership v1.04b
-
FORUM
ADMIN TOOLSADMIN BOARDMINTER BOARDARA BOARD
+
FORUM
ADMIN TOOLSADMIN BOARDMINTER BOARDMAM Board
@@ -93,7 +93,7 @@
Mintership Forum
-

Minting Rights? - Start Here - MinterBoard

+

MinterBoard

@@ -109,7 +109,7 @@ Admin Board

- Promote / Demote Minter Admins

+ Minter Admin Management (MAM) Board
@@ -191,6 +191,42 @@
+
+
+
+
+

+ v1.04beta 01-27-2025

+
+
+
+
+

+ v1.04b Fixes- MANY fixes - See post in the FORUM for details, too many to list here. +

+
+
+
+
+ +
+
+
+
+

+ v1.03beta 01-23-2025

+
+
+
+
+

+ v1.03b Fixes- Filtering issue resolved - Version 1.02 had a filtering logic modification applied to add and remove admin transactions. However, it was not changed on the REMOVE filtering, so REMOVE transactions that were PENDING were showing as COMPLETE and thus the board was displaying cards as already removed when there was only a PENDING tx. This has been resolved in 1.03b. +

+
+
+
+
+
@@ -536,12 +572,12 @@
-

Q-Mintership (v1.02b)

+

Q-Mintership (v1.04b)

- +