mirror of
https://github.com/acgnhiki/blrec.git
synced 2025-01-30 19:00:25 +08:00
feat: add pushdeer notification
This commit is contained in:
parent
cc44f20c2f
commit
d5d9ece36a
@ -31,6 +31,7 @@ from .setting import (
|
||||
from .notification import (
|
||||
EmailNotifier,
|
||||
ServerchanNotifier,
|
||||
PushdeerNotifier,
|
||||
PushplusNotifier,
|
||||
TelegramNotifier,
|
||||
)
|
||||
@ -327,10 +328,12 @@ class Application:
|
||||
def _setup_notifiers(self) -> None:
|
||||
self._email_notifier = EmailNotifier()
|
||||
self._serverchan_notifier = ServerchanNotifier()
|
||||
self._pushdeer_notifier = PushdeerNotifier()
|
||||
self._pushplus_notifier = PushplusNotifier()
|
||||
self._telegram_notifier = TelegramNotifier()
|
||||
self._settings_manager.apply_email_notification_settings()
|
||||
self._settings_manager.apply_serverchan_notification_settings()
|
||||
self._settings_manager.apply_pushdeer_notification_settings()
|
||||
self._settings_manager.apply_pushplus_notification_settings()
|
||||
self._settings_manager.apply_telegram_notification_settings()
|
||||
|
||||
@ -361,10 +364,12 @@ class Application:
|
||||
def _destroy_notifiers(self) -> None:
|
||||
self._email_notifier.disable()
|
||||
self._serverchan_notifier.disable()
|
||||
self._pushdeer_notifier.disable()
|
||||
self._pushplus_notifier.disable()
|
||||
self._telegram_notifier.disable()
|
||||
del self._email_notifier
|
||||
del self._serverchan_notifier
|
||||
del self._pushdeer_notifier
|
||||
del self._pushplus_notifier
|
||||
del self._telegram_notifier
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
1
src/blrec/data/webapp/474.88f730916af2dc81.js
Normal file
1
src/blrec/data/webapp/474.88f730916af2dc81.js
Normal file
File diff suppressed because one or more lines are too long
1
src/blrec/data/webapp/66.17103bf51c59b5c8.js
Normal file
1
src/blrec/data/webapp/66.17103bf51c59b5c8.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -10,6 +10,6 @@
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<noscript>Please enable JavaScript to continue using this application.</noscript>
|
||||
<script src="runtime.c354415fc493c1ff.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.ee42aef57b3529db.js" type="module"></script>
|
||||
<script src="runtime.5296fd12ffdfadbe.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.b9234f0840c7101a.js" type="module"></script>
|
||||
|
||||
</body></html>
|
1
src/blrec/data/webapp/main.b9234f0840c7101a.js
Normal file
1
src/blrec/data/webapp/main.b9234f0840c7101a.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"configVersion": 1,
|
||||
"timestamp": 1651319640894,
|
||||
"timestamp": 1651566774775,
|
||||
"index": "/index.html",
|
||||
"assetGroups": [
|
||||
{
|
||||
@ -13,16 +13,16 @@
|
||||
"urls": [
|
||||
"/103.5b5d2a6e5a8a7479.js",
|
||||
"/146.92e3b29c4c754544.js",
|
||||
"/369.6447ab1db6f39c5d.js",
|
||||
"/45.c90c3cea2bf1a66e.js",
|
||||
"/66.925f958307346684.js",
|
||||
"/474.88f730916af2dc81.js",
|
||||
"/66.17103bf51c59b5c8.js",
|
||||
"/869.ac675e78fa0ea7cf.js",
|
||||
"/common.858f777e9296e6f2.js",
|
||||
"/index.html",
|
||||
"/main.ee42aef57b3529db.js",
|
||||
"/main.b9234f0840c7101a.js",
|
||||
"/manifest.webmanifest",
|
||||
"/polyfills.4b08448aee19bb22.js",
|
||||
"/runtime.c354415fc493c1ff.js",
|
||||
"/runtime.5296fd12ffdfadbe.js",
|
||||
"/styles.1f581691b230dc4d.css"
|
||||
],
|
||||
"patterns": []
|
||||
@ -1636,9 +1636,9 @@
|
||||
"hashTable": {
|
||||
"/103.5b5d2a6e5a8a7479.js": "cc0240f217015b6d4ddcc14f31fcc42e1c1c282a",
|
||||
"/146.92e3b29c4c754544.js": "3824de681dd1f982ea69a065cdf54d7a1e781f4d",
|
||||
"/369.6447ab1db6f39c5d.js": "4e3ec6f0b1742d78c52c49ba2ce0099778ae369c",
|
||||
"/45.c90c3cea2bf1a66e.js": "e5bfb8cf3803593e6b8ea14c90b3d3cb6a066764",
|
||||
"/66.925f958307346684.js": "cda15ab0b7c746412407ced24061e5913450d955",
|
||||
"/474.88f730916af2dc81.js": "e7cb3e7bd68c162633d94c8c848dea2daeac8bc3",
|
||||
"/66.17103bf51c59b5c8.js": "67c9bb3ac7e7c7c25ebe1db69fc87890a2fdc184",
|
||||
"/869.ac675e78fa0ea7cf.js": "f45052016cb5201d5784b3f261e719d96bd1b153",
|
||||
"/assets/animal/panda.js": "fec2868bb3053dd2da45f96bbcb86d5116ed72b1",
|
||||
"/assets/animal/panda.svg": "bebd302cdc601e0ead3a6d2710acf8753f3d83b1",
|
||||
@ -3234,11 +3234,11 @@
|
||||
"/assets/twotone/warning.js": "fb2d7ea232f3a99bf8f080dbc94c65699232ac01",
|
||||
"/assets/twotone/warning.svg": "8c7a2d3e765a2e7dd58ac674870c6655cecb0068",
|
||||
"/common.858f777e9296e6f2.js": "b68ca68e1e214a2537d96935c23410126cc564dd",
|
||||
"/index.html": "cf9bd8f6b2acd7238eb2a0a7d807baaa36f2daed",
|
||||
"/main.ee42aef57b3529db.js": "003c7b5dec11f8297a28878ba376f0ba429fb045",
|
||||
"/manifest.webmanifest": "0c4534b4c868d756691b1b4372cecb2efce47c6d",
|
||||
"/index.html": "4957097d609200632fe355aef8f7603a3bb1addc",
|
||||
"/main.b9234f0840c7101a.js": "c8c7b588c070b957a2659f62d6a77de284aa2233",
|
||||
"/manifest.webmanifest": "62c1cb8c5ad2af551a956b97013ab55ce77dd586",
|
||||
"/polyfills.4b08448aee19bb22.js": "8e73f2d42cc13ca353cea5c886d930bd6da08d0d",
|
||||
"/runtime.c354415fc493c1ff.js": "f6682aed9b5806652e888520f71d062494af864b",
|
||||
"/runtime.5296fd12ffdfadbe.js": "5b84a91028ab9e0daaaf89d70f2d12c48d5e358e",
|
||||
"/styles.1f581691b230dc4d.css": "6f5befbbad57c2b2e80aae855139744b8010d150"
|
||||
},
|
||||
"navigationUrls": [
|
||||
|
@ -1 +1 @@
|
||||
(()=>{"use strict";var e,v={},m={};function r(e){var i=m[e];if(void 0!==i)return i.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(i,t,f,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,f,o]=e[n],c=!0,l=0;l<t.length;l++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=f();void 0!==d&&(i=d)}}return i}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,f,o]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",66:"925f958307346684",103:"5b5d2a6e5a8a7479",146:"92e3b29c4c754544",369:"6447ab1db6f39c5d",592:"858f777e9296e6f2",869:"ac675e78fa0ea7cf"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="blrec:";r.l=(t,f,o,n)=>{if(e[t])e[t].push(f);else{var a,c;if(void 0!==o)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==i+o){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+o),a.src=r.tu(t)),e[t]=[f];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var n=r.o(e,f)?e[f]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=f){var a=new Promise((u,s)=>n=e[f]=[u,s]);o.push(n[2]=a);var c=r.p+r.u(f),l=new Error;r.l(c,u=>{if(r.o(e,f)&&(0!==(n=e[f])&&(e[f]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+f+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var i=(f,o)=>{var l,d,[n,a,c]=o,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(f&&f(o);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
||||
(()=>{"use strict";var e,v={},m={};function r(e){var i=m[e];if(void 0!==i)return i.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(i,t,o,f)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,o,f]=e[n],c=!0,l=0;l<t.length;l++)(!1&f||a>=f)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,f<a&&(a=f));if(c){e.splice(n--,1);var d=o();void 0!==d&&(i=d)}}return i}f=f||0;for(var n=e.length;n>0&&e[n-1][2]>f;n--)e[n]=e[n-1];e[n]=[t,o,f]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",66:"17103bf51c59b5c8",103:"5b5d2a6e5a8a7479",146:"92e3b29c4c754544",474:"88f730916af2dc81",592:"858f777e9296e6f2",869:"ac675e78fa0ea7cf"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="blrec:";r.l=(t,o,f,n)=>{if(e[t])e[t].push(o);else{var a,c;if(void 0!==f)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==i+f){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+f),a.src=r.tu(t)),e[t]=[o];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(o,f)=>{var n=r.o(e,o)?e[o]:void 0;if(0!==n)if(n)f.push(n[2]);else if(666!=o){var a=new Promise((u,s)=>n=e[o]=[u,s]);f.push(n[2]=a);var c=r.p+r.u(o),l=new Error;r.l(c,u=>{if(r.o(e,o)&&(0!==(n=e[o])&&(e[o]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+o+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+o,o)}else e[o]=0},r.O.j=o=>0===e[o];var i=(o,f)=>{var l,d,[n,a,c]=f,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(o&&o(f);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
@ -3,6 +3,7 @@ from .notifiers import (
|
||||
MessageNotifier,
|
||||
EmailNotifier,
|
||||
ServerchanNotifier,
|
||||
PushdeerNotifier,
|
||||
PushplusNotifier,
|
||||
TelegramNotifier,
|
||||
)
|
||||
@ -10,6 +11,7 @@ from .providers import (
|
||||
MessagingProvider,
|
||||
EmailService,
|
||||
Serverchan,
|
||||
Pushdeer,
|
||||
Pushplus,
|
||||
Telegram,
|
||||
)
|
||||
@ -19,6 +21,7 @@ __all__ = (
|
||||
'MessagingProvider',
|
||||
'EmailService',
|
||||
'Serverchan',
|
||||
'Pushdeer',
|
||||
'Pushplus',
|
||||
'Telegram',
|
||||
|
||||
@ -26,6 +29,7 @@ __all__ = (
|
||||
'MessageNotifier',
|
||||
'EmailNotifier',
|
||||
'ServerchanNotifier',
|
||||
'PushdeerNotifier',
|
||||
'PushplusNotifier',
|
||||
'TelegramNotifier',
|
||||
)
|
||||
|
@ -13,6 +13,7 @@ from .providers import (
|
||||
EmailService,
|
||||
MessagingProvider,
|
||||
Serverchan,
|
||||
Pushdeer,
|
||||
Pushplus,
|
||||
Telegram,
|
||||
)
|
||||
@ -37,6 +38,7 @@ __all__ = (
|
||||
'MessageNotifier',
|
||||
'EmailNotifier',
|
||||
'ServerchanNotifier',
|
||||
'PushdeerNotifier',
|
||||
'PushplusNotifier',
|
||||
'TelegramNotifier',
|
||||
)
|
||||
@ -190,6 +192,18 @@ class ServerchanNotifier(MessageNotifier):
|
||||
logger.debug('Disabled Serverchan notifier')
|
||||
|
||||
|
||||
class PushdeerNotifier(MessageNotifier):
|
||||
provider = Pushdeer.get_instance()
|
||||
|
||||
def _do_enable(self) -> None:
|
||||
super()._do_enable()
|
||||
logger.debug('Enabled Pushdeer notifier')
|
||||
|
||||
def _do_disable(self) -> None:
|
||||
super()._do_disable()
|
||||
logger.debug('Disabled Pushdeer notifier')
|
||||
|
||||
|
||||
class PushplusNotifier(MessageNotifier):
|
||||
provider = Pushplus.get_instance()
|
||||
|
||||
|
@ -1,19 +1,24 @@
|
||||
import ssl
|
||||
import logging
|
||||
import asyncio
|
||||
import logging
|
||||
import smtplib
|
||||
import ssl
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TypedDict, cast, Literal
|
||||
from email.message import EmailMessage
|
||||
from http.client import HTTPException
|
||||
from typing import Final, Literal, TypedDict, cast
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import aiohttp
|
||||
|
||||
from ..utils.patterns import Singleton
|
||||
|
||||
|
||||
__all__ = (
|
||||
'MessagingProvider', 'EmailService', 'Serverchan', 'Pushplus', 'Telegram'
|
||||
'MessagingProvider',
|
||||
'EmailService',
|
||||
'Serverchan',
|
||||
'Pushdeer',
|
||||
'Pushplus',
|
||||
'Telegram',
|
||||
)
|
||||
|
||||
|
||||
@ -109,6 +114,44 @@ class Serverchan(MessagingProvider):
|
||||
pass
|
||||
|
||||
|
||||
class PushdeerResponse(TypedDict):
|
||||
code: int
|
||||
content: str
|
||||
error: str
|
||||
|
||||
|
||||
class Pushdeer(MessagingProvider):
|
||||
_server: Final = 'https://api2.pushdeer.com'
|
||||
_endpoint: Final = '/message/push'
|
||||
|
||||
def __init__(self, server: str = '', pushkey: str = '') -> None:
|
||||
super().__init__()
|
||||
self.server = server
|
||||
self.pushkey = pushkey
|
||||
|
||||
async def send_message(self, title: str, content: str) -> None:
|
||||
self._check_parameters()
|
||||
await self._post_message(title, content)
|
||||
|
||||
def _check_parameters(self) -> None:
|
||||
if not self.pushkey:
|
||||
raise ValueError('No pushkey supplied')
|
||||
|
||||
async def _post_message(self, title: str, content: str) -> None:
|
||||
url = urljoin(self.server or self._server, self._endpoint)
|
||||
payload = {
|
||||
'pushkey': self.pushkey,
|
||||
'text': title,
|
||||
'desp': content,
|
||||
'type': 'text',
|
||||
}
|
||||
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
||||
async with session.post(url, json=payload) as res:
|
||||
response = cast(PushdeerResponse, await res.json())
|
||||
if response['code'] != 0:
|
||||
raise HTTPException(response['code'], response['error'])
|
||||
|
||||
|
||||
class PushplusResponse(TypedDict):
|
||||
code: int
|
||||
msg: str
|
||||
|
@ -22,12 +22,14 @@ from .models import (
|
||||
SpaceSettings,
|
||||
EmailSettings,
|
||||
ServerchanSettings,
|
||||
PushdeerSettings,
|
||||
PushplusSettings,
|
||||
TelegramSettings,
|
||||
NotifierSettings,
|
||||
NotificationSettings,
|
||||
EmailNotificationSettings,
|
||||
ServerchanNotificationSettings,
|
||||
PushdeerNotificationSettings,
|
||||
PushplusNotificationSettings,
|
||||
TelegramNotificationSettings,
|
||||
WebHookSettings,
|
||||
@ -64,12 +66,14 @@ __all__ = (
|
||||
'SpaceSettings',
|
||||
'EmailSettings',
|
||||
'ServerchanSettings',
|
||||
'PushdeerSettings',
|
||||
'PushplusSettings',
|
||||
'TelegramSettings',
|
||||
'NotifierSettings',
|
||||
'NotificationSettings',
|
||||
'EmailNotificationSettings',
|
||||
'ServerchanNotificationSettings',
|
||||
'PushdeerNotificationSettings',
|
||||
'PushplusNotificationSettings',
|
||||
'TelegramNotificationSettings',
|
||||
'WebHookSettings',
|
||||
|
@ -51,12 +51,14 @@ __all__ = (
|
||||
'SpaceSettings',
|
||||
'EmailSettings',
|
||||
'ServerchanSettings',
|
||||
'PushdeerSettings',
|
||||
'PushplusSettings',
|
||||
'TelegramSettings',
|
||||
'NotifierSettings',
|
||||
'NotificationSettings',
|
||||
'EmailNotificationSettings',
|
||||
'ServerchanNotificationSettings',
|
||||
'PushdeerNotificationSettings',
|
||||
'PushplusNotificationSettings',
|
||||
'TelegramNotificationSettings',
|
||||
'WebHookSettings',
|
||||
@ -345,6 +347,23 @@ class ServerchanSettings(BaseModel):
|
||||
return value
|
||||
|
||||
|
||||
class PushdeerSettings(BaseModel):
|
||||
server: str = ''
|
||||
pushkey: str = ''
|
||||
|
||||
@validator('server')
|
||||
def _validate_server(cls, value: str) -> str:
|
||||
if value != '' and not re.fullmatch(r'https?://.+', value):
|
||||
raise ValueError('server is invalid')
|
||||
return value
|
||||
|
||||
@validator('pushkey')
|
||||
def _validate_pushkey(cls, value: str) -> str:
|
||||
if value != '' and not re.fullmatch(r'[a-zA-Z\d]{41}', value):
|
||||
raise ValueError('pushkey is invalid')
|
||||
return value
|
||||
|
||||
|
||||
class PushplusSettings(BaseModel):
|
||||
token: str = ''
|
||||
topic: str = ''
|
||||
@ -398,6 +417,12 @@ class ServerchanNotificationSettings(
|
||||
pass
|
||||
|
||||
|
||||
class PushdeerNotificationSettings(
|
||||
PushdeerSettings, NotifierSettings, NotificationSettings
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
class PushplusNotificationSettings(
|
||||
PushplusSettings, NotifierSettings, NotificationSettings
|
||||
):
|
||||
@ -450,6 +475,8 @@ class Settings(BaseModel):
|
||||
email_notification: EmailNotificationSettings = EmailNotificationSettings()
|
||||
serverchan_notification: ServerchanNotificationSettings = \
|
||||
ServerchanNotificationSettings()
|
||||
pushdeer_notification: PushdeerNotificationSettings = \
|
||||
PushdeerNotificationSettings()
|
||||
pushplus_notification: PushplusNotificationSettings = \
|
||||
PushplusNotificationSettings()
|
||||
telegram_notification: TelegramNotificationSettings = \
|
||||
@ -500,6 +527,7 @@ class SettingsIn(BaseModel):
|
||||
space: Optional[SpaceSettings] = None
|
||||
email_notification: Optional[EmailNotificationSettings] = None
|
||||
serverchan_notification: Optional[ServerchanNotificationSettings] = None
|
||||
pushdeer_notification: Optional[PushdeerNotificationSettings] = None
|
||||
pushplus_notification: Optional[PushplusNotificationSettings] = None
|
||||
telegram_notification: Optional[TelegramNotificationSettings] = None
|
||||
webhooks: Optional[List[WebHookSettings]] = None
|
||||
|
@ -22,7 +22,7 @@ from .models import (
|
||||
from .typing import KeySetOfSettings
|
||||
from ..webhook import WebHook
|
||||
from ..notification import (
|
||||
Notifier, EmailService, Serverchan, Pushplus, Telegram
|
||||
Notifier, EmailService, Serverchan, Pushdeer, Pushplus, Telegram
|
||||
)
|
||||
from ..logging import configure_logger
|
||||
from ..exception import NotFoundError
|
||||
@ -335,6 +335,13 @@ class SettingsManager:
|
||||
self._apply_notifier_settings(notifier, settings)
|
||||
self._apply_notification_settings(notifier, settings)
|
||||
|
||||
def apply_pushdeer_notification_settings(self) -> None:
|
||||
notifier = self._app._pushdeer_notifier
|
||||
settings = self._settings.pushdeer_notification
|
||||
self._apply_pushdeer_settings(notifier.provider)
|
||||
self._apply_notifier_settings(notifier, settings)
|
||||
self._apply_notification_settings(notifier, settings)
|
||||
|
||||
def apply_pushplus_notification_settings(self) -> None:
|
||||
notifier = self._app._pushplus_notifier
|
||||
settings = self._settings.pushplus_notification
|
||||
@ -363,6 +370,10 @@ class SettingsManager:
|
||||
def _apply_serverchan_settings(self, serverchan: Serverchan) -> None:
|
||||
serverchan.sendkey = self._settings.serverchan_notification.sendkey
|
||||
|
||||
def _apply_pushdeer_settings(self, pushdeer: Pushdeer) -> None:
|
||||
pushdeer.server = self._settings.pushdeer_notification.server
|
||||
pushdeer.pushkey = self._settings.pushdeer_notification.pushkey
|
||||
|
||||
def _apply_pushplus_settings(self, pushplus: Pushplus) -> None:
|
||||
pushplus.token = self._settings.pushplus_notification.token
|
||||
pushplus.topic = self._settings.pushplus_notification.topic
|
||||
|
@ -13,6 +13,7 @@ KeyOfSettings = Literal[
|
||||
'space',
|
||||
'email_notification',
|
||||
'serverchan_notification',
|
||||
'pushdeer_notification',
|
||||
'pushplus_notification',
|
||||
'telegram_notification',
|
||||
'webhooks',
|
||||
|
@ -51,6 +51,7 @@ AliasKeyOfSettings = Literal[
|
||||
'space',
|
||||
'emailNotification',
|
||||
'serverchanNotification',
|
||||
'pushdeerNotification',
|
||||
'pushplusNotification',
|
||||
'telegramNotification',
|
||||
'webhooks',
|
||||
|
@ -6,6 +6,10 @@
|
||||
><span class="setting-label">ServerChan 通知</span
|
||||
><span class="setting-control"><i nz-icon nzType="right"></i></span
|
||||
></a>
|
||||
<a class="setting-item" routerLink="pushdeer-notification"
|
||||
><span class="setting-label">PushDeer 通知</span
|
||||
><span class="setting-control"><i nz-icon nzType="right"></i></span
|
||||
></a>
|
||||
<a class="setting-item" routerLink="pushplus-notification"
|
||||
><span class="setting-label">pushplus 通知</span
|
||||
><span class="setting-control"><i nz-icon nzType="right"></i></span
|
||||
|
@ -0,0 +1,24 @@
|
||||
<app-sub-page pageTitle="PushDeer 通知">
|
||||
<ng-template appSubPageContent>
|
||||
<app-page-section>
|
||||
<app-notifier-settings
|
||||
[settings]="notifierSettings"
|
||||
keyOfSettings="pushdeerNotification"
|
||||
></app-notifier-settings>
|
||||
</app-page-section>
|
||||
|
||||
<app-page-section name="PushDeer">
|
||||
<app-pushdeer-settings
|
||||
[settings]="pushdeerSettings"
|
||||
></app-pushdeer-settings>
|
||||
</app-page-section>
|
||||
|
||||
<app-page-section name="事件">
|
||||
<app-event-settings
|
||||
[settings]="notificationSettings"
|
||||
keyOfSettings="pushdeerNotification"
|
||||
></app-event-settings>
|
||||
</app-page-section>
|
||||
</ng-template>
|
||||
</app-sub-page>
|
||||
|
@ -0,0 +1,2 @@
|
||||
|
||||
@use '../../shared/styles/setting';
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PushdeerNotificationSettingsComponent } from './pushdeer-notification-settings.component';
|
||||
|
||||
describe('PushdeerNotificationSettingsComponent', () => {
|
||||
let component: PushdeerNotificationSettingsComponent;
|
||||
let fixture: ComponentFixture<PushdeerNotificationSettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PushdeerNotificationSettingsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PushdeerNotificationSettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import pick from 'lodash-es/pick';
|
||||
|
||||
import {
|
||||
KEYS_OF_NOTIFICATION_SETTINGS,
|
||||
KEYS_OF_NOTIFIER_SETTINGS,
|
||||
KEYS_OF_PUSHDEER_SETTINGS,
|
||||
NotificationSettings,
|
||||
NotifierSettings,
|
||||
PushdeerNotificationSettings,
|
||||
PushdeerSettings,
|
||||
} from '../../shared/setting.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pushdeer-notification-settings',
|
||||
templateUrl: './pushdeer-notification-settings.component.html',
|
||||
styleUrls: ['./pushdeer-notification-settings.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PushdeerNotificationSettingsComponent implements OnInit {
|
||||
pushdeerSettings!: PushdeerSettings;
|
||||
notifierSettings!: NotifierSettings;
|
||||
notificationSettings!: NotificationSettings;
|
||||
|
||||
constructor(
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
private route: ActivatedRoute
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.data.subscribe((data) => {
|
||||
const settings = data.settings as PushdeerNotificationSettings;
|
||||
this.pushdeerSettings = pick(settings, KEYS_OF_PUSHDEER_SETTINGS);
|
||||
this.notifierSettings = pick(settings, KEYS_OF_NOTIFIER_SETTINGS);
|
||||
this.notificationSettings = pick(settings, KEYS_OF_NOTIFICATION_SETTINGS);
|
||||
this.changeDetector.markForCheck();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<form nz-form [formGroup]="settingsForm">
|
||||
<nz-form-item class="setting-item">
|
||||
<nz-form-label class="setting-label align-required" nzFor="server" nzNoColon
|
||||
>server</nz-form-label
|
||||
>
|
||||
<nz-form-control
|
||||
class="setting-control input"
|
||||
nzHasFeedback
|
||||
[nzErrorTip]="serverErrorTip"
|
||||
[nzWarningTip]="syncFailedWarningTip"
|
||||
[nzValidateStatus]="
|
||||
serverControl.valid && !syncStatus.server ? 'warning' : serverControl
|
||||
"
|
||||
>
|
||||
<input
|
||||
id="server"
|
||||
type="url"
|
||||
placeholder="默认为官方服务器 https://api2.pushdeer.com"
|
||||
nz-input
|
||||
formControlName="server"
|
||||
/>
|
||||
<ng-template #serverErrorTip let-control>
|
||||
<ng-container *ngIf="control.hasError('pattern')">
|
||||
server 无效
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item class="setting-item">
|
||||
<nz-form-label class="setting-label" nzFor="pushkey" nzNoColon nzRequired
|
||||
>pushkey</nz-form-label
|
||||
>
|
||||
<nz-form-control
|
||||
class="setting-control input"
|
||||
nzHasFeedback
|
||||
[nzErrorTip]="pushkeyErrorTip"
|
||||
[nzWarningTip]="syncFailedWarningTip"
|
||||
[nzValidateStatus]="
|
||||
pushkeyControl.valid && !syncStatus.pushkey ? 'warning' : pushkeyControl
|
||||
"
|
||||
>
|
||||
<input
|
||||
id="pushkey"
|
||||
type="text"
|
||||
required
|
||||
nz-input
|
||||
formControlName="pushkey"
|
||||
/>
|
||||
<ng-template #pushkeyErrorTip let-control>
|
||||
<ng-container *ngIf="control.hasError('required')">
|
||||
请输入 pushkey!
|
||||
</ng-container>
|
||||
<ng-container *ngIf="control.hasError('pattern')">
|
||||
pushkey 无效
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
@ -0,0 +1,6 @@
|
||||
@use '../../../shared/styles/setting';
|
||||
|
||||
.setting-label {
|
||||
max-width: 5em !important;
|
||||
width: 5em !important;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PushdeerSettingsComponent } from './pushdeer-settings.component';
|
||||
|
||||
describe('PushdeerSettingsComponent', () => {
|
||||
let component: PushdeerSettingsComponent;
|
||||
let fixture: ComponentFixture<PushdeerSettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PushdeerSettingsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PushdeerSettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,81 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
OnChanges,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
|
||||
import mapValues from 'lodash-es/mapValues';
|
||||
|
||||
import { PushdeerSettings } from '../../../shared/setting.model';
|
||||
import { filterValueChanges } from '../../../shared/rx-operators';
|
||||
import {
|
||||
SettingsSyncService,
|
||||
SyncStatus,
|
||||
calcSyncStatus,
|
||||
} from '../../../shared/services/settings-sync.service';
|
||||
import { SYNC_FAILED_WARNING_TIP } from 'src/app/settings/shared/constants/form';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pushdeer-settings',
|
||||
templateUrl: './pushdeer-settings.component.html',
|
||||
styleUrls: ['./pushdeer-settings.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PushdeerSettingsComponent implements OnInit, OnChanges {
|
||||
@Input() settings!: PushdeerSettings;
|
||||
syncStatus!: SyncStatus<PushdeerSettings>;
|
||||
|
||||
readonly settingsForm: FormGroup;
|
||||
readonly syncFailedWarningTip = SYNC_FAILED_WARNING_TIP;
|
||||
|
||||
constructor(
|
||||
formBuilder: FormBuilder,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
private settingsSyncService: SettingsSyncService
|
||||
) {
|
||||
this.settingsForm = formBuilder.group({
|
||||
server: ['', [Validators.pattern(/^https?:\/\/.+/)]],
|
||||
pushkey: [
|
||||
'',
|
||||
[Validators.required, Validators.pattern(/^[a-zA-Z\d]{41}$/)],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
get serverControl() {
|
||||
return this.settingsForm.get('server') as FormControl;
|
||||
}
|
||||
|
||||
get pushkeyControl() {
|
||||
return this.settingsForm.get('pushkey') as FormControl;
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.syncStatus = mapValues(this.settings, () => true);
|
||||
this.settingsForm.setValue(this.settings);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.settingsSyncService
|
||||
.syncSettings(
|
||||
'pushdeerNotification',
|
||||
this.settings,
|
||||
this.settingsForm.valueChanges.pipe(
|
||||
filterValueChanges<Partial<PushdeerSettings>>(this.settingsForm)
|
||||
)
|
||||
)
|
||||
.subscribe((detail) => {
|
||||
this.syncStatus = { ...this.syncStatus, ...calcSyncStatus(detail) };
|
||||
this.changeDetector.markForCheck();
|
||||
});
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ export class EventSettingsComponent implements OnInit, OnChanges {
|
||||
@Input() keyOfSettings!:
|
||||
| 'emailNotification'
|
||||
| 'serverchanNotification'
|
||||
| 'pushdeerNotification'
|
||||
| 'pushplusNotification'
|
||||
| 'telegramNotification';
|
||||
|
||||
|
@ -30,6 +30,7 @@ export class NotifierSettingsComponent implements OnInit, OnChanges {
|
||||
@Input() keyOfSettings!:
|
||||
| 'emailNotification'
|
||||
| 'serverchanNotification'
|
||||
| 'pushdeerNotification'
|
||||
| 'pushplusNotification'
|
||||
| 'telegramNotification';
|
||||
|
||||
|
@ -6,10 +6,12 @@ import { EmailNotificationSettingsResolver } from './shared/services/email-notif
|
||||
import { PushplusNotificationSettingsResolver } from './shared/services/pushplus-notification-settings.resolver';
|
||||
import { TelegramNotificationSettingsResolver } from './shared/services/telegram-notification-settings.resolver';
|
||||
import { ServerchanNotificationSettingsResolver } from './shared/services/serverchan-notification-settings.resolver';
|
||||
import { PushdeerNotificationSettingsResolver } from './shared/services/pushdeer-notification-settings.resolver';
|
||||
import { WebhookSettingsResolver } from './shared/services/webhook-settings.resolver';
|
||||
import { SettingsComponent } from './settings.component';
|
||||
import { EmailNotificationSettingsComponent } from './notification-settings/email-notification-settings/email-notification-settings.component';
|
||||
import { ServerchanNotificationSettingsComponent } from './notification-settings/serverchan-notification-settings/serverchan-notification-settings.component';
|
||||
import { PushdeerNotificationSettingsComponent } from './notification-settings/pushdeer-notification-settings/pushdeer-notification-settings.component';
|
||||
import { PushplusNotificationSettingsComponent } from './notification-settings/pushplus-notification-settings/pushplus-notification-settings.component';
|
||||
import { TelegramNotificationSettingsComponent } from './notification-settings/telegram-notification-settings/telegram-notification-settings.component';
|
||||
import { WebhookManagerComponent } from './webhook-settings/webhook-manager/webhook-manager.component';
|
||||
@ -29,6 +31,13 @@ const routes: Routes = [
|
||||
settings: ServerchanNotificationSettingsResolver,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'pushdeer-notification',
|
||||
component: PushdeerNotificationSettingsComponent,
|
||||
resolve: {
|
||||
settings: PushdeerNotificationSettingsResolver,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'pushplus-notification',
|
||||
component: PushplusNotificationSettingsComponent,
|
||||
|
@ -27,6 +27,7 @@ import { SharedModule } from '../shared/shared.module';
|
||||
import { SettingsResolver } from './shared/services/settings.resolver';
|
||||
import { EmailNotificationSettingsResolver } from './shared/services/email-notification-settings.resolver';
|
||||
import { ServerchanNotificationSettingsResolver } from './shared/services/serverchan-notification-settings.resolver';
|
||||
import { PushdeerNotificationSettingsResolver } from './shared/services/pushdeer-notification-settings.resolver';
|
||||
import { PushplusNotificationSettingsResolver } from './shared/services/pushplus-notification-settings.resolver';
|
||||
import { TelegramNotificationSettingsResolver } from './shared/services/telegram-notification-settings.resolver';
|
||||
import { WebhookSettingsResolver } from './shared/services/webhook-settings.resolver';
|
||||
@ -49,6 +50,8 @@ import { EmailNotificationSettingsComponent } from './notification-settings/emai
|
||||
import { EmailSettingsComponent } from './notification-settings/email-notification-settings/email-settings/email-settings.component';
|
||||
import { ServerchanNotificationSettingsComponent } from './notification-settings/serverchan-notification-settings/serverchan-notification-settings.component';
|
||||
import { ServerchanSettingsComponent } from './notification-settings/serverchan-notification-settings/serverchan-settings/serverchan-settings.component';
|
||||
import { PushdeerNotificationSettingsComponent } from './notification-settings/pushdeer-notification-settings/pushdeer-notification-settings.component';
|
||||
import { PushdeerSettingsComponent } from './notification-settings/pushdeer-notification-settings/pushdeer-settings/pushdeer-settings.component';
|
||||
import { PushplusNotificationSettingsComponent } from './notification-settings/pushplus-notification-settings/pushplus-notification-settings.component';
|
||||
import { PushplusSettingsComponent } from './notification-settings/pushplus-notification-settings/pushplus-settings/pushplus-settings.component';
|
||||
import { TelegramNotificationSettingsComponent } from './notification-settings/telegram-notification-settings/telegram-notification-settings.component';
|
||||
@ -81,6 +84,8 @@ import { PathTemplateEditDialogComponent } from './output-settings/path-template
|
||||
EmailSettingsComponent,
|
||||
ServerchanNotificationSettingsComponent,
|
||||
ServerchanSettingsComponent,
|
||||
PushdeerNotificationSettingsComponent,
|
||||
PushdeerSettingsComponent,
|
||||
PushplusNotificationSettingsComponent,
|
||||
PushplusSettingsComponent,
|
||||
TelegramNotificationSettingsComponent,
|
||||
@ -125,6 +130,7 @@ import { PathTemplateEditDialogComponent } from './output-settings/path-template
|
||||
SettingsResolver,
|
||||
EmailNotificationSettingsResolver,
|
||||
ServerchanNotificationSettingsResolver,
|
||||
PushdeerNotificationSettingsResolver,
|
||||
PushplusNotificationSettingsResolver,
|
||||
TelegramNotificationSettingsResolver,
|
||||
WebhookSettingsResolver,
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PushdeerNotificationSettingsResolver } from './pushdeer-notification-settings.resolver';
|
||||
|
||||
describe('PushdeerNotificationSettingsResolver', () => {
|
||||
let service: PushdeerNotificationSettingsResolver;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(PushdeerNotificationSettingsResolver);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
Resolve,
|
||||
RouterStateSnapshot,
|
||||
} from '@angular/router';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { NzNotificationService } from 'ng-zorro-antd/notification';
|
||||
|
||||
import { retry } from '../../../shared/rx-operators';
|
||||
import { PushdeerNotificationSettings } from '../setting.model';
|
||||
import { SettingService } from './setting.service';
|
||||
|
||||
@Injectable()
|
||||
export class PushdeerNotificationSettingsResolver
|
||||
implements Resolve<PushdeerNotificationSettings>
|
||||
{
|
||||
constructor(
|
||||
private logger: NGXLogger,
|
||||
private notification: NzNotificationService,
|
||||
private settingService: SettingService
|
||||
) {}
|
||||
resolve(
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
): Observable<PushdeerNotificationSettings> {
|
||||
return this.settingService.getSettings(['pushdeerNotification']).pipe(
|
||||
map((settings) => settings.pushdeerNotification),
|
||||
retry(3, 300),
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
this.logger.error(
|
||||
'Failed to get PushDeer notification settings:',
|
||||
error
|
||||
);
|
||||
this.notification.error('获取 pushdeer 通知设置出错', error.message, {
|
||||
nzDuration: 0,
|
||||
});
|
||||
throw error;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -127,6 +127,13 @@ export interface ServerchanSettings {
|
||||
|
||||
export const KEYS_OF_SERVERCHAN_SETTINGS = ['sendkey'] as const;
|
||||
|
||||
export interface PushdeerSettings {
|
||||
server: string;
|
||||
pushkey: string;
|
||||
}
|
||||
|
||||
export const KEYS_OF_PUSHDEER_SETTINGS = ['server', 'pushkey'] as const;
|
||||
|
||||
export interface PushplusSettings {
|
||||
token: string;
|
||||
topic: string;
|
||||
@ -169,6 +176,10 @@ export type ServerchanNotificationSettings = ServerchanSettings &
|
||||
NotifierSettings &
|
||||
NotificationSettings;
|
||||
|
||||
export type PushdeerNotificationSettings = PushdeerSettings &
|
||||
NotifierSettings &
|
||||
NotificationSettings;
|
||||
|
||||
export type PushplusNotificationSettings = PushplusSettings &
|
||||
NotifierSettings &
|
||||
NotificationSettings;
|
||||
@ -211,6 +222,7 @@ export interface Settings {
|
||||
space: SpaceSettings;
|
||||
emailNotification: EmailNotificationSettings;
|
||||
serverchanNotification: ServerchanNotificationSettings;
|
||||
pushdeerNotification: PushdeerNotificationSettings;
|
||||
pushplusNotification: PushplusNotificationSettings;
|
||||
telegramNotification: TelegramNotificationSettings;
|
||||
webhooks: WebhookSettings[];
|
||||
|
Loading…
Reference in New Issue
Block a user