You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jumpserver/apps/notifications/notifications.py

186 lines
4.9 KiB

from typing import Iterable
import traceback
from itertools import chain
import time
from celery import shared_task
from django.utils.translation import gettext_lazy as _
from common.utils.timezone import now
from common.utils import lazyproperty
from users.models import User
from notifications.backends import BACKEND
from .models import SystemMsgSubscription, UserMsgSubscription
__all__ = ('SystemMessage', 'UserMessage', 'system_msgs')
system_msgs = []
user_msgs = []
class MessageType(type):
def __new__(cls, name, bases, attrs: dict):
clz = type.__new__(cls, name, bases, attrs)
if 'message_type_label' in attrs \
and 'category' in attrs \
and 'category_label' in attrs:
message_type = clz.get_message_type()
msg = {
'message_type': message_type,
'message_type_label': attrs['message_type_label'],
'category': attrs['category'],
'category_label': attrs['category_label'],
}
if issubclass(clz, SystemMessage):
system_msgs.append(msg)
elif issubclass(clz, UserMessage):
user_msgs.append(msg)
return clz
@shared_task
def publish_task(msg):
msg.publish()
class Message(metaclass=MessageType):
"""
这里封装了什么
封装不同消息的模板提供统一的发送消息的接口
- publish 该方法的实现与消息订阅的表结构有关
- send_msg
"""
message_type_label: str
category: str
category_label: str
@classmethod
def get_message_type(cls):
return cls.__name__
def publish_async(self):
return publish_task.delay(self)
def publish(self):
raise NotImplementedError
def send_msg(self, users: Iterable, backends: Iterable = BACKEND):
backends = set(backends)
backends.add(BACKEND.SITE_MSG) # 站内信必须发
for backend in backends:
try:
backend = BACKEND(backend)
if not backend.is_enable:
continue
get_msg_method = getattr(self, f'get_{backend}_msg', self.get_common_msg)
try:
msg = get_msg_method()
except NotImplementedError:
continue
client = backend.client()
client.send_msg(users, **msg)
except:
traceback.print_exc()
def send_test_msg(self):
from users.models import User
users = User.objects.filter(username='admin')
self.send_msg(users, [])
def get_common_msg(self) -> dict:
raise NotImplementedError
def get_text_msg(self) -> dict:
return self.common_msg
def get_html_msg(self) -> dict:
return self.common_msg
@lazyproperty
def common_msg(self) -> dict:
return self.get_common_msg()
@lazyproperty
def text_msg(self) -> dict:
return self.get_text_msg()
@lazyproperty
def html_msg(self) -> dict:
return self.get_html_msg()
# --------------------------------------------------------------
# 支持不同发送消息的方式定义自己的消息内容,比如有些支持 html 标签
def get_dingtalk_msg(self) -> dict:
# 钉钉相同的消息一天只能发一次,所以给所有消息添加基于时间的序号,使他们不相同
message = self.text_msg['message']
suffix = _('\nTime: {}').format(now())
return {
'subject': self.text_msg['subject'],
'message': message + suffix
}
def get_wecom_msg(self) -> dict:
return self.text_msg
def get_feishu_msg(self) -> dict:
return self.text_msg
def get_email_msg(self) -> dict:
return self.html_msg
def get_site_msg_msg(self) -> dict:
return self.html_msg
def get_sms_msg(self) -> dict:
return self.text_msg
# --------------------------------------------------------------
class SystemMessage(Message):
def publish(self):
subscription = SystemMsgSubscription.objects.get(
message_type=self.get_message_type()
)
# 只发送当前有效后端
receive_backends = subscription.receive_backends
receive_backends = BACKEND.filter_enable_backends(receive_backends)
users = [
*subscription.users.all(),
*chain(*[g.users.all() for g in subscription.groups.all()])
]
self.send_msg(users, receive_backends)
@classmethod
def post_insert_to_db(cls, subscription: SystemMsgSubscription):
pass
class UserMessage(Message):
user: User
def __init__(self, user):
self.user = user
def publish(self):
"""
发送消息到每个用户配置的接收方式上
"""
sub = UserMsgSubscription.objects.get(user=self.user)
self.send_msg([self.user], sub.receive_backends)