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

feat: add comment-incentive command #840

Open
wants to merge 17 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/configs/ubiquibot-config-default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export const DefaultConfig: MergedConfig = {
name: "start",
enabled: false,
},
{
name: "incentivize",
enabled: false,
},
{
name: "stop",
enabled: false,
Expand Down
1 change: 1 addition & 0 deletions src/handlers/comment/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum IssueCommentCommands {
MULTIPLIER = "/multiplier", // set bounty multiplier (for treasury)
QUERY = "/query",
ASK = "/ask", // ask GPT a question
INCENTIVIZE = "/incentivize",
// Access Controls

ALLOW = "/allow",
Expand Down
22 changes: 22 additions & 0 deletions src/handlers/comment/handlers/incentivize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getBotContext, getLogger } from "../../../bindings";
import { Payload } from "../../../types";

export const incentivize = async (body: string) => {
const context = getBotContext();
const logger = getLogger();
const payload = context.payload as Payload;
const sender = payload.sender.login;

logger.info(`Received '/incentivize' command from user: ${sender}`);

if (!payload.issue) {
logger.info(`Skipping '/incentivize' because of no issue instance`);
return `Skipping '/incentivize' because of no issue instance`;
}
const toggle = body.match(/^\/incentivize @(\w+)/);
BeanieMen marked this conversation as resolved.
Show resolved Hide resolved
if (!toggle) {
return `invalid syntax for /incentivize \n usage /incentivize @user @user1... true|false \n ex /incentivize @user true`;
} else {
return;
}
};
9 changes: 9 additions & 0 deletions src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { approveLabelChange } from "./authorize";
import { setAccess } from "./allow";
import { ask } from "./ask";
import { multiplier } from "./multiplier";

import { BigNumber, ethers } from "ethers";
import { addPenalty } from "../../../adapters/supabase";
import {
Expand All @@ -33,6 +34,7 @@ import {
calculateIssueAssigneeReward,
calculatePullRequestReviewsReward,
} from "../../payout";
import { incentivize } from "./incentivize";
import { query } from "./query";
import { autoPay } from "./payout";
import { getTargetPriceLabel } from "../../shared";
Expand All @@ -48,6 +50,7 @@ export * from "./multiplier";
export * from "./query";
export * from "./ask";
export * from "./authorize";
export * from "./incentivize";

export interface RewardsResponse {
error: string | null;
Expand Down Expand Up @@ -263,6 +266,12 @@ export const userCommands = (): UserCommands[] => {
handler: unassign,
callback: commandCallback,
},
{
id: IssueCommentCommands.INCENTIVIZE,
description: "Enables or Disables comment incentive for a user",
handler: incentivize,
callback: commandCallback,
},
{
handler: listAvailableCommands,
id: IssueCommentCommands.HELP,
Expand Down
7 changes: 5 additions & 2 deletions src/handlers/payout/post.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getWalletAddress } from "../../adapters/supabase";
import { getBotContext, getLogger } from "../../bindings";
import { getAllIssueComments, getAllPullRequestReviews, getIssueDescription, parseComments } from "../../helpers";
import { getAllIssueComments, getAllPullRequestReviews, getIncentivizedUsers, getIssueDescription, parseComments } from "../../helpers";
import { getLatestPullRequest, gitLinkedPrParser } from "../../helpers/parser";
import { Incentives, MarkdownItem, Payload, UserType } from "../../types";
import { RewardsResponse, commentParser } from "../comment";
Expand Down Expand Up @@ -44,7 +44,7 @@ export const calculateIssueConversationReward = async (calculateIncentives: Ince
const issueCommentsByUser: Record<string, { id: number; comments: string[] }> = {};
for (const issueComment of issueComments) {
const user = issueComment.user;
if (user.type == UserType.Bot || user.login == assignee.login) continue;
if (user.type == UserType.Bot) continue;
const commands = commentParser(issueComment.body);
if (commands.length > 0) {
logger.info(`Skipping to parse the comment because it contains commands. comment: ${JSON.stringify(issueComment)}`);
Expand All @@ -68,8 +68,11 @@ export const calculateIssueConversationReward = async (calculateIncentives: Ince

// array of awaiting permits to generate
const reward: { account: string; priceInEth: Decimal; userId: number; user: string; penaltyAmount: BigNumber }[] = [];
const users = await getIncentivizedUsers(calculateIncentives.issue.number);
if (!users) return { error: "Error: Could not find any incentivized users" };

for (const user of Object.keys(issueCommentsByUser)) {
if (!users[user] === true) continue;
BeanieMen marked this conversation as resolved.
Show resolved Hide resolved
const commentsByUser = issueCommentsByUser[user];
const commentsByNode = await parseComments(commentsByUser.comments, ItemsToExclude);
const rewardValue = calculateRewardValue(commentsByNode, calculateIncentives.incentives);
Expand Down
26 changes: 26 additions & 0 deletions src/helpers/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ export const clearAllPriceLabelsOnIssue = async (): Promise<void> => {
}
};

export const getIncentivizedUsers = async (issue_number: number) => {
const comments = await getAllIssueComments(issue_number);
const incentiveComments = comments.filter((comment) => comment.body.startsWith("/comment-incentives"));
const users: { [key: string]: boolean } = {};
for (const incentiveComment of incentiveComments) {
const parts = incentiveComment.body.split(" ");
parts.shift();
const toggle: RegExpMatchArray | null = incentiveComment.body.match(/\b(true|false)\b/);

if (!toggle) {
BeanieMen marked this conversation as resolved.
Show resolved Hide resolved
for (const part of parts) {
if (part.startsWith("@")) {
users[part.substring(1)] = false;
}
}
} else {
for (const part of parts) {
if (part.startsWith("@")) {
users[part.substring(1)] = toggle[0] === "true";
}
}
}
}
return users;
};

export const addLabelToIssue = async (labelName: string) => {
const context = getBotContext();
const logger = getLogger();
Expand Down