Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decrease rep with user mention #93

Merged
merged 2 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
104 changes: 104 additions & 0 deletions src/bots/Reputation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,78 @@ describe('ReputationBot', () => {
assertBotSaid(messages, /.*?/);
await assert(triggerMessage);
});

// Testing when user is mention
it('when user mentions another user with "boo"', async () => {
await createUserInDb();
const triggerMessage = createTgTextMessage('@omar_alfaruq boo', {
chat: thisChat,
from: senderUser,
entities: [
{
type: 'mention',
offset: 0,
length: 13,
},
],
});

const messages = await runBot([ScriberBot, ReputationBot], ({ sendMessage }) => {
sendMessage(mainMessage);
sendMessage(triggerMessage);
});

assertBotSaid(messages, /decreased reputation/);
await assert({
...triggerMessage,
reply_to_message: {
from: {
id: 2,
username: 'omar_alfaruq',
},
},
});
});

// Testing when user is mention (text_mention -> when user has no username)
// https://core.telegram.org/bots/api#messageentity
it('when user mentions another user with "boo"', async () => {
await createUserInDb();
const triggerMessage = createTgTextMessage('@omar_alfaruq boo', {
chat: thisChat,
from: senderUser,
entities: [
{
type: 'text_mention',
offset: 0,
length: 13,
user: {
id: 2,
is_bot: false,
first_name: 'Omar',
last_name: 'Al-Faruq',
username: 'omar_alfaruq',
},
},
],
});

const messages = await runBot([ScriberBot, ReputationBot], ({ sendMessage }) => {
sendMessage(mainMessage);
sendMessage(triggerMessage);
});

assertBotSaid(messages, /decreased reputation/);
await assert({
...triggerMessage,
reply_to_message: {
from: {
id: 2,
username: 'omar_alfaruq',
},
},
});
});
});

describe('does not change reputation', () => {
Expand Down Expand Up @@ -809,6 +881,38 @@ describe('ReputationBot', () => {
assertBotSaid(messages, 'Tag only one user at a time to increase rep!');
await assert(0);
});

it('when user mentions multiple users with "boo"', async () => {
const mainMessage = createTgTextMessage('Is it your new PC?', {
chat: thisChat,
from: recipientUser,
reply_to_message: undefined,
});
const triggerMessage = createTgTextMessage('@omar_alfaruq @abu_bakr boo', {
chat: thisChat,
from: senderUser,
entities: [
{
type: 'mention',
offset: 0,
length: 13,
},
{
type: 'mention',
offset: 0,
length: 9,
},
],
});

const messages = await runBot([ScriberBot, ReputationBot], ({ sendMessage }) => {
sendMessage(mainMessage);
sendMessage(triggerMessage);
});

assertBotSaid(messages, 'Tag only one user at a time to increase rep!');
await assert(0);
});
});
});

Expand Down
99 changes: 66 additions & 33 deletions src/bots/Reputation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { MsocietyBotContext } from '../context';

const bot = new Composer<MsocietyBotContext>();

async function vote(ctx: MsocietyBotContext, sender: TelegramUser, recipient: TelegramUser) {
async function upvote(ctx: MsocietyBotContext, sender: TelegramUser, recipient: TelegramUser) {
const canVote = await Reputation.isAllowedToVote(ctx.entityManager, sender);

// Can't vote for yourself :)
Expand Down Expand Up @@ -49,11 +49,45 @@ async function vote(ctx: MsocietyBotContext, sender: TelegramUser, recipient: Te
}
}

async function downvote(ctx: MsocietyBotContext, sender: TelegramUser, recipient: TelegramUser) {
const canVote = await Reputation.isAllowedToVote(ctx.entityManager, sender);

// Can't vote for yourself :)
if (recipient.id === sender.id) {
await ctx.replyWithMarkdown('Are you _ok_?', { reply_to_message_id: ctx.message.message_id });
}
// Can't vote for the bot.
else if (recipient.id === ctx.botInfo.id) {
// eslint-disable-next-line quotes
await ctx.reply('🙂 Excuse me?', {
reply_to_message_id: ctx.message.message_id,
});
}
// Does user have enough votes in their quota to give out?
else if (!canVote) {
const { nextVote } = await Reputation.getVoteQuota(ctx.entityManager, ctx.message.from);

await ctx.replyWithMarkdown(
`You have already used up your vote quota of ${voteQuota} for the past ${voteQuotaDuration} hours. Please try again later!\nYou will receive a new vote in *${nextVote.hours} hours* and *${nextVote.minutes} minutes*`,
{ reply_to_message_id: ctx.message.message_id },
);
}
// Can't vote for bots
else if (!recipient.is_bot && canVote) {
await insertReputation(ctx.entityManager, sender, recipient, ctx.chat, ctx.message, defaultVoteValue * -1);
const senderRep = await Reputation.getLocalReputation(ctx.entityManager, sender, ctx.chat);
const recipientRep = await Reputation.getLocalReputation(ctx.entityManager, recipient, ctx.chat);
await ctx.replyWithMarkdown(
`*${sender.first_name}* (${senderRep}) has decreased reputation of *${recipient.first_name}* (${recipientRep})`,
{ reply_to_message_id: ctx.message.message_id },
);
}
}
bot.hears(/thank you|thanks|👍|💯|👆|🆙|🔥/i, async ctx => {
const mentionEntities =
ctx.message?.entities?.filter(entity => ['mention', 'text_mention'].includes(entity.type)) || [];
if (ctx.message.reply_to_message !== undefined) {
await vote(ctx, ctx.from, ctx.message.reply_to_message.from);
await upvote(ctx, ctx.from, ctx.message.reply_to_message.from);
} else if (
// check if there is a mention
mentionEntities.length
Expand All @@ -80,48 +114,47 @@ bot.hears(/thank you|thanks|👍|💯|👆|🆙|🔥/i, async ctx => {
return;
}
const recipient = await ctx.getChatMember(+recipientId);
await vote(ctx, ctx.message.from, recipient.user);
await upvote(ctx, ctx.message.from, recipient.user);
} else if (entity.type === 'text_mention') {
await vote(ctx, ctx.message.from, entity.user);
await upvote(ctx, ctx.message.from, entity.user);
}
}
});

bot.hears(/👎|👇|🔽|\bboo(o*)\b|\beww(w*)\b/i, async ctx => {
const mentionEntities =
ctx.message?.entities?.filter(entity => ['mention', 'text_mention'].includes(entity.type)) || [];
if (ctx.message.reply_to_message !== undefined) {
const sender = ctx.message.from;
const recipient = ctx.message.reply_to_message.from;
const canVote = await Reputation.isAllowedToVote(ctx.entityManager, sender);

// Can't vote for yourself :)
if (recipient.id === sender.id) {
await ctx.replyWithMarkdown('Are you _ok_?', { reply_to_message_id: ctx.message.message_id });
}
// Can't vote for the bot.
else if (recipient.id === ctx.botInfo.id) {
// eslint-disable-next-line quotes
await ctx.reply('🙂 Excuse me?', {
await downvote(ctx, ctx.from, ctx.message.reply_to_message.from);
} else if (
// check if there is a mention
mentionEntities.length
) {
if (mentionEntities.length > 1) {
await ctx.reply('Tag only one user at a time to increase rep!', {
reply_to_message_id: ctx.message.message_id,
});
return;
}
// Does user have enough votes in their quota to give out?
else if (!canVote) {
const { nextVote } = await Reputation.getVoteQuota(ctx.entityManager, ctx.message.from);
// get the mention metadata
const entity = mentionEntities[0];

await ctx.replyWithMarkdown(
`You have already used up your vote quota of ${voteQuota} for the past ${voteQuotaDuration} hours. Please try again later!\nYou will receive a new vote in *${nextVote.hours} hours* and *${nextVote.minutes} minutes*`,
{ reply_to_message_id: ctx.message.message_id },
);
}
// Can't vote for bots
else if (!recipient.is_bot && canVote) {
await insertReputation(ctx.entityManager, sender, recipient, ctx.chat, ctx.message, defaultVoteValue * -1);
const senderRep = await Reputation.getLocalReputation(ctx.entityManager, sender, ctx.chat);
const recipientRep = await Reputation.getLocalReputation(ctx.entityManager, recipient, ctx.chat);
await ctx.replyWithMarkdown(
`*${sender.first_name}* (${senderRep}) has decreased reputation of *${recipient.first_name}* (${recipientRep})`,
{ reply_to_message_id: ctx.message.message_id },
);
if (entity.type === 'mention') {
//get username from text using metadata
const username = ctx.message.text.substr(entity.offset + 1, entity.length - 1);
// telegram api doesn't provide resolving user by username so we depend on our db to get userID
const recipientId = (await User.getUserByUsername(ctx.entityManager, username))?.id;
if (!recipientId) {
// eslint-disable-next-line quotes
await ctx.reply("Can't find user in DB. Did they change their username?", {
reply_to_message_id: ctx.message.message_id,
});
return;
}
const recipient = await ctx.getChatMember(+recipientId);
await downvote(ctx, ctx.message.from, recipient.user);
} else if (entity.type === 'text_mention') {
await downvote(ctx, ctx.message.from, entity.user);
}
}
});
Expand Down