feat: telegram bot global push (#269)

This commit is contained in:
Dream Hunter
2024-05-25 14:07:00 +08:00
committed by GitHub
parent 9414f7a977
commit bf3c372d8c
24 changed files with 232 additions and 147 deletions

View File

@@ -1,21 +1,27 @@
import { Context } from 'hono';
import { CONSTANTS } from '../constants';
import { getJsonSetting, saveSetting, checkUserPassword, getDomains } from '../utils';
import { UserSettings, GeoData, UserInfo } from "../models";
import { handleListQuery } from '../common'
import { HonoCustomType } from '../types';
export default {
getSetting: async (c) => {
getSetting: async (c: Context<HonoCustomType>) => {
const value = await getJsonSetting(c, CONSTANTS.USER_SETTINGS_KEY);
const settings = new UserSettings(value);
return c.json(settings)
},
saveSetting: async (c) => {
saveSetting: async (c: Context<HonoCustomType>) => {
const value = await c.req.json();
const settings = new UserSettings(value);
if (settings.enableMailVerify && !c.env.KV) {
return c.text("Please enable KV first if you want to enable mail verify", 403)
}
if (settings.enableMailVerify) {
if (settings.enableMailVerify && !settings.verifyMailSender) {
return c.text("Please provide verifyMailSender", 400)
}
if (settings.enableMailVerify && settings.verifyMailSender) {
const mailDomain = settings.verifyMailSender.split("@")[1];
const domains = getDomains(c);
if (!domains.includes(mailDomain)) {
@@ -28,7 +34,7 @@ export default {
await saveSetting(c, CONSTANTS.USER_SETTINGS_KEY, JSON.stringify(settings));
return c.json({ success: true })
},
getUsers: async (c) => {
getUsers: async (c: Context<HonoCustomType>) => {
const { limit, offset, query } = c.req.query();
if (query) {
return await handleListQuery(c,
@@ -48,15 +54,15 @@ export default {
[], limit, offset
);
},
createUser: async (c) => {
createUser: async (c: Context<HonoCustomType>) => {
const { email, password } = await c.req.json();
if (!email || !password) {
return c.text("Invalid email or password", 400)
}
// geo data
const reqIp = c.req.raw.headers.get("cf-connecting-ip")
const geoData = new GeoData(reqIp, c.req.raw.cf);
const userInfo = new UserInfo(geoData);
const geoData = new GeoData(reqIp, c.req.raw.cf as any);
const userInfo = new UserInfo(geoData, email);
try {
checkUserPassword(password);
const { success } = await c.env.DB.prepare(
@@ -69,14 +75,15 @@ export default {
return c.text("Failed to register", 500)
}
} catch (e) {
if (e.message && e.message.includes("UNIQUE")) {
const errorMsg = (e as Error).message;
if (errorMsg && errorMsg.includes("UNIQUE")) {
return c.text("User already exists", 400)
}
return c.text(`Failed to register: ${e.message}`, 500)
return c.text(`Failed to register: ${errorMsg}`, 500)
}
return c.json({ success: true })
},
deleteUser: async (c) => {
deleteUser: async (c: Context<HonoCustomType>) => {
const { user_id } = c.req.param();
if (!user_id) return c.text("Invalid user_id", 400);
const { success } = await c.env.DB.prepare(
@@ -90,7 +97,7 @@ export default {
}
return c.json({ success: true })
},
resetPassword: async (c) => {
resetPassword: async (c: Context<HonoCustomType>) => {
const { user_id } = c.req.param();
const { password } = await c.req.json();
if (!user_id) return c.text("Invalid user_id", 400);
@@ -103,7 +110,7 @@ export default {
return c.text("Failed to reset password", 500)
}
} catch (e) {
return c.text(`Failed to reset password: ${e.message}`, 500)
return c.text(`Failed to reset password: ${(e as Error).message}`, 500)
}
return c.json({ success: true });
},

View File

@@ -1,25 +1,28 @@
import { Context } from 'hono';
import { cleanup } from '../common';
import { CONSTANTS } from '../constants';
import { getJsonSetting, saveSetting } from '../utils';
import { CleanupSettings } from '../models';
import { HonoCustomType } from '../types';
export default {
cleanup: async (c) => {
cleanup: async (c: Context<HonoCustomType>) => {
const { cleanType, cleanDays } = await c.req.json();
try {
await cleanup(c, cleanType, cleanDays);
} catch (error) {
console.error(error);
return c.text(`Failed to cleanup ${error.message}`, 500)
return c.text(`Failed to cleanup ${(error as Error).message}`, 500)
}
return c.json({ success: true })
},
getCleanup: async (c) => {
getCleanup: async (c: Context<HonoCustomType>) => {
const value = await getJsonSetting(c, CONSTANTS.AUTO_CLEANUP_KEY);
const cleanupSetting = new CleanupSettings(value);
return c.json(cleanupSetting)
},
saveCleanup: async (c) => {
saveCleanup: async (c: Context<HonoCustomType>) => {
const value = await c.req.json();
const cleanupSetting = new CleanupSettings(value);
await saveSetting(c, CONSTANTS.AUTO_CLEANUP_KEY, JSON.stringify(cleanupSetting));

View File

@@ -1,5 +1,7 @@
import { Hono } from 'hono'
import { Jwt } from 'hono/utils/jwt'
import { HonoCustomType } from '../types'
import { sendAdminInternalMail, getJsonSetting, saveSetting } from '../utils'
import { newAddress, handleListQuery } from '../common'
import { CONSTANTS } from '../constants'
@@ -7,7 +9,7 @@ import cleanup_api from './cleanup_api'
import admin_user_api from './admin_user_api'
import webhook_settings from './webhook_settings'
const api = new Hono()
export const api = new Hono<HonoCustomType>()
api.get('/admin/address', async (c) => {
const { limit, offset, query } = c.req.query();
@@ -41,7 +43,7 @@ api.post('/admin/new_address', async (c) => {
const res = await newAddress(c, name, domain, enablePrefix);
return c.json(res);
} catch (e) {
return c.text(`Failed create address: ${e.message}`, 400)
return c.text(`Failed create address: ${(e as Error).message}`, 400)
}
})
@@ -181,16 +183,16 @@ api.get('/admin/sendbox', async (c) => {
api.get('/admin/statistics', async (c) => {
const { count: mailCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM raw_mails`
).first();
).first<{ count: number }>() || {};
const { count: addressCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM address`
).first();
).first<{ count: number }>() || {};
const { count: activeUserCount7days } = await c.env.DB.prepare(
`SELECT count(*) as count FROM address where updated_at > datetime('now', '-7 day')`
).first();
).first<{ count: number }>() || {};
const { count: sendMailCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM sendbox`
).first();
).first<{ count: number }>() || {};
return c.json({
mailCount: mailCount,
userCount: addressCount,
@@ -201,13 +203,13 @@ api.get('/admin/statistics', async (c) => {
api.get('/admin/account_settings', async (c) => {
try {
/** @type {Array<string>|undefined|null} */
const blockList = await getJsonSetting(c, CONSTANTS.ADDRESS_BLOCK_LIST_KEY);
/** @type {Array<string>|undefined|null} */
const sendBlockList = await getJsonSetting(c, CONSTANTS.SEND_BLOCK_LIST_KEY);
const verifiedAddressList = await getJsonSetting(c, CONSTANTS.VERIFIED_ADDRESS_LIST_KEY);
return c.json({
blockList: blockList || [],
sendBlockList: sendBlockList || []
sendBlockList: sendBlockList || [],
verifiedAddressList: verifiedAddressList || []
})
} catch (error) {
console.error(error);
@@ -217,10 +219,13 @@ api.get('/admin/account_settings', async (c) => {
api.post('/admin/account_settings', async (c) => {
/** @type {{ blockList: Array<string>, sendBlockList: Array<string> }} */
const { blockList, sendBlockList } = await c.req.json();
if (!blockList || !sendBlockList) {
const { blockList, sendBlockList, verifiedAddressList } = await c.req.json();
if (!blockList || !sendBlockList || !verifiedAddressList) {
return c.text("Invalid blockList or sendBlockList", 400)
}
if (!c.env.SEND_MAIL && verifiedAddressList.length > 0) {
return c.text("Please enable SEND_MAIL to use verifiedAddressList", 400)
}
await saveSetting(
c, CONSTANTS.ADDRESS_BLOCK_LIST_KEY,
JSON.stringify(blockList)
@@ -229,6 +234,10 @@ api.post('/admin/account_settings', async (c) => {
c, CONSTANTS.SEND_BLOCK_LIST_KEY,
JSON.stringify(sendBlockList)
);
await saveSetting(
c, CONSTANTS.VERIFIED_ADDRESS_LIST_KEY,
JSON.stringify(verifiedAddressList)
)
return c.json({
success: true
})
@@ -245,5 +254,3 @@ api.post('/admin/users', admin_user_api.createUser)
api.post('/admin/users/:user_id/reset_password', admin_user_api.resetPassword)
api.get("/admin/webhook/settings", webhook_settings.getWebhookSettings);
api.post("/admin/webhook/settings", webhook_settings.saveWebhookSettings);
export { api }

View File

@@ -1,7 +1,7 @@
import { Context } from "hono";
import { HonoCustomType } from "../types";
import { CONSTANTS } from "../constants";
import { AdminWebhookSettings } from "../models/models";
import { AdminWebhookSettings } from "../models";
async function getWebhookSettings(c: Context<HonoCustomType>): Promise<Response> {
const settings = await c.env.KV.get<AdminWebhookSettings>(CONSTANTS.WEBHOOK_KV_SETTINGS_KEY, "json");