mirror of https://github.com/veops/cmdb.git
feat: notice_config access messenger (#190)
This commit is contained in:
parent
ccce5c830a
commit
297270063c
|
@ -177,7 +177,7 @@ class InitDepartment(object):
|
||||||
else:
|
else:
|
||||||
resource_type = results[0]
|
resource_type = results[0]
|
||||||
|
|
||||||
for name in ['公司信息']:
|
for name in ['公司信息', '通知设置']:
|
||||||
payload = dict(
|
payload = dict(
|
||||||
type_id=resource_type['id'],
|
type_id=resource_type['id'],
|
||||||
app_id=acl.app_name,
|
app_id=acl.app_name,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
from api.extensions import cache
|
||||||
from api.models.common_setting import CompanyInfo
|
from api.models.common_setting import CompanyInfo
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,14 +11,34 @@ class CompanyInfoCRUD(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(**kwargs):
|
def create(**kwargs):
|
||||||
return CompanyInfo.create(**kwargs)
|
res = CompanyInfo.create(**kwargs)
|
||||||
|
CompanyInfoCache.refresh(res.info)
|
||||||
|
return res
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update(_id, **kwargs):
|
def update(_id, **kwargs):
|
||||||
kwargs.pop('id', None)
|
kwargs.pop('id', None)
|
||||||
existed = CompanyInfo.get_by_id(_id)
|
existed = CompanyInfo.get_by_id(_id)
|
||||||
if not existed:
|
if not existed:
|
||||||
return CompanyInfoCRUD.create(**kwargs)
|
existed = CompanyInfoCRUD.create(**kwargs)
|
||||||
else:
|
else:
|
||||||
existed = existed.update(**kwargs)
|
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
|
LESS_THAN = 6
|
||||||
IS_EMPTY = 7
|
IS_EMPTY = 7
|
||||||
IS_NOT_EMPTY = 8
|
IS_NOT_EMPTY = 8
|
||||||
|
|
||||||
|
|
||||||
|
BotNameMap = {
|
||||||
|
'wechatApp': 'wechatBot',
|
||||||
|
'feishuApp': 'feishuBot',
|
||||||
|
'dingdingApp': 'dingdingBot',
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
import copy
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
import requests
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from sqlalchemy import or_, literal_column, func, not_, and_
|
from sqlalchemy import or_, literal_column, func, not_, and_
|
||||||
|
@ -474,6 +475,58 @@ class EmployeeCRUD(object):
|
||||||
|
|
||||||
return [r.to_dict() for r in results]
|
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
|
@staticmethod
|
||||||
def get_employee_notice_by_ids(employee_ids):
|
def get_employee_notice_by_ids(employee_ids):
|
||||||
criterion = [
|
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 Form
|
||||||
from wtforms import StringField
|
from wtforms import StringField
|
||||||
from wtforms import validators
|
from wtforms import validators
|
||||||
from flask import abort
|
from flask import abort, current_app
|
||||||
import smtplib
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
from email.utils import formataddr
|
|
||||||
|
|
||||||
|
|
||||||
class NoticeConfigCRUD(object):
|
class NoticeConfigCRUD(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_notice_config(**kwargs):
|
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:
|
try:
|
||||||
return NoticeConfig.create(
|
NoticeConfigCRUD.update_messenger_config(**info)
|
||||||
|
res = NoticeConfig.create(
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
return res
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return abort(400, str(e))
|
return abort(400, str(e))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_platform(platform):
|
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
|
@staticmethod
|
||||||
def edit_notice_config(_id, **kwargs):
|
def edit_notice_config(_id, **kwargs):
|
||||||
existed = NoticeConfigCRUD.get_notice_config_by_id(_id)
|
existed = NoticeConfigCRUD.get_notice_config_by_id(_id)
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
return abort(400, str(e))
|
return abort(400, str(e))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_notice_config_by_id(_id):
|
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
|
@staticmethod
|
||||||
def get_all():
|
def get_all():
|
||||||
|
@ -43,38 +106,46 @@ class NoticeConfigCRUD(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_send_email(receive_address, **kwargs):
|
def test_send_email(receive_address, **kwargs):
|
||||||
# 设置发送方和接收方的电子邮件地址
|
messenger = NoticeConfigCRUD.get_messenger_url()
|
||||||
sender_email = 'test@test.com'
|
if not messenger or len(messenger) == 0:
|
||||||
sender_name = 'Test Sender'
|
abort(400, ErrFormat.notice_please_config_messenger_first)
|
||||||
|
url = f"{messenger}/v1/message"
|
||||||
|
|
||||||
recipient_email = receive_address
|
recipient_email = receive_address
|
||||||
recipient_name = receive_address
|
|
||||||
|
|
||||||
subject = 'Test Email'
|
subject = 'Test Email'
|
||||||
body = 'This is a test email'
|
body = 'This is a test email'
|
||||||
|
payload = {
|
||||||
message = MIMEText(body, 'plain', 'utf-8')
|
"sender": 'email',
|
||||||
message['From'] = formataddr((sender_name, sender_email))
|
"msgtype": "text/plain",
|
||||||
message['To'] = formataddr((recipient_name, recipient_email))
|
"title": subject,
|
||||||
message['Subject'] = subject
|
"content": body,
|
||||||
|
"tos": [recipient_email],
|
||||||
smtp_server = kwargs.get('server')
|
}
|
||||||
smtp_port = kwargs.get('port')
|
current_app.logger.info(f"test_send_email: {url}, {payload}")
|
||||||
smtp_username = kwargs.get('username')
|
response = requests.post(url, json=payload)
|
||||||
smtp_password = kwargs.get('password')
|
if response.status_code != 200:
|
||||||
|
abort(400, response.text)
|
||||||
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()
|
|
||||||
|
|
||||||
return 1
|
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):
|
class NoticeConfigForm(Form):
|
||||||
platform = StringField(validators=[
|
platform = StringField(validators=[
|
||||||
|
@ -91,4 +162,4 @@ class NoticeConfigUpdateForm(Form):
|
||||||
info = StringField(validators=[
|
info = StringField(validators=[
|
||||||
validators.DataRequired(message="信息 不能为空"),
|
validators.DataRequired(message="信息 不能为空"),
|
||||||
validators.Length(max=255),
|
validators.Length(max=255),
|
||||||
])
|
])
|
|
@ -56,3 +56,10 @@ class ErrFormat(CommonErrFormat):
|
||||||
email_send_timeout = "邮件发送超时"
|
email_send_timeout = "邮件发送超时"
|
||||||
|
|
||||||
common_data_not_found = "ID {} 找不到记录"
|
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:
|
else:
|
||||||
result = EmployeeCRUD.get_employee_notice_by_ids(employee_ids)
|
result = EmployeeCRUD.get_employee_notice_by_ids(employee_ids)
|
||||||
return self.jsonify(result)
|
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):
|
def get(self):
|
||||||
res = NoticeConfigCRUD.get_all()
|
res = NoticeConfigCRUD.get_all()
|
||||||
return self.jsonify(res)
|
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)
|
||||||
|
|
Loading…
Reference in New Issue