mirror of
				https://github.com/veops/cmdb.git
				synced 2025-11-04 13:46:17 +08:00 
			
		
		
		
	feat: notice_config access messenger (#190)
This commit is contained in:
		@@ -177,7 +177,7 @@ class InitDepartment(object):
 | 
			
		||||
        else:
 | 
			
		||||
            resource_type = results[0]
 | 
			
		||||
 | 
			
		||||
        for name in ['公司信息']:
 | 
			
		||||
        for name in ['公司信息', '通知设置']:
 | 
			
		||||
            payload = dict(
 | 
			
		||||
                type_id=resource_type['id'],
 | 
			
		||||
                app_id=acl.app_name,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
# -*- coding:utf-8 -*-
 | 
			
		||||
 | 
			
		||||
from api.extensions import cache
 | 
			
		||||
from api.models.common_setting import CompanyInfo
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -11,14 +11,34 @@ class CompanyInfoCRUD(object):
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def create(**kwargs):
 | 
			
		||||
        return CompanyInfo.create(**kwargs)
 | 
			
		||||
        res = CompanyInfo.create(**kwargs)
 | 
			
		||||
        CompanyInfoCache.refresh(res.info)
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def update(_id, **kwargs):
 | 
			
		||||
        kwargs.pop('id', None)
 | 
			
		||||
        existed = CompanyInfo.get_by_id(_id)
 | 
			
		||||
        if not existed:
 | 
			
		||||
            return CompanyInfoCRUD.create(**kwargs)
 | 
			
		||||
            existed = CompanyInfoCRUD.create(**kwargs)
 | 
			
		||||
        else:
 | 
			
		||||
            existed = existed.update(**kwargs)
 | 
			
		||||
            return existed
 | 
			
		||||
        CompanyInfoCache.refresh(existed.info)
 | 
			
		||||
        return existed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompanyInfoCache(object):
 | 
			
		||||
    key = 'CompanyInfoCache::'
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get(cls):
 | 
			
		||||
        info = cache.get(cls.key)
 | 
			
		||||
        if not info:
 | 
			
		||||
            res = CompanyInfo.get_by(first=True) or {}
 | 
			
		||||
            info = res.get('info', {})
 | 
			
		||||
            cache.set(cls.key, info)
 | 
			
		||||
        return info
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def refresh(cls, info):
 | 
			
		||||
        cache.set(cls.key, info)
 | 
			
		||||
@@ -12,3 +12,10 @@ class OperatorType(BaseEnum):
 | 
			
		||||
    LESS_THAN = 6
 | 
			
		||||
    IS_EMPTY = 7
 | 
			
		||||
    IS_NOT_EMPTY = 8
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BotNameMap = {
 | 
			
		||||
    'wechatApp': 'wechatBot',
 | 
			
		||||
    'feishuApp': 'feishuBot',
 | 
			
		||||
    'dingdingApp': 'dingdingBot',
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
# -*- coding:utf-8 -*-
 | 
			
		||||
 | 
			
		||||
import copy
 | 
			
		||||
import traceback
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
import requests
 | 
			
		||||
from flask import abort
 | 
			
		||||
from flask_login import current_user
 | 
			
		||||
from sqlalchemy import or_, literal_column, func, not_, and_
 | 
			
		||||
@@ -474,6 +475,58 @@ class EmployeeCRUD(object):
 | 
			
		||||
 | 
			
		||||
        return [r.to_dict() for r in results]
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def remove_bind_notice_by_uid(_platform, _uid):
 | 
			
		||||
        existed = EmployeeCRUD.get_employee_by_uid(_uid)
 | 
			
		||||
        employee_data = existed.to_dict()
 | 
			
		||||
 | 
			
		||||
        notice_info = copy.deepcopy(employee_data.get('notice_info', {}))
 | 
			
		||||
 | 
			
		||||
        notice_info[_platform] = ''
 | 
			
		||||
 | 
			
		||||
        existed.update(
 | 
			
		||||
            notice_info=notice_info
 | 
			
		||||
        )
 | 
			
		||||
        return ErrFormat.notice_remove_bind_success
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def bind_notice_by_uid(_platform, _uid):
 | 
			
		||||
        existed = EmployeeCRUD.get_employee_by_uid(_uid)
 | 
			
		||||
        mobile = existed.mobile
 | 
			
		||||
        if not mobile or len(mobile) == 0:
 | 
			
		||||
            abort(400, ErrFormat.notice_bind_err_with_empty_mobile)
 | 
			
		||||
 | 
			
		||||
        from api.lib.common_setting.notice_config import NoticeConfigCRUD
 | 
			
		||||
        messenger = NoticeConfigCRUD.get_messenger_url()
 | 
			
		||||
        if not messenger or len(messenger) == 0:
 | 
			
		||||
            abort(400, ErrFormat.notice_please_config_messenger_first)
 | 
			
		||||
 | 
			
		||||
        url = f"{messenger}/v1/uid/getbyphone"
 | 
			
		||||
        try:
 | 
			
		||||
            payload = dict(
 | 
			
		||||
                phone=mobile,
 | 
			
		||||
                sender=_platform
 | 
			
		||||
            )
 | 
			
		||||
            res = requests.post(url, json=payload)
 | 
			
		||||
            result = res.json()
 | 
			
		||||
            if res.status_code != 200:
 | 
			
		||||
                raise Exception(result.get('msg', ''))
 | 
			
		||||
            target_id = result.get('uid', '')
 | 
			
		||||
 | 
			
		||||
            employee_data = existed.to_dict()
 | 
			
		||||
 | 
			
		||||
            notice_info = copy.deepcopy(employee_data.get('notice_info', {}))
 | 
			
		||||
 | 
			
		||||
            notice_info[_platform] = '' if not target_id else target_id
 | 
			
		||||
 | 
			
		||||
            existed.update(
 | 
			
		||||
                notice_info=notice_info
 | 
			
		||||
            )
 | 
			
		||||
            return ErrFormat.notice_bind_success
 | 
			
		||||
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            return abort(400, ErrFormat.notice_bind_failed.format(str(e)))
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_employee_notice_by_ids(employee_ids):
 | 
			
		||||
        criterion = [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,41 +1,104 @@
 | 
			
		||||
from api.models.common_setting import NoticeConfig
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from api.lib.common_setting.const import BotNameMap
 | 
			
		||||
from api.lib.common_setting.resp_format import ErrFormat
 | 
			
		||||
from api.models.common_setting import CompanyInfo, NoticeConfig
 | 
			
		||||
from wtforms import Form
 | 
			
		||||
from wtforms import StringField
 | 
			
		||||
from wtforms import validators
 | 
			
		||||
from flask import abort
 | 
			
		||||
import smtplib
 | 
			
		||||
from email.mime.text import MIMEText
 | 
			
		||||
from email.utils import formataddr
 | 
			
		||||
from flask import abort, current_app
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NoticeConfigCRUD(object):
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def add_notice_config(**kwargs):
 | 
			
		||||
        NoticeConfigCRUD.check_platform(kwargs.get('platform'))
 | 
			
		||||
        platform = kwargs.get('platform')
 | 
			
		||||
        NoticeConfigCRUD.check_platform(platform)
 | 
			
		||||
        info = kwargs.get('info', {})
 | 
			
		||||
        if 'name' not in info:
 | 
			
		||||
            info['name'] = platform
 | 
			
		||||
        kwargs['info'] = info
 | 
			
		||||
        try:
 | 
			
		||||
            return NoticeConfig.create(
 | 
			
		||||
            NoticeConfigCRUD.update_messenger_config(**info)
 | 
			
		||||
            res = NoticeConfig.create(
 | 
			
		||||
                **kwargs
 | 
			
		||||
            )
 | 
			
		||||
            return res
 | 
			
		||||
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            return abort(400, str(e))
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def check_platform(platform):
 | 
			
		||||
        NoticeConfig.get_by(first=True, to_dict=False, platform=platform) and abort(400, f"{platform} 已存在!")
 | 
			
		||||
        NoticeConfig.get_by(first=True, to_dict=False, platform=platform) and \
 | 
			
		||||
        abort(400, ErrFormat.notice_platform_existed.format(platform))
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def edit_notice_config(_id, **kwargs):
 | 
			
		||||
        existed = NoticeConfigCRUD.get_notice_config_by_id(_id)
 | 
			
		||||
        try:
 | 
			
		||||
            return existed.update(**kwargs)
 | 
			
		||||
            info = kwargs.get('info', {})
 | 
			
		||||
            if 'name' not in info:
 | 
			
		||||
                info['name'] = existed.platform
 | 
			
		||||
            kwargs['info'] = info
 | 
			
		||||
            NoticeConfigCRUD.update_messenger_config(**info)
 | 
			
		||||
 | 
			
		||||
            res = existed.update(**kwargs)
 | 
			
		||||
            return res
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            return abort(400, str(e))
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_messenger_url():
 | 
			
		||||
        from api.lib.common_setting.company_info import CompanyInfoCache
 | 
			
		||||
        com_info = CompanyInfoCache.get()
 | 
			
		||||
        if not com_info:
 | 
			
		||||
            return
 | 
			
		||||
        messenger = com_info.get('messenger', '')
 | 
			
		||||
        if len(messenger) == 0:
 | 
			
		||||
            return
 | 
			
		||||
        if messenger[-1] == '/':
 | 
			
		||||
            messenger = messenger[:-1]
 | 
			
		||||
        return messenger
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def update_messenger_config(**kwargs):
 | 
			
		||||
        try:
 | 
			
		||||
            messenger = NoticeConfigCRUD.get_messenger_url()
 | 
			
		||||
            if not messenger or len(messenger) == 0:
 | 
			
		||||
                raise Exception(ErrFormat.notice_please_config_messenger_first)
 | 
			
		||||
 | 
			
		||||
            url = f"{messenger}/v1/senders"
 | 
			
		||||
            name = kwargs.get('name')
 | 
			
		||||
            bot_list = kwargs.pop('bot', None)
 | 
			
		||||
            for k, v in kwargs.items():
 | 
			
		||||
                if isinstance(v, bool):
 | 
			
		||||
                    kwargs[k] = 'true' if v else 'false'
 | 
			
		||||
                else:
 | 
			
		||||
                    kwargs[k] = str(v)
 | 
			
		||||
 | 
			
		||||
            payload = {name: [kwargs]}
 | 
			
		||||
            current_app.logger.info(f"update_messenger_config: {url}, {payload}")
 | 
			
		||||
            res = requests.put(url, json=payload, timeout=2)
 | 
			
		||||
            current_app.logger.info(f"update_messenger_config: {res.status_code}, {res.text}")
 | 
			
		||||
 | 
			
		||||
            if not bot_list or len(bot_list) == 0:
 | 
			
		||||
                return
 | 
			
		||||
            bot_name = BotNameMap.get(name)
 | 
			
		||||
            payload = {bot_name: bot_list}
 | 
			
		||||
            current_app.logger.info(f"update_messenger_config: {url}, {payload}")
 | 
			
		||||
            bot_res = requests.put(url, json=payload, timeout=2)
 | 
			
		||||
            current_app.logger.info(f"update_messenger_config: {bot_res.status_code}, {bot_res.text}")
 | 
			
		||||
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            return abort(400, str(e))
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_notice_config_by_id(_id):
 | 
			
		||||
        return NoticeConfig.get_by(first=True, to_dict=False, id=_id) or abort(400, f"{_id} 配置项不存在!")
 | 
			
		||||
        return NoticeConfig.get_by(first=True, to_dict=False, id=_id) or \
 | 
			
		||||
            abort(400,
 | 
			
		||||
                  ErrFormat.notice_not_existed.format(_id))
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_all():
 | 
			
		||||
@@ -43,38 +106,46 @@ class NoticeConfigCRUD(object):
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def test_send_email(receive_address, **kwargs):
 | 
			
		||||
        # 设置发送方和接收方的电子邮件地址
 | 
			
		||||
        sender_email = 'test@test.com'
 | 
			
		||||
        sender_name = 'Test Sender'
 | 
			
		||||
        messenger = NoticeConfigCRUD.get_messenger_url()
 | 
			
		||||
        if not messenger or len(messenger) == 0:
 | 
			
		||||
            abort(400, ErrFormat.notice_please_config_messenger_first)
 | 
			
		||||
        url = f"{messenger}/v1/message"
 | 
			
		||||
 | 
			
		||||
        recipient_email = receive_address
 | 
			
		||||
        recipient_name = receive_address
 | 
			
		||||
 | 
			
		||||
        subject = 'Test Email'
 | 
			
		||||
        body = 'This is a test email'
 | 
			
		||||
 | 
			
		||||
        message = MIMEText(body, 'plain', 'utf-8')
 | 
			
		||||
        message['From'] = formataddr((sender_name, sender_email))
 | 
			
		||||
        message['To'] = formataddr((recipient_name, recipient_email))
 | 
			
		||||
        message['Subject'] = subject
 | 
			
		||||
 | 
			
		||||
        smtp_server = kwargs.get('server')
 | 
			
		||||
        smtp_port = kwargs.get('port')
 | 
			
		||||
        smtp_username = kwargs.get('username')
 | 
			
		||||
        smtp_password = kwargs.get('password')
 | 
			
		||||
 | 
			
		||||
        if kwargs.get('mail_type') == 'SMTP':
 | 
			
		||||
            smtp_connection = smtplib.SMTP(smtp_server, smtp_port)
 | 
			
		||||
        else:
 | 
			
		||||
            smtp_connection = smtplib.SMTP_SSL(smtp_server, smtp_port)
 | 
			
		||||
 | 
			
		||||
        if kwargs.get('is_login'):
 | 
			
		||||
            smtp_connection.login(smtp_username, smtp_password)
 | 
			
		||||
 | 
			
		||||
        smtp_connection.sendmail(sender_email, recipient_email, message.as_string())
 | 
			
		||||
        smtp_connection.quit()
 | 
			
		||||
        payload = {
 | 
			
		||||
            "sender": 'email',
 | 
			
		||||
            "msgtype": "text/plain",
 | 
			
		||||
            "title": subject,
 | 
			
		||||
            "content": body,
 | 
			
		||||
            "tos": [recipient_email],
 | 
			
		||||
        }
 | 
			
		||||
        current_app.logger.info(f"test_send_email: {url}, {payload}")
 | 
			
		||||
        response = requests.post(url, json=payload)
 | 
			
		||||
        if response.status_code != 200:
 | 
			
		||||
            abort(400, response.text)
 | 
			
		||||
 | 
			
		||||
        return 1
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_app_bot():
 | 
			
		||||
        result = []
 | 
			
		||||
        for notice_app in NoticeConfig.get_by(to_dict=False):
 | 
			
		||||
            if notice_app.platform in ['email']:
 | 
			
		||||
                continue
 | 
			
		||||
            info = notice_app.info
 | 
			
		||||
            name = info.get('name', '')
 | 
			
		||||
            if name not in BotNameMap:
 | 
			
		||||
                continue
 | 
			
		||||
            result.append(dict(
 | 
			
		||||
                name=info.get('name', ''),
 | 
			
		||||
                label=info.get('label', ''),
 | 
			
		||||
                bot=info.get('bot', []),
 | 
			
		||||
            ))
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NoticeConfigForm(Form):
 | 
			
		||||
    platform = StringField(validators=[
 | 
			
		||||
@@ -91,4 +162,4 @@ class NoticeConfigUpdateForm(Form):
 | 
			
		||||
    info = StringField(validators=[
 | 
			
		||||
        validators.DataRequired(message="信息 不能为空"),
 | 
			
		||||
        validators.Length(max=255),
 | 
			
		||||
    ])
 | 
			
		||||
    ])
 | 
			
		||||
@@ -56,3 +56,10 @@ class ErrFormat(CommonErrFormat):
 | 
			
		||||
    email_send_timeout = "邮件发送超时"
 | 
			
		||||
 | 
			
		||||
    common_data_not_found = "ID {} 找不到记录"
 | 
			
		||||
    notice_platform_existed = "{} 已存在"
 | 
			
		||||
    notice_not_existed = "{} 配置项不存在"
 | 
			
		||||
    notice_please_config_messenger_first = "请先配置 messenger"
 | 
			
		||||
    notice_bind_err_with_empty_mobile = "绑定失败,手机号为空"
 | 
			
		||||
    notice_bind_failed = "绑定失败: {}"
 | 
			
		||||
    notice_bind_success = "绑定成功"
 | 
			
		||||
    notice_remove_bind_success = "解绑成功"
 | 
			
		||||
 
 | 
			
		||||
@@ -156,3 +156,15 @@ class GetEmployeeNoticeByIds(APIView):
 | 
			
		||||
        else:
 | 
			
		||||
            result = EmployeeCRUD.get_employee_notice_by_ids(employee_ids)
 | 
			
		||||
        return self.jsonify(result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EmployeeBindNoticeWithACLID(APIView):
 | 
			
		||||
    url_prefix = (f'{prefix}/by_uid/bind_notice/<string:platform>/<int:_uid>',)
 | 
			
		||||
 | 
			
		||||
    def put(self, platform, _uid):
 | 
			
		||||
        data = EmployeeCRUD.bind_notice_by_uid(platform, _uid)
 | 
			
		||||
        return self.jsonify(info=data)
 | 
			
		||||
 | 
			
		||||
    def delete(self, platform, _uid):
 | 
			
		||||
        data = EmployeeCRUD.remove_bind_notice_by_uid(platform, _uid)
 | 
			
		||||
        return self.jsonify(info=data)
 | 
			
		||||
 
 | 
			
		||||
@@ -69,3 +69,11 @@ class NoticeConfigGetView(APIView):
 | 
			
		||||
    def get(self):
 | 
			
		||||
        res = NoticeConfigCRUD.get_all()
 | 
			
		||||
        return self.jsonify(res)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NoticeAppBotView(APIView):
 | 
			
		||||
    url_prefix = (f'{prefix}/app_bot',)
 | 
			
		||||
 | 
			
		||||
    def get(self):
 | 
			
		||||
        res = NoticeConfigCRUD.get_app_bot()
 | 
			
		||||
        return self.jsonify(res)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user