Skip to content

Commit

Permalink
feat: notice_config access messenger (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
simontigers authored Oct 9, 2023
1 parent f7f3543 commit 065e29e
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 42 deletions.
2 changes: 1 addition & 1 deletion cmdb-api/api/commands/click_common_setting.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def init_backend_resource(self):
else:
resource_type = results[0]

for name in ['公司信息']:
for name in ['公司信息', '通知设置']:
payload = dict(
type_id=resource_type['id'],
app_id=acl.app_name,
Expand Down
28 changes: 24 additions & 4 deletions cmdb-api/api/lib/common_setting/company_info.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding:utf-8 -*-

from api.extensions import cache
from api.models.common_setting import CompanyInfo


Expand All @@ -11,14 +11,34 @@ def get():

@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)
7 changes: 7 additions & 0 deletions cmdb-api/api/lib/common_setting/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ class OperatorType(BaseEnum):
LESS_THAN = 6
IS_EMPTY = 7
IS_NOT_EMPTY = 8


BotNameMap = {
'wechatApp': 'wechatBot',
'feishuApp': 'feishuBot',
'dingdingApp': 'dingdingBot',
}
55 changes: 54 additions & 1 deletion cmdb-api/api/lib/common_setting/employee.py
Original file line number Diff line number Diff line change
@@ -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_
Expand Down Expand Up @@ -474,6 +475,58 @@ def get_employees_by_department_id(department_id, block):

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 = [
Expand Down
143 changes: 107 additions & 36 deletions cmdb-api/api/lib/common_setting/notice_config.py
Original file line number Diff line number Diff line change
@@ -1,80 +1,151 @@
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():
return NoticeConfig.get_by(to_dict=True)

@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=[
Expand All @@ -91,4 +162,4 @@ class NoticeConfigUpdateForm(Form):
info = StringField(validators=[
validators.DataRequired(message="信息 不能为空"),
validators.Length(max=255),
])
])
7 changes: 7 additions & 0 deletions cmdb-api/api/lib/common_setting/resp_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "解绑成功"
12 changes: 12 additions & 0 deletions cmdb-api/api/views/common_setting/employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,15 @@ def post(self):
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)
8 changes: 8 additions & 0 deletions cmdb-api/api/views/common_setting/notice_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 065e29e

Please sign in to comment.