Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #848 from devpanther/debug-comment-incentive
Browse files Browse the repository at this point in the history
  • Loading branch information
0x4007 authored Sep 30, 2023
2 parents c6f79f5 + 970f478 commit 062dee5
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface RewardsResponse {
penaltyAmount: BigNumber;
user: string;
userId: number;
debug: Record<string, { count: number; reward: Decimal }>;
}[];
fallbackReward?: Record<string, Decimal>;
}
Expand Down
8 changes: 7 additions & 1 deletion src/handlers/payout/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface RewardByUser {
type: (string | undefined)[];
user: string | undefined;
priceArray: string[];
debug: Record<string, { count: number; reward: Decimal }>;
}

/**
Expand Down Expand Up @@ -324,6 +325,7 @@ export const calculateIssueAssigneeReward = async (incentivesCalculation: Incent
account: account || "0x",
user: "",
userId: incentivesCalculation.assignee.id,
debug: {},
},
],
};
Expand Down Expand Up @@ -369,6 +371,7 @@ export const handleIssueClosed = async (
type: [conversationRewards.title],
user: permit.user,
priceArray: [permit.priceInEth.toString()],
debug: permit.debug,
});
}
});
Expand All @@ -387,6 +390,7 @@ export const handleIssueClosed = async (
type: [pullRequestReviewersReward.title],
user: permit.user,
priceArray: [permit.priceInEth.toString()],
debug: permit.debug,
});
}
});
Expand All @@ -403,6 +407,7 @@ export const handleIssueClosed = async (
type: [creatorReward.title],
user: creatorReward.username,
priceArray: [creatorReward.reward[0].priceInEth.toString()],
debug: creatorReward.reward[0].debug,
});
} else if (creatorReward && creatorReward.reward && creatorReward.reward[0].account === "0x") {
logger.info(`Skipping to generate a permit url for missing account. fallback: ${creatorReward.fallbackReward}`);
Expand All @@ -424,6 +429,7 @@ export const handleIssueClosed = async (
type: title,
user: assigneeReward.username,
priceArray: [assigneeReward.reward[0].priceInEth.toString()],
debug: assigneeReward.reward[0].debug,
});

if (permitComments.length > 0) {
Expand Down Expand Up @@ -497,7 +503,7 @@ export const handleIssueClosed = async (

const price = `${reward.priceInEth} ${incentivesCalculation.tokenSymbol.toUpperCase()}`;

const comment = createDetailsTable(price, payoutUrl, reward.user, detailsValue);
const comment = createDetailsTable(price, payoutUrl, reward.user, detailsValue, reward.debug);

await savePermitToDB(Number(reward.userId), txData);
permitComment += comment;
Expand Down
67 changes: 51 additions & 16 deletions src/handlers/payout/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,32 @@ export const calculateIssueConversationReward = async (calculateIncentives: Ince
const fallbackReward: Record<string, Decimal> = {};

// array of awaiting permits to generate
const reward: { account: string; priceInEth: Decimal; userId: number; user: string; penaltyAmount: BigNumber }[] = [];
const reward: {
account: string;
priceInEth: Decimal;
userId: number;
user: string;
penaltyAmount: BigNumber;
debug: Record<string, { count: number; reward: Decimal }>;
}[] = [];

for (const user of Object.keys(issueCommentsByUser)) {
const commentsByUser = issueCommentsByUser[user];
const commentsByNode = await parseComments(commentsByUser.comments, ItemsToExclude);
const rewardValue = calculateRewardValue(commentsByNode, calculateIncentives.incentives);
if (rewardValue.equals(0)) {
if (rewardValue.sum.equals(0)) {
logger.info(`Skipping to generate a permit url because the reward value is 0. user: ${user}`);
continue;
}
logger.debug(`Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue}`);
logger.debug(`Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue.sum}`);
const account = await getWalletAddress(user);
const priceInEth = rewardValue.mul(calculateIncentives.baseMultiplier);
const priceInEth = rewardValue.sum.mul(calculateIncentives.baseMultiplier);
if (priceInEth.gt(calculateIncentives.paymentPermitMaxPrice)) {
logger.info(`Skipping comment reward for user ${user} because reward is higher than payment permit max price`);
continue;
}
if (account) {
reward.push({ account, priceInEth, userId: commentsByUser.id, user, penaltyAmount: BigNumber.from(0) });
reward.push({ account, priceInEth, userId: commentsByUser.id, user, penaltyAmount: BigNumber.from(0), debug: rewardValue.sumByType });
} else {
fallbackReward[user] = priceInEth;
}
Expand Down Expand Up @@ -147,6 +154,7 @@ export const calculateIssueCreatorReward = async (incentivesCalculation: Incenti
userId: creator.id,
user: "",
penaltyAmount: BigNumber.from(0),
debug: {},
},
],
};
Expand Down Expand Up @@ -212,7 +220,14 @@ export const calculatePullRequestReviewsReward = async (incentivesCalculation: I
logger.info(`calculatePullRequestReviewsReward: Filtering by the user type done. commentsByUser: ${JSON.stringify(prReviewsByUser)}`);

// array of awaiting permits to generate
const reward: { account: string; priceInEth: Decimal; userId: number; user: string; penaltyAmount: BigNumber }[] = [];
const reward: {
account: string;
priceInEth: Decimal;
userId: number;
user: string;
penaltyAmount: BigNumber;
debug: Record<string, { count: number; reward: Decimal }>;
}[] = [];

// The mapping between gh handle and amount in ETH
const fallbackReward: Record<string, Decimal> = {};
Expand All @@ -221,20 +236,22 @@ export const calculatePullRequestReviewsReward = async (incentivesCalculation: I
const commentByUser = prReviewsByUser[user];
const commentsByNode = await parseComments(commentByUser.comments, ItemsToExclude);
const rewardValue = calculateRewardValue(commentsByNode, incentivesCalculation.incentives);
if (rewardValue.equals(0)) {
if (rewardValue.sum.equals(0)) {
logger.info(`calculatePullRequestReviewsReward: Skipping to generate a permit url because the reward value is 0. user: ${user}`);
continue;
}
logger.info(`calculatePullRequestReviewsReward: Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue}`);
logger.info(
`calculatePullRequestReviewsReward: Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue.sum}`
);
const account = await getWalletAddress(user);
const priceInEth = rewardValue.mul(incentivesCalculation.baseMultiplier);
const priceInEth = rewardValue.sum.mul(incentivesCalculation.baseMultiplier);
if (priceInEth.gt(incentivesCalculation.paymentPermitMaxPrice)) {
logger.info(`calculatePullRequestReviewsReward: Skipping comment reward for user ${user} because reward is higher than payment permit max price`);
continue;
}

if (account) {
reward.push({ account, priceInEth, userId: commentByUser.id, user, penaltyAmount: BigNumber.from(0) });
reward.push({ account, priceInEth, userId: commentByUser.id, user, penaltyAmount: BigNumber.from(0), debug: rewardValue.sumByType });
} else {
fallbackReward[user] = priceInEth;
}
Expand All @@ -256,13 +273,13 @@ const generatePermitForComments = async (
const logger = getLogger();
const commentsByNode = await parseComments(comments, ItemsToExclude);
const rewardValue = calculateRewardValue(commentsByNode, incentives);
if (rewardValue.equals(0)) {
if (rewardValue.sum.equals(0)) {
logger.info(`No reward for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue}`);
return;
}
logger.debug(`Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue}`);
logger.debug(`Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue.sum}`);
const account = await getWalletAddress(user);
const amountInETH = rewardValue.mul(multiplier);
const amountInETH = rewardValue.sum.mul(multiplier);
if (amountInETH.gt(paymentPermitMaxPrice)) {
logger.info(`Skipping issue creator reward for user ${user} because reward is higher than payment permit max price`);
return;
Expand All @@ -280,28 +297,46 @@ const generatePermitForComments = async (
* @param incentives - The basic price table for reward calculation
* @returns - The reward value
*/
const calculateRewardValue = (comments: Record<string, string[]>, incentives: Incentives): Decimal => {
const calculateRewardValue = (
comments: Record<string, string[]>,
incentives: Incentives
): { sum: Decimal; sumByType: Record<string, { count: number; reward: Decimal }> } => {
let sum = new Decimal(0);
const sumByType: Record<string, { count: number; reward: Decimal }> = {};

for (const key of Object.keys(comments)) {
const value = comments[key];

// Initialize the sum for this key if it doesn't exist
if (!sumByType[key]) {
sumByType[key] = {
count: 0,
reward: new Decimal(0),
};
}

// if it's a text node calculate word count and multiply with the reward value
if (key == "#text") {
if (!incentives.comment.totals.word) {
continue;
}
const wordReward = new Decimal(incentives.comment.totals.word);
const reward = wordReward.mul(value.map((str) => str.trim().split(" ").length).reduce((totalWords, wordCount) => totalWords + wordCount, 0));
const wordCount = value.map((str) => str.trim().split(" ").length).reduce((totalWords, wordCount) => totalWords + wordCount, 0);
const reward = wordReward.mul(wordCount);
sumByType[key].count += wordCount;
sumByType[key].reward = wordReward;
sum = sum.add(reward);
} else {
if (!incentives.comment.elements[key]) {
continue;
}
const rewardValue = new Decimal(incentives.comment.elements[key]);
const reward = rewardValue.mul(value.length);
sumByType[key].count += value.length;
sumByType[key].reward = rewardValue;
sum = sum.add(reward);
}
}

return sum;
return { sum, sumByType };
};
57 changes: 55 additions & 2 deletions src/helpers/comment.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Decimal from "decimal.js";
import { isEmpty } from "lodash";
import * as parse5 from "parse5";

type Node = {
Expand Down Expand Up @@ -41,12 +43,46 @@ export const parseComments = (comments: string[], itemsToExclude: string[]): Rec
return result;
};

export const generateCollapsibleTable = (data: { element: string; units: number; reward: Decimal }[]) => {
// Check if the data array is empty
if (data.length === 0) {
return "No data to display.";
}

// Create the table header row
const headerRow = "| element | units | reward |\n| --- | --- | --- |";

// Create the table rows from the data array
const tableRows = data.map((item) => `| ${item.element} | ${item.units} | ${item.reward} |`).join("\n");

// Create the complete Markdown table
const tableMarkdown = `
<details>
<summary>Details</summary>
${headerRow}
${tableRows}
</details>
`;

return tableMarkdown;
};

export const createDetailsTable = (
amount: string,
paymentURL: string,
username: string,
values: { title: string; subtitle: string; value: string }[]
values: { title: string; subtitle: string; value: string }[],
debug: Record<
string,
{
count: number;
reward: Decimal;
}
>
): string => {
let collapsibleTable = null;
// Generate the table rows based on the values array
const tableRows = values
.map(({ title, value, subtitle }) => {
Expand All @@ -61,6 +97,19 @@ export const createDetailsTable = (
})
.join("");

if (!isEmpty(debug)) {
const data = Object.entries(debug)
.filter(([_, value]) => value.count > 0)
.map(([key, value]) => {
const element = key === "#text" ? "words" : key;
const units = value.count;
const reward = value.reward;
return { element, units, reward };
});

collapsibleTable = generateCollapsibleTable(data);
}

// Construct the complete HTML structure
const html = `
<details>
Expand All @@ -77,11 +126,15 @@ export const createDetailsTable = (
${tableRows}
</tbody>
</table>
${collapsibleTable ? "COLLAPSIBLE_TABLE_PLACEHOLDER" : ""}
</details>
`;

// Remove spaces and line breaks from the HTML, ignoring the attributes like <a href="..."> and [ ... ]
const cleanedHtml = html.replace(/>\s+</g, "><").replace(/[\r\n]+/g, "");

return cleanedHtml;
// Add collapsible table here to avoid compression
const finalHtml = cleanedHtml.replace("COLLAPSIBLE_TABLE_PLACEHOLDER", collapsibleTable || "");

return finalHtml;
};

0 comments on commit 062dee5

Please sign in to comment.