feat: add apprise notification #10
This commit is contained in:
parent
699fe6c967
commit
09c3cfa0dc
@ -8,6 +8,9 @@ COPY . .
|
||||
|
||||
RUN apk add --update --no-cache python3 g++ make py3-pip
|
||||
|
||||
# Push client(only support pure text message)
|
||||
RUN pip install apprise
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
RUN pnpm build
|
||||
|
@ -50,6 +50,7 @@
|
||||
"detect-browser": "^5.3.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"eventemitter-strict": "^1.0.1",
|
||||
"execa": "^5.1.1",
|
||||
"express": "^4.18.2",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-validator": "^7.0.1",
|
||||
|
@ -82,6 +82,9 @@ dependencies:
|
||||
eventemitter-strict:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
execa:
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1
|
||||
express:
|
||||
specifier: ^4.18.2
|
||||
version: 4.18.2
|
||||
@ -5183,7 +5186,6 @@ packages:
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
strip-final-newline: 2.0.0
|
||||
dev: true
|
||||
|
||||
/execa@7.2.0:
|
||||
resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
|
||||
@ -5983,7 +5985,6 @@ packages:
|
||||
/human-signals@2.1.0:
|
||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||
engines: {node: '>=10.17.0'}
|
||||
dev: true
|
||||
|
||||
/human-signals@4.3.1:
|
||||
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
|
||||
@ -6911,7 +6912,6 @@ packages:
|
||||
|
||||
/merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
dev: true
|
||||
|
||||
/merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
@ -6961,7 +6961,6 @@ packages:
|
||||
/mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/mimic-fn@4.0.0:
|
||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||
@ -7346,7 +7345,6 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
dev: true
|
||||
|
||||
/npm-run-path@5.2.0:
|
||||
resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==}
|
||||
@ -7423,7 +7421,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
dev: true
|
||||
|
||||
/onetime@6.0.0:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
@ -9484,7 +9481,6 @@ packages:
|
||||
|
||||
/signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
dev: true
|
||||
|
||||
/signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
@ -9839,7 +9835,6 @@ packages:
|
||||
/strip-final-newline@2.0.0:
|
||||
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/strip-final-newline@3.0.0:
|
||||
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
|
||||
|
@ -0,0 +1,26 @@
|
||||
import { Form, Input } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export const NotificationApprise: React.FC = React.memo(() => {
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
label="Apprise URL"
|
||||
name={['payload', 'appriseUrl']}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input placeholder="For example: pushdeer://pushKey" />
|
||||
</Form.Item>
|
||||
<div className="text-sm opacity-80">
|
||||
Read more:{' '}
|
||||
<a
|
||||
href="https://github.com/caronc/apprise/wiki#notification-services"
|
||||
target="_blank"
|
||||
>
|
||||
https://github.com/caronc/apprise/wiki#notification-services
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
NotificationApprise.displayName = 'NotificationApprise';
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { NotificationSMTP } from './smtp';
|
||||
import { NotificationTelegram } from './telegram';
|
||||
import { NotificationApprise } from './apprise';
|
||||
|
||||
interface NotificationStrategy {
|
||||
label: string;
|
||||
@ -14,6 +15,11 @@ export const notificationStrategies: NotificationStrategy[] = [
|
||||
name: 'smtp',
|
||||
form: NotificationSMTP,
|
||||
},
|
||||
{
|
||||
label: 'Apprise(Support 90+ services)',
|
||||
name: 'apprise',
|
||||
form: NotificationApprise,
|
||||
},
|
||||
{
|
||||
label: 'Telegram',
|
||||
name: 'telegram',
|
||||
|
@ -19,7 +19,6 @@ import { initUdpServer } from './udp/server';
|
||||
import { createServer } from 'http';
|
||||
import { initSocketio } from './ws';
|
||||
import { monitorManager } from './model/monitor';
|
||||
import { settings } from './utils/settings';
|
||||
import { env } from './utils/env';
|
||||
import cors from 'cors';
|
||||
import { serverStatusRouter } from './router/serverStatus';
|
||||
@ -28,7 +27,7 @@ import { logger } from './utils/logger';
|
||||
import { monitorRouter } from './router/monitor';
|
||||
import { healthRouter } from './router/health';
|
||||
|
||||
const port = settings.port;
|
||||
const port = env.port;
|
||||
|
||||
const app = express();
|
||||
const httpServer = createServer(app);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { getBillingCreditGrants } from '../openai';
|
||||
|
||||
describe.runIf(!!process.env.OPENAI_SESS_KEY)('openai', () => {
|
||||
describe.runIf(!!process.env.TEST_OPENAI_SESS_KEY)('openai', () => {
|
||||
test('getBillingCreditGrants should be ok', async () => {
|
||||
const res = await getBillingCreditGrants(
|
||||
String(process.env.OPENAI_SESS_KEY)
|
||||
String(process.env.TEST_OPENAI_SESS_KEY)
|
||||
);
|
||||
|
||||
expect(typeof res.allUSD).toBe('number');
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { describe, test } from 'vitest';
|
||||
import { apprise } from '../apprise';
|
||||
import { token } from '../../token';
|
||||
|
||||
describe.runIf(!!process.env.TEST_APPRISE_URL)('apprise', () => {
|
||||
test('apprise should be work', async () => {
|
||||
await apprise.send(
|
||||
{
|
||||
payload: {
|
||||
appriseUrl: process.env.TEST_APPRISE_URL,
|
||||
},
|
||||
} as any,
|
||||
'test title',
|
||||
[token.text('Foooo'), token.newline(), token.text('Baaaar')]
|
||||
);
|
||||
});
|
||||
});
|
34
src/server/model/notification/provider/apprise.ts
Normal file
34
src/server/model/notification/provider/apprise.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { NotificationProvider } from './type';
|
||||
import { baseContentTokenizer } from '../token';
|
||||
import execa from 'execa';
|
||||
|
||||
interface ApprisePayload {
|
||||
appriseUrl: string;
|
||||
}
|
||||
|
||||
// Fork from https://github.com/louislam/uptime-kuma/blob/HEAD/server/notification-providers/smtp.js
|
||||
export const apprise: NotificationProvider = {
|
||||
send: async (notification, title, message) => {
|
||||
const payload = notification.payload as unknown as ApprisePayload;
|
||||
|
||||
const content = baseContentTokenizer.parse(message);
|
||||
|
||||
const args = ['-vv', '-b', content, payload.appriseUrl];
|
||||
if (title) {
|
||||
args.push('-t');
|
||||
args.push(title);
|
||||
}
|
||||
|
||||
const { stdout } = await execa('apprise', args);
|
||||
|
||||
const output = stdout
|
||||
? stdout.toString()
|
||||
: 'ERROR: maybe apprise not found';
|
||||
|
||||
if (output) {
|
||||
if (output.includes('ERROR')) {
|
||||
throw new Error(output);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
@ -1,8 +1,10 @@
|
||||
import { apprise } from './apprise';
|
||||
import { smtp } from './smtp';
|
||||
import { telegram } from './telegram';
|
||||
import type { NotificationProvider } from './type';
|
||||
|
||||
export const notificationProviders: Record<string, NotificationProvider> = {
|
||||
smtp,
|
||||
apprise,
|
||||
telegram,
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const env = {
|
||||
port: Number(process.env.PORT || 12345),
|
||||
allowRegister: checkEnvTrusty(process.env.ALLOW_REGISTER),
|
||||
allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI),
|
||||
websiteId: process.env.WEBSITE_ID,
|
||||
|
@ -1,3 +0,0 @@
|
||||
export const settings = {
|
||||
port: Number(process.env.PORT || 12345),
|
||||
};
|
Loading…
Reference in New Issue
Block a user