ad-password-self-service/utils/feishu/dt_message.py

315 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding: utf-8
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
from typing import TYPE_CHECKING, Any, Dict, List
import attr
from utils.feishu.dt_enum import ImageColor
from utils.feishu.dt_help import to_json_decorator
from utils.feishu.exception import LarkInvalidArguments
if TYPE_CHECKING:
from six import string_types
# 文字图片atlink这四个在post和card中都有做统一处理
# 富文本https://lark-open.bytedance.net/document/ukTMukTMukTM/uMDMxEjLzATMx4yMwETM
# 卡片https://lark-open.bytedance.net/document/ukTMukTMukTM/uUzMxEjL1MTMx4SNzETM
@to_json_decorator
@attr.s
class I18nText(object):
text = attr.ib(type=str, default=None)
zh_cn = attr.ib(type=str, default=None) # 如果设置了,那么国际化中文环境会显示
en_us = attr.ib(type=str, default=None) # 如果设置了,那么国际化日文环境会显示
ja_jp = attr.ib(type=str, default=None) # 如果设置了,那么国际化英文环境会显示
def as_dict(self):
return {
'text': self.text,
'i18n': {
'zh_cn': self.zh_cn or self.text,
'en_us': self.en_us or self.text,
'ja_jp': self.ja_jp or self.text,
}
}
@to_json_decorator
@attr.s
class MessageText(object):
text = attr.ib(type=str, default=None)
zh_cn = attr.ib(type=str, default=None) # card 格式有效:如果设置了,那么国际化中文环境会显示
en_us = attr.ib(type=str, default=None) # card 格式有效:如果设置了,那么国际化日文环境会显示
ja_jp = attr.ib(type=str, default=None) # card 格式有效:如果设置了,那么国际化英文环境会显示
lines = attr.ib(type=int, default=None) # 只能在富文本消息中起作用,最大显示行数
un_escape = attr.ib(type=bool, default=None) # 只能在富文本消息中起作用,表示为 unescape 解码
def as_post_dict(self):
if self.zh_cn or self.en_us or self.ja_jp:
logging.warning('zh_cn or en_us or ja_jp is for card text')
text = ''
for i in [self.text, self.zh_cn, self.en_us, self.ja_jp]:
if i is not None:
text = i
break
d = {
'tag': 'text',
'text': text,
}
for i in ['un_escape', 'lines']:
r = getattr(self, i)
if r is not None:
d[i] = r
return d
def as_card_dict(self):
if self.lines is not None:
logging.warning('lines is for post text')
if self.un_escape is not None:
logging.warning('un_escape is for post text')
return {
'tag': 'text',
'text': self.text,
'i18n': {
'zh_cn': self.zh_cn or self.text,
'en_us': self.en_us or self.text,
'ja_jp': self.ja_jp or self.text,
}
}
@to_json_decorator
@attr.s
class MessageAt(object):
"""富文本的at消息
"""
user_id = attr.ib(type=str, default=None) # open_id 或者 employee_id
text = attr.ib(type=str, default=None) # 用户名
def as_dict(self):
return {
'tag': 'at',
'user_id': self.user_id,
'text': self.text,
}
as_post_dict = as_dict
as_card_dict = as_dict
@to_json_decorator
@attr.s
class MessageImage(object):
"""富文本的图片消息
"""
# 图片的唯一标识,可以通过图片上传接口获得: https://lark-open.bytedance.net/document/ukTMukTMukTM/uEDO04SM4QjLxgDN
image_key = attr.ib(type=str, default=None)
height = attr.ib(type=int, default=None) # 图片的宽
width = attr.ib(type=int, default=None) # 图片的高
def as_dict(self):
return {
'tag': 'img',
'image_key': self.image_key,
'height': self.height,
'width': self.width
}
as_post_dict = as_dict
as_card_dict = as_dict
@to_json_decorator
@attr.s
class MessageLink(object):
text = attr.ib(type=str, default=None)
href = attr.ib(type=str, default=None) # 默认的链接地址,如果这个没有写,从下面三个取一个
un_escape = attr.ib(type=bool, default=None)
# 以下配置只在 card 有效
zh_cn = attr.ib(type=str, default=None) # card有效如果设置了那么国际化中文环境会显示
en_us = attr.ib(type=str, default=None) # card有效如果设置了那么国际化日文环境会显示
ja_jp = attr.ib(type=str, default=None) # card有效如果设置了那么国际化英文环境会显示
pc_href = attr.ib(type=str, default=None) # card有效PC 端的链接地址
ios_href = attr.ib(type=str, default=None) # card有效iOS 端的链接地址
android_href = attr.ib(type=str, default=None) # card有效Android 端的链接地址
def as_post_dict(self):
i18n_text = self.zh_cn or self.en_us or self.ja_jp
if i18n_text:
logging.warning('zh_cn or en_us or ja_jp is for card text')
multi_platform_href = self.pc_href or self.ios_href or self.android_href
if multi_platform_href:
logging.warning('pc_href or ios_href or android_href is for card text')
text = self.text or i18n_text
if text is None:
raise LarkInvalidArguments(msg='[message] empty text')
href = self.href or multi_platform_href
if href is None:
raise LarkInvalidArguments(msg='[message] empty href')
d = {
'tag': 'a',
'text': text,
'href': href,
} # type: Dict[string_types, Any]
if self.un_escape is not None:
d['un_escape'] = self.un_escape
return d
def as_card_dict(self):
return {
'tag': 'a',
'text': self.text,
'i18n': {
'zh_cn': self.zh_cn or self.text,
'en_us': self.en_us or self.text,
'ja_jp': self.ja_jp or self.text,
},
'href': {
'href': self.href,
'pc_href': self.pc_href,
'ios_href': self.ios_href,
'android_href': self.android_href,
}
}
@to_json_decorator
@attr.s
class CardURL(object):
"""多设备 URL
"""
href = attr.ib(type=str, default=None) # 默认的链接地址,如果这个没有写,从下面三个取一个
pc_href = attr.ib(type=str, default=None) # PC 端的链接地址
ios_href = attr.ib(type=str, default=None) # iOS 端的链接地址
android_href = attr.ib(type=str, default=None) # Android 端的链接地址
def as_card_dict(self):
d = {'href': self.href}
for i in ['pc_href', 'ios_href', 'android_href']:
href = getattr(self, i)
if not href:
continue
d[i] = href
if not d['href']:
d['href'] = href
return d
def as_button_dict(self):
d = {}
if self.pc_href:
d['pc_url'] = self.pc_href or self.href
if self.ios_href:
d['ios_url'] = self.ios_href or self.href
if self.android_href:
d['android_url'] = self.android_href or self.href
return d
@to_json_decorator
@attr.s
class CardHeader(object):
title = attr.ib(type=str, default=None) # 显示的默认的文本内容,如果设置了 i18n 内容,会优先显示 i18n 里面对应的语种内容
zh_cn = attr.ib(type=str, default=None) # 如果设置了,那么国际化中文环境会显示
en_us = attr.ib(type=str, default=None) # 如果设置了,那么国际化日文环境会显示
ja_jp = attr.ib(type=str, default=None) # 如果设置了,那么国际化英文环境会显示
# 标题前图标的颜色。可选范围:[orange, red, yellow, gray, blue, green] 默认为 red
image_color = attr.ib(type=ImageColor, default=ImageColor.red)
lines = attr.ib(type=int, default=None) # 指定文本最大显示行数0 表示不限行数
def as_dict(self):
d = {'title': self.title, 'image_color': self.image_color.value}
if self.lines:
d['lines'] = self.lines
if self.zh_cn or self.en_us or self.ja_jp:
d['i18n'] = {
'zh_cn': self.zh_cn or self.title,
'en_us': self.en_us or self.title,
'ja_jp': self.ja_jp or self.title,
}
return d
@to_json_decorator
@attr.s
class CardButton(object):
text = attr.ib(type=str, default=None)
# 发送 post 请求
method = attr.ib(type=str, default=None)
# 请求或者跳转的地址
url = attr.ib(type=str, default=None)
# 标题的 i18n
text_i18n = attr.ib(type=I18nText, default=None)
# 点击按钮以后显示的默认的文本内容,仅在 method 是 post 或 get 时候才有效
triggered_text = attr.ib(type=str, default=None)
# 点击按钮以后国际化内容的字段,仅在 method 是 post 或 get 时候才有效
triggered_i18n = attr.ib(type=I18nText, default=None)
# 为 true 时,请求参数会带上 open_id 或者 employee_id仅在 method 是 post 时候才有效
need_user_info = attr.ib(type=bool, default=None)
# 为 true 时,请求参数会带上 open_message_id仅在 method 是 post 时候才有效
need_message_info = attr.ib(type=bool, default=None)
# 开发者自定义的请求参数,仅在 method 是 post 时候才有效
parameter = attr.ib(type=Any, default=None)
# 可包含 pc_url, ios_url, android_url, 仅在 method 是 jump 时候才有效. 如果配置了该字段, 则在相应端上优先使用指定的链接
open_url = attr.ib(type=CardURL, default=None)
# 配置是否点击成功后,需要将其它按钮隐藏,仅在 method 是 post 或 get 时候才有效
hide_others = attr.ib(type=bool, default=None)
def as_dict(self):
d = {
'text': self.text,
'method': self.method,
'url': self.url,
} # type: Dict[string_types, Any]
if self.text_i18n:
d['i18n'] = self.text_i18n.as_dict()
if self.triggered_i18n:
d['triggered_i18n'] = self.triggered_i18n.as_dict()
if self.open_url:
d['open_url'] = self.open_url.as_button_dict()
for i in ['triggered_text', 'need_user_info', 'need_message_info', 'parameter', 'hide_others']:
r = getattr(self, i, None)
if r is not None:
d[i] = r
return d
as_post_dict = as_dict
as_card_dict = as_dict
@to_json_decorator
@attr.s
class CardAction(object):
buttons = attr.ib(type=List[CardButton], default=None) # type: List[CardButton]
changeable = attr.ib(type=bool, default=None)
def as_dict(self):
d = {'buttons': [i.as_dict() for i in self.buttons]} # type: Dict[string_types, Any]
if self.changeable is not None:
d['changeable'] = self.changeable
return d