2
0
mirror of https://github.com/thedevs-network/the-guard-bot synced 2025-08-29 13:17:56 +00:00

Add /permit, closes #72

This commit is contained in:
Wojciech Pawlik 2020-06-29 15:07:12 +02:00
parent e54719ad11
commit 8fcfea6bb9
No known key found for this signature in database
GPG Key ID: 7D763FCB7B36ADB5
7 changed files with 92 additions and 7 deletions

View File

@ -56,6 +56,7 @@ Command | Role | Available at | Description
`/warn <reason>` | _Admin_ | _Groups_ | Warns the user.
`/unwarn` | _Admin_ | _Everywhere_ | Removes the last warn from the user.
`/nowarns` | _Admin_ | _Everywhere_ | Clears warns for the user.
`/permit` | _Admin_ | _Everywhere_ | Permits the user to advertise once, within 24 hours.
`/ban <reason>` | _Admin_ | _Groups_ | Bans the user from groups.
`/unban` | _Admin_ | _Everywhere_ | Removes the user from ban list.
`/user` | _Admin_ | _Everywhere_ | Shows the status of the user.

View File

@ -25,6 +25,7 @@ const adminCommands = `\
<code>/warn &lt;reason&gt;</code> - Warns the user.
<code>/unwarn</code> - Removes the last warn from the user.
<code>/nowarns</code> - Clears warns for the user.
<code>/permit</code> - Permits the user to advertise once, within 24 hours.
<code>/ban &lt;reason&gt;</code> - Bans the user from groups.
<code>/unban</code> - Removes the user from ban list.
<code>/user</code> - Shows user's status and warns.

View File

@ -0,0 +1,26 @@
import { displayUser, scheduleDeletion } from "../../utils/tg";
import { html, lrm } from "../../utils/html";
import { parse, strip } from "../../utils/cmd";
import type { ExtendedContext } from "../../typings/context";
import { permit } from "../../stores/user";
export = async (ctx: ExtendedContext) => {
if (ctx.from?.status !== "admin") return null;
const { targets } = parse(ctx.message);
if (targets.length !== 1) {
return ctx
.replyWithHTML(" <b>Specify one user to permit.</b>")
.then(scheduleDeletion());
}
const permitted = await permit(strip(targets[0]), {
by_id: ctx.from.id,
date: new Date(),
});
return ctx.replyWithHTML(html`
🎟 ${lrm}${ctx.from.first_name} <b>permitted</b> ${displayUser(permitted)} to
promote once within the next 24 hours!
`);
};

View File

@ -9,7 +9,7 @@ const { isMaster, isWarnNotExpired } = require('../../utils/config');
const { parse, strip } = require('../../utils/cmd');
// DB
const { getUser } = require('../../stores/user');
const { getUser, permit } = require('../../stores/user');
/** @param {Date} date */
const formatDate = date =>
@ -100,9 +100,19 @@ const getWarnsHandler = async ({ from, message, replyWithHTML }) => {
formatDate(theUser.createdAt),
);
return replyWithHTML(TgHtml.join('\n\n', [
const permitS = permit.isValid(theUser.permit)
// eslint-disable-next-line max-len
? `🎟 ${(await getUser({ id: theUser.permit.by_id })).first_name}, ${formatDate(theUser.permit.date)}`
: '';
const oneliners = TgHtml.join('\n', [
header,
firstSeen,
permitS,
].filter(isNotEmpty));
return replyWithHTML(TgHtml.join('\n\n', [
oneliners,
userWarns,
banReason,
].filter(isNotEmpty))).then(scheduleDeletion());

View File

@ -1,10 +1,11 @@
/* eslint new-cap: ["error", {"capIsNewExceptionPattern": "^(?:Action|jspack)\."}] */
import * as R from "ramda";
import { html, lrm } from "../../utils/html";
import { isAdmin, permit } from "../../stores/user";
import { config } from "../../utils/config";
import type { ExtendedContext } from "../../typings/context";
import fetch from "node-fetch";
import { isAdmin } from "../../stores/user";
import { jspack } from "jspack";
import { managesGroup } from "../../stores/group";
import type { MessageEntity } from "telegraf/typings/telegram-types";
@ -223,6 +224,13 @@ export = async (ctx: ExtendedContext, next) => {
if (userToWarn.id === 777000) return next();
if (await isAdmin(userToWarn)) return next();
if (await permit.revoke(userToWarn)) {
await ctx.replyWithHTML(html`
${lrm}${userToWarn.first_name} used 🎟 permit!
`);
return next();
}
ctx.deleteMessage().catch(() => null);
return ctx.warn({
admin: ctx.botInfo!,

View File

@ -3,11 +3,12 @@
const R = require('ramda');
const { optional, passThru } = require('telegraf');
const { permit } = require('../../stores/user');
const { html, lrm } = require('../../utils/html');
const { excludeLinks = [] } = require('../../utils/config').config;
if (excludeLinks === false || excludeLinks === '*') {
/** @type { import('../../typings/context').GuardMiddlewareFn } */
module.exports = passThru();
return;
}
@ -46,7 +47,12 @@ const pred = R.allPass([
]);
/** @param { import('../../typings/context').ExtendedContext } ctx */
const handler = ctx => {
const handler = async (ctx, next) => {
if (await permit.revoke(ctx.from)) {
await ctx.replyWithHTML(html`${lrm}${ctx.from.first_name} used 🎟 permit!`);
return next();
}
ctx.deleteMessage().catch(() => null);
return ctx.warn({
admin: ctx.botInfo,

View File

@ -1,9 +1,15 @@
'use strict';
/**
* @typedef { { id: number } | { username: string } } UserQuery
* @exports UserQuery
*/
// Utils
const { strip } = require('../utils/cmd');
const Datastore = require('nedb-promise');
const ms = require('millisecond');
const R = require('ramda');
const User = new Datastore({
@ -117,10 +123,36 @@ const unban = ({ id }) =>
},
);
/**
* @param {UserQuery} user
*/
const permit = (user, { by_id, date }) =>
User.update(
user,
{ $set: { permit: { by_id, date } } },
{ returnUpdatedDocs: true },
).then(getUpdatedDocument);
/**
* @param {UserQuery} user
*/
permit.revoke = (user) =>
User.update(
{ permit: { $exists: true }, ...strip(user) },
{ $unset: { permit: true } },
{ returnUpdatedDocs: true },
).then(getUpdatedDocument);
permit.isValid = (p) => Date.now() - ms('24h') < p?.date;
const warn = ({ id }, reason, { amend }) =>
User.update(
{ id, $not: { status: 'admin' } },
{ $pop: { warns: +!!amend }, $push: { warns: reason } },
{
$pop: { warns: +!!amend },
$push: { warns: reason },
$unset: { permit: true },
},
{ returnUpdatedDocs: true },
).then(getUpdatedDocument);
@ -145,6 +177,7 @@ module.exports = {
getUser,
isAdmin,
nowarns,
permit,
unadmin,
unban,
unwarn,