优化:飞书群机器人飞书企业应用支持自定义消息卡片模板 #381

优化:`飞书企业应用`支持指定`消息接收者ID类型`
This commit is contained in:
pppscn 2024-01-11 22:53:57 +08:00
parent d48b9d826a
commit 6792a779c3
14 changed files with 447 additions and 33 deletions

View File

@ -2,12 +2,13 @@ package com.idormy.sms.forwarder.entity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.text.TextUtils import android.text.TextUtils
import com.idormy.sms.forwarder.utils.Log import com.google.gson.Gson
import com.idormy.sms.forwarder.App import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.utils.AppUtils import com.idormy.sms.forwarder.utils.AppUtils
import com.idormy.sms.forwarder.utils.BatteryUtils import com.idormy.sms.forwarder.utils.BatteryUtils
import com.idormy.sms.forwarder.utils.HttpServerUtils import com.idormy.sms.forwarder.utils.HttpServerUtils
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.SettingUtils import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.enableSmsTemplate import com.idormy.sms.forwarder.utils.SettingUtils.Companion.enableSmsTemplate
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.extraDeviceMark import com.idormy.sms.forwarder.utils.SettingUtils.Companion.extraDeviceMark
@ -72,6 +73,10 @@ data class MsgInfo(
.replace(getString(R.string.tag_device_name), deviceMark) .replace(getString(R.string.tag_device_name), deviceMark)
.replace(getString(R.string.tag_app_version), versionName) .replace(getString(R.string.tag_app_version), versionName)
.replace(getString(R.string.tag_call_type), callTypeMap[callType.toString()] ?: getString(R.string.unknown_call)) .replace(getString(R.string.tag_call_type), callTypeMap[callType.toString()] ?: getString(R.string.unknown_call))
.replace(getString(R.string.tag_battery_pct), TaskUtils.batteryPct.toString())
.replace(getString(R.string.tag_battery_status), BatteryUtils.getStatus(TaskUtils.batteryStatus))
.replace(getString(R.string.tag_battery_plugged), BatteryUtils.getPlugged(TaskUtils.batteryPlugged))
.replace(getString(R.string.tag_battery_info), TaskUtils.batteryInfo)
.trim() .trim()
return replaceLocationTag(replaceAppName(regexReplace(titleForSend, regexReplace), from)) return replaceLocationTag(replaceAppName(regexReplace(titleForSend, regexReplace), from))
} }
@ -129,6 +134,42 @@ data class MsgInfo(
return replaceLocationTag(replaceAppName(regexReplace(smsVoForSend, regexReplace), from)) return replaceLocationTag(replaceAppName(regexReplace(smsVoForSend, regexReplace), from))
} }
@SuppressLint("SimpleDateFormat")
fun getContentFromJson(jsonTemplate: String): String {
var template = jsonTemplate.replace("null", "")
if (TextUtils.isEmpty(template)) template = getString(R.string.tag_from)
val deviceMark = extraDeviceMark.trim()
val versionName = AppUtils.getAppVersionName()
val splitSimInfo = simInfo.split("#####")
var title = splitSimInfo.getOrElse(0) { simInfo }
title = jsonInnerStr(title)
var scheme = splitSimInfo.getOrElse(1) { "" }
scheme = jsonInnerStr(scheme)
from = jsonInnerStr(from)
content = jsonInnerStr(content)
val msgForSend: String = template.replace(getString(R.string.tag_from), from)
.replace(getString(R.string.tag_package_name), from)
.replace(getString(R.string.tag_sms), content)
.replace(getString(R.string.tag_msg), content)
.replace(getString(R.string.tag_card_slot), title)
.replace(getString(R.string.tag_card_subid), subId.toString())
.replace(getString(R.string.tag_title), title)
.replace(getString(R.string.tag_scheme), scheme)
.replace(getString(R.string.tag_uid), uid.toString())
.replace(getString(R.string.tag_receive_time), jsonInnerStr(SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)))
.replace(getString(R.string.tag_current_time), jsonInnerStr(SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())))
.replace(getString(R.string.tag_device_name), jsonInnerStr(deviceMark))
.replace(getString(R.string.tag_app_version), jsonInnerStr(versionName))
.replace(getString(R.string.tag_call_type), jsonInnerStr(callTypeMap[callType.toString()] ?: getString(R.string.unknown_call)))
.replace(getString(R.string.tag_battery_pct), jsonInnerStr(TaskUtils.batteryPct.toString()))
.replace(getString(R.string.tag_battery_status), jsonInnerStr(BatteryUtils.getStatus(TaskUtils.batteryStatus)))
.replace(getString(R.string.tag_battery_plugged), jsonInnerStr(BatteryUtils.getPlugged(TaskUtils.batteryPlugged)))
.replace(getString(R.string.tag_battery_info), jsonInnerStr(TaskUtils.batteryInfo))
.trim()
return replaceLocationTag(replaceAppName(msgForSend, from, true), true)
}
//正则替换内容 //正则替换内容
private fun regexReplace(content: String, regexReplace: String): String { private fun regexReplace(content: String, regexReplace: String): String {
return if (TextUtils.isEmpty(regexReplace)) content else try { return if (TextUtils.isEmpty(regexReplace)) content else try {
@ -150,7 +191,7 @@ data class MsgInfo(
} }
//替换{{APP名称}}标签 //替换{{APP名称}}标签
private fun replaceAppName(content: String, packageName: String): String { private fun replaceAppName(content: String, packageName: String, needJson: Boolean = false): String {
if (TextUtils.isEmpty(content)) return content if (TextUtils.isEmpty(content)) return content
if (content.indexOf(getString(R.string.tag_app_name)) == -1) return content if (content.indexOf(getString(R.string.tag_app_name)) == -1) return content
@ -171,18 +212,32 @@ data class MsgInfo(
} }
} }
} }
if (needJson) {
appName = jsonInnerStr(appName)
}
return content.replace(getString(R.string.tag_app_name), appName) return content.replace(getString(R.string.tag_app_name), appName)
} }
//替换 {{定位信息}} 标签 //替换 {{定位信息}} 标签
private fun replaceLocationTag(content: String): String { private fun replaceLocationTag(content: String, needJson: Boolean = false): String {
if (TextUtils.isEmpty(content)) return content if (TextUtils.isEmpty(content)) return content
if (content.indexOf(getString(R.string.tag_location)) == -1) return content if (content.indexOf(getString(R.string.tag_location)) == -1) return content
val location = HttpServerUtils.apiLocationCache.toString() var location = HttpServerUtils.apiLocationCache.toString()
if (needJson) {
location = jsonInnerStr(location)
}
return content.replace(getString(R.string.tag_location), location) return content.replace(getString(R.string.tag_location), location)
} }
private fun jsonInnerStr(string: String?): String {
if (string == null) return "null"
if (string == "") return "\"\""
val jsonStr: String = Gson().toJson(string)
return if (jsonStr.length >= 2) jsonStr.substring(1, jsonStr.length - 1) else jsonStr
}
override fun toString(): String { override fun toString(): String {
return "MsgInfo{" + return "MsgInfo{" +
"mobile='" + from + '\'' + "mobile='" + from + '\'' +

View File

@ -10,8 +10,21 @@ data class FeishuAppSetting(
val receiveId: String = "", val receiveId: String = "",
val msgType: String = "interactive", val msgType: String = "interactive",
val titleTemplate: String = "", val titleTemplate: String = "",
val receiveIdType: String = "user_id",
val messageCard: String = "", //自定义消息卡片
) : Serializable { ) : Serializable {
fun getReceiveIdTypeCheckId(): Int {
return when (receiveIdType) {
"open_id" -> R.id.rb_receive_id_type_open_id
"user_id" -> R.id.rb_receive_id_type_user_id
"union_id" -> R.id.rb_receive_id_type_union_id
"email" -> R.id.rb_receive_id_type_email
"chat_id" -> R.id.rb_receive_id_type_chat_id
else -> R.id.rb_receive_id_type_user_id
}
}
fun getMsgTypeCheckId(): Int { fun getMsgTypeCheckId(): Int {
return if (msgType == null || msgType == "interactive") { return if (msgType == null || msgType == "interactive") {
R.id.rb_msg_type_interactive R.id.rb_msg_type_interactive

View File

@ -8,6 +8,7 @@ data class FeishuSetting(
val secret: String? = "", val secret: String? = "",
val msgType: String? = "interactive", val msgType: String? = "interactive",
val titleTemplate: String? = "", val titleTemplate: String? = "",
val messageCard: String = "", //自定义消息卡片
) : Serializable { ) : Serializable {
fun getMsgTypeCheckId(): Int { fun getMsgTypeCheckId(): Int {

View File

@ -328,6 +328,7 @@ class SendersFragment : BaseFragment<FragmentSendersBinding?>(),
.setNewActivity(true) .setNewActivity(true)
.putInt(KEY_SENDER_TYPE, pos) //注意:目前刚好是这个顺序而已 .putInt(KEY_SENDER_TYPE, pos) //注意:目前刚好是这个顺序而已
.open(this) .open(this)
dialog.dismiss()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
Log.e(TAG, "onItemClick error: ${e.message}") Log.e(TAG, "onItemClick error: ${e.message}")

View File

@ -94,6 +94,16 @@ class FeishuAppFragment : BaseFragment<FragmentSendersFeishuAppBinding?>(), View
} }
}) })
binding!!.rgMsgType.setOnCheckedChangeListener { _, checkedId ->
if (checkedId == R.id.rb_msg_type_interactive) {
binding!!.layoutTitleTemplate.visibility = View.VISIBLE
binding!!.layoutMessageCard.visibility = View.VISIBLE
} else {
binding!!.layoutTitleTemplate.visibility = View.GONE
binding!!.layoutMessageCard.visibility = View.GONE
}
}
//新增 //新增
if (senderId <= 0) { if (senderId <= 0) {
titleBar?.setSubTitle(getString(R.string.add_sender)) titleBar?.setSubTitle(getString(R.string.add_sender))
@ -128,16 +138,23 @@ class FeishuAppFragment : BaseFragment<FragmentSendersFeishuAppBinding?>(), View
if (settingVo != null) { if (settingVo != null) {
binding!!.etAppId.setText(settingVo.appId) binding!!.etAppId.setText(settingVo.appId)
binding!!.etAppSecret.setText(settingVo.appSecret) binding!!.etAppSecret.setText(settingVo.appSecret)
binding!!.etUserId.setText(settingVo.receiveId) binding!!.rgReceiveIdType.check(settingVo.getReceiveIdTypeCheckId())
binding!!.etReceiveId.setText(settingVo.receiveId)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId()) binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate) binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
binding!!.etMessageCard.setText(settingVo.messageCard)
} }
} }
}) })
} }
override fun initListeners() { override fun initListeners() {
binding!!.btInsertSenderToTitle.setOnClickListener(this)
binding!!.btInsertExtraToTitle.setOnClickListener(this)
binding!!.btInsertTimeToTitle.setOnClickListener(this)
binding!!.btInsertDeviceNameToTitle.setOnClickListener(this)
binding!!.btInsertSender.setOnClickListener(this) binding!!.btInsertSender.setOnClickListener(this)
binding!!.btInsertContent.setOnClickListener(this)
binding!!.btInsertExtra.setOnClickListener(this) binding!!.btInsertExtra.setOnClickListener(this)
binding!!.btInsertTime.setOnClickListener(this) binding!!.btInsertTime.setOnClickListener(this)
binding!!.btInsertDeviceName.setOnClickListener(this) binding!!.btInsertDeviceName.setOnClickListener(this)
@ -151,27 +168,53 @@ class FeishuAppFragment : BaseFragment<FragmentSendersFeishuAppBinding?>(), View
override fun onClick(v: View) { override fun onClick(v: View) {
try { try {
val etTitleTemplate: EditText = binding!!.etTitleTemplate val etTitleTemplate: EditText = binding!!.etTitleTemplate
val etMessageCard: EditText = binding!!.etMessageCard
when (v.id) { when (v.id) {
R.id.bt_insert_sender -> { R.id.bt_insert_sender_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from))
return return
} }
R.id.bt_insert_extra -> { R.id.bt_insert_extra_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot))
return return
} }
R.id.bt_insert_time -> { R.id.bt_insert_time_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time))
return return
} }
R.id.bt_insert_device_name -> { R.id.bt_insert_device_name_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name))
return return
} }
R.id.bt_insert_sender -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_from))
return
}
R.id.bt_insert_content -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_sms))
return
}
R.id.bt_insert_extra -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_card_slot))
return
}
R.id.bt_insert_time -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_receive_time))
return
}
R.id.bt_insert_device_name -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_device_name))
return
}
R.id.btn_test -> { R.id.btn_test -> {
mCountDownHelper?.start() mCountDownHelper?.start()
Thread { Thread {
@ -239,15 +282,24 @@ class FeishuAppFragment : BaseFragment<FragmentSendersFeishuAppBinding?>(), View
private fun checkSetting(): FeishuAppSetting { private fun checkSetting(): FeishuAppSetting {
val appId = binding!!.etAppId.text.toString().trim() val appId = binding!!.etAppId.text.toString().trim()
val appSecret = binding!!.etAppSecret.text.toString().trim() val appSecret = binding!!.etAppSecret.text.toString().trim()
val receiveId = binding!!.etUserId.text.toString().trim() val receiveId = binding!!.etReceiveId.text.toString().trim()
if (TextUtils.isEmpty(appId) || TextUtils.isEmpty(appSecret) || TextUtils.isEmpty(receiveId)) { if (TextUtils.isEmpty(appId) || TextUtils.isEmpty(appSecret) || TextUtils.isEmpty(receiveId)) {
throw Exception(getString(R.string.invalid_feishu_app_parameter)) throw Exception(getString(R.string.invalid_feishu_app_parameter))
} }
val receiveIdType = when (binding!!.rgReceiveIdType.checkedRadioButtonId) {
R.id.rb_receive_id_type_open_id -> "open_id"
R.id.rb_receive_id_type_user_id -> "user_id"
R.id.rb_receive_id_type_union_id -> "union_id"
R.id.rb_receive_id_type_email -> "email"
R.id.rb_receive_id_type_chat_id -> "chat_id"
else -> "user_id"
}
val msgType = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_interactive) "interactive" else "text" val msgType = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_interactive) "interactive" else "text"
val title = binding!!.etTitleTemplate.text.toString().trim() val title = binding!!.etTitleTemplate.text.toString().trim()
val messageCard = binding!!.etMessageCard.text.toString().trim()
return FeishuAppSetting(appId, appSecret, receiveId, msgType, title) return FeishuAppSetting(appId, appSecret, receiveId, msgType, title, receiveIdType, messageCard)
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -94,6 +94,16 @@ class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnCli
} }
}) })
binding!!.rgMsgType.setOnCheckedChangeListener { _, checkedId ->
if (checkedId == R.id.rb_msg_type_interactive) {
binding!!.layoutTitleTemplate.visibility = View.VISIBLE
binding!!.layoutMessageCard.visibility = View.VISIBLE
} else {
binding!!.layoutTitleTemplate.visibility = View.GONE
binding!!.layoutMessageCard.visibility = View.GONE
}
}
//新增 //新增
if (senderId <= 0) { if (senderId <= 0) {
titleBar?.setSubTitle(getString(R.string.add_sender)) titleBar?.setSubTitle(getString(R.string.add_sender))
@ -127,13 +137,19 @@ class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnCli
binding!!.etSecret.setText(settingVo.secret) binding!!.etSecret.setText(settingVo.secret)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId()) binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate) binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
binding!!.etMessageCard.setText(settingVo.messageCard)
} }
} }
}) })
} }
override fun initListeners() { override fun initListeners() {
binding!!.btInsertSenderToTitle.setOnClickListener(this)
binding!!.btInsertExtraToTitle.setOnClickListener(this)
binding!!.btInsertTimeToTitle.setOnClickListener(this)
binding!!.btInsertDeviceNameToTitle.setOnClickListener(this)
binding!!.btInsertSender.setOnClickListener(this) binding!!.btInsertSender.setOnClickListener(this)
binding!!.btInsertContent.setOnClickListener(this)
binding!!.btInsertExtra.setOnClickListener(this) binding!!.btInsertExtra.setOnClickListener(this)
binding!!.btInsertTime.setOnClickListener(this) binding!!.btInsertTime.setOnClickListener(this)
binding!!.btInsertDeviceName.setOnClickListener(this) binding!!.btInsertDeviceName.setOnClickListener(this)
@ -147,27 +163,53 @@ class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnCli
override fun onClick(v: View) { override fun onClick(v: View) {
try { try {
val etTitleTemplate: EditText = binding!!.etTitleTemplate val etTitleTemplate: EditText = binding!!.etTitleTemplate
val etMessageCard: EditText = binding!!.etMessageCard
when (v.id) { when (v.id) {
R.id.bt_insert_sender -> { R.id.bt_insert_sender_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from))
return return
} }
R.id.bt_insert_extra -> { R.id.bt_insert_extra_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot))
return return
} }
R.id.bt_insert_time -> { R.id.bt_insert_time_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time))
return return
} }
R.id.bt_insert_device_name -> { R.id.bt_insert_device_name_to_title -> {
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name)) CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name))
return return
} }
R.id.bt_insert_sender -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_from))
return
}
R.id.bt_insert_content -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_sms))
return
}
R.id.bt_insert_extra -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_card_slot))
return
}
R.id.bt_insert_time -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_receive_time))
return
}
R.id.bt_insert_device_name -> {
CommonUtils.insertOrReplaceText2Cursor(etMessageCard, getString(R.string.tag_device_name))
return
}
R.id.btn_test -> { R.id.btn_test -> {
mCountDownHelper?.start() mCountDownHelper?.start()
Thread { Thread {
@ -235,8 +277,9 @@ class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnCli
val secret = binding!!.etSecret.text.toString().trim() val secret = binding!!.etSecret.text.toString().trim()
val msgType = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_interactive) "interactive" else "text" val msgType = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_interactive) "interactive" else "text"
val title = binding!!.etTitleTemplate.text.toString().trim() val title = binding!!.etTitleTemplate.text.toString().trim()
val messageCard = binding!!.etMessageCard.text.toString().trim()
return FeishuSetting(webhook, secret, msgType, title) return FeishuSetting(webhook, secret, msgType, title, messageCard)
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -91,7 +91,7 @@ class FeishuAppUtils private constructor() {
logId: Long = 0L, logId: Long = 0L,
msgId: Long = 0L msgId: Long = 0L
) { ) {
val requestUrl = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=user_id" val requestUrl = "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${setting.receiveIdType}"
Log.d(TAG, "requestUrl$requestUrl") Log.d(TAG, "requestUrl$requestUrl")
val content: String = if (rule != null) { val content: String = if (rule != null) {
@ -106,7 +106,16 @@ class FeishuAppUtils private constructor() {
} else { } else {
msgInfo.getTitleForSend(setting.titleTemplate) msgInfo.getTitleForSend(setting.titleTemplate)
} }
"{\"elements\":[{\"tag\":\"markdown\",\"content\":\"**[{{MSG_TITLE}}]({{MSG_URL}})**\\n --------------\\n{{MSG_CONTENT}}\"}]}".trimIndent().replace("{{MSG_TITLE}}", jsonInnerStr(title)).replace("{{MSG_URL}}", jsonInnerStr("https://github.com/pppscn/SmsForwarder")).replace("{{MSG_CONTENT}}", jsonInnerStr(content)) if (TextUtils.isEmpty(setting.messageCard.trim())) {
"{\"elements\":[{\"tag\":\"markdown\",\"content\":\"**[{{MSG_TITLE}}]({{MSG_URL}})**\\n --------------\\n{{MSG_CONTENT}}\"}]}".trimIndent().replace("{{MSG_TITLE}}", jsonInnerStr(title)).replace("{{MSG_URL}}", jsonInnerStr("https://github.com/pppscn/SmsForwarder")).replace("{{MSG_CONTENT}}", jsonInnerStr(content))
} else {
msgInfo.getContentFromJson(
setting.messageCard.trimIndent()
.replace("{{MSG_TITLE}}", jsonInnerStr(title))
.replace("{{MSG_URL}}", jsonInnerStr("https://github.com/pppscn/SmsForwarder"))
.replace("{{MSG_CONTENT}}", jsonInnerStr(content))
)
}
} else { } else {
"{\"text\":\"{{MSG_CONTENT}}\"}".trimIndent().replace("{{MSG_CONTENT}}", jsonInnerStr(content)) "{\"text\":\"{{MSG_CONTENT}}\"}".trimIndent().replace("{{MSG_CONTENT}}", jsonInnerStr(content))
} }

View File

@ -1,5 +1,6 @@
package com.idormy.sms.forwarder.utils.sender package com.idormy.sms.forwarder.utils.sender
import android.text.TextUtils
import android.util.Base64 import android.util.Base64
import com.google.gson.Gson import com.google.gson.Gson
import com.idormy.sms.forwarder.database.entity.Rule import com.idormy.sms.forwarder.database.entity.Rule
@ -121,8 +122,20 @@ class FeishuUtils private constructor() {
val requestMsg: String val requestMsg: String
if (setting.msgType == null || setting.msgType == "interactive") { if (setting.msgType == null || setting.msgType == "interactive") {
msgMap["msg_type"] = "interactive" msgMap["msg_type"] = "interactive"
msgMap["card"] = "{{CARD_BODY}}" if (TextUtils.isEmpty(setting.messageCard.trim())) {
requestMsg = Gson().toJson(msgMap).replace("\"{{CARD_BODY}}\"", buildMsg(title, content, from, msgInfo.date)) msgMap["card"] = "{{CARD_BODY}}"
requestMsg = Gson().toJson(msgMap).replace("\"{{CARD_BODY}}\"", buildMsg(title, content, from, msgInfo.date))
} else {
val msgTime = jsonInnerStr(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(msgInfo.date))
msgMap["card"] = msgInfo.getContentFromJson(
setting.messageCard.trimIndent()
.replace("{{MSG_TITLE}}", jsonInnerStr(title))
.replace("{{MSG_TIME}}", msgTime)
.replace("{{MSG_FROM}}", jsonInnerStr(from))
.replace("{{MSG_CONTENT}}", jsonInnerStr(content))
)
requestMsg = Gson().toJson(msgMap)
}
} else { } else {
msgMap["msg_type"] = "text" msgMap["msg_type"] = "text"
val contentMap: MutableMap<String, Any> = mutableMapOf() val contentMap: MutableMap<String, Any> = mutableMapOf()

View File

@ -123,7 +123,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/layout_custom_template" android:id="@+id/layout_title_template"
style="@style/BarStyle" style="@style/BarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -164,24 +164,24 @@
android:orientation="horizontal"> android:orientation="horizontal">
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_sender" android:id="@+id/bt_insert_sender_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:text="@string/insert_sender" /> android:text="@string/insert_sender" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_extra" android:id="@+id/bt_insert_extra_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:text="@string/insert_extra" /> android:text="@string/insert_extra" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_time" android:id="@+id/bt_insert_time_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:text="@string/insert_time" /> android:text="@string/insert_time" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_device_name" android:id="@+id/bt_insert_device_name_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:text="@string/insert_device_name" /> android:text="@string/insert_device_name" />
@ -190,6 +190,84 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/layout_message_card"
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:ignore="RtlSymmetry">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/feishu_msg_type_interactive_message_card"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/custom_template_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.edittext.ClearEditText
android:id="@+id/et_message_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:gravity="left|top"
android:inputType="textMultiLine"
android:minLines="5"
android:text=""
tools:ignore="RtlHardcoded,SpeakableTextPresentCheck" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_sender"
style="@style/insertButtonStyle"
android:text="@string/insert_sender" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_content"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_content" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_extra"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_extra" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_time"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_time" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_device_name"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_device_name" />
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -95,6 +95,53 @@
</LinearLayout> </LinearLayout>
<LinearLayout
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/feishu_receive_id_type"
android:textStyle="bold" />
<RadioGroup
android:id="@+id/rg_receive_id_type"
style="@style/rg_style"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_receive_id_type_open_id"
style="@style/rg_rb_style"
android:text="@string/open_id" />
<RadioButton
android:id="@+id/rb_receive_id_type_user_id"
style="@style/rg_rb_style"
android:checked="true"
android:text="@string/user_id" />
<RadioButton
android:id="@+id/rb_receive_id_type_union_id"
style="@style/rg_rb_style"
android:text="@string/union_id" />
<RadioButton
android:id="@+id/rb_receive_id_type_email"
style="@style/rg_rb_style"
android:text="@string/email" />
<RadioButton
android:id="@+id/rb_receive_id_type_chat_id"
style="@style/rg_rb_style"
android:text="@string/chat_id" />
</RadioGroup>
</LinearLayout>
<LinearLayout <LinearLayout
style="@style/BarStyle" style="@style/BarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -102,14 +149,14 @@
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:layout_width="75dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="end" android:gravity="end"
android:text="@string/user_id" android:text="@string/receive_id"
android:textStyle="bold" /> android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText <com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_user_id" android:id="@+id/et_receive_id"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
@ -153,7 +200,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/layout_custom_template" android:id="@+id/layout_title_template"
style="@style/BarStyle" style="@style/BarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -194,24 +241,24 @@
android:orientation="horizontal"> android:orientation="horizontal">
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_sender" android:id="@+id/bt_insert_sender_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:text="@string/insert_sender" /> android:text="@string/insert_sender" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_extra" android:id="@+id/bt_insert_extra_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:text="@string/insert_extra" /> android:text="@string/insert_extra" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_time" android:id="@+id/bt_insert_time_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:text="@string/insert_time" /> android:text="@string/insert_time" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton <com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_device_name" android:id="@+id/bt_insert_device_name_to_title"
style="@style/insertButtonStyle" style="@style/insertButtonStyle"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:text="@string/insert_device_name" /> android:text="@string/insert_device_name" />
@ -220,6 +267,84 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/layout_message_card"
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:ignore="RtlSymmetry">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/feishu_msg_type_interactive_message_card"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/custom_template_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.edittext.ClearEditText
android:id="@+id/et_message_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:gravity="left|top"
android:inputType="textMultiLine"
android:minLines="5"
android:text=""
tools:ignore="RtlHardcoded,SpeakableTextPresentCheck" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_sender"
style="@style/insertButtonStyle"
android:text="@string/insert_sender" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_content"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_content" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_extra"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_extra" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_time"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_time" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/bt_insert_device_name"
style="@style/insertButtonStyle"
android:layout_marginStart="3dp"
android:text="@string/insert_device_name" />
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -323,10 +323,12 @@
<string name="email_title">Email Title</string> <string name="email_title">Email Title</string>
<string name="feishu_webhook">Webhook</string> <string name="feishu_webhook">Webhook</string>
<string name="feishu_secret">Secret (optional)</string> <string name="feishu_secret">Secret (optional)</string>
<string name="feishu_receive_id_type">Receive Id Type"</string>
<string name="feishu_msg_type">Msg Type</string> <string name="feishu_msg_type">Msg Type</string>
<string name="feishu_msg_type_text">Text</string> <string name="feishu_msg_type_text">Text</string>
<string name="feishu_msg_type_interactive">Interactive</string> <string name="feishu_msg_type_interactive">Interactive</string>
<string name="feishu_msg_type_interactive_title">Interactive Title</string> <string name="feishu_msg_type_interactive_title">Interactive Title</string>
<string name="feishu_msg_type_interactive_message_card">Message Card Json</string>
<string name="Customize_API">Customize API</string> <string name="Customize_API">Customize API</string>
<string name="Corp_ID">Corp ID</string> <string name="Corp_ID">Corp ID</string>
<string name="Agent_ID">Agent ID</string> <string name="Agent_ID">Agent ID</string>
@ -1331,4 +1333,8 @@
<string name="logs">【Logs】</string> <string name="logs">【Logs】</string>
<string name="close_logs">Close Logs</string> <string name="close_logs">Close Logs</string>
<string name="stopped">Stopped</string> <string name="stopped">Stopped</string>
<string name="open_id">Open ID</string>
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">Receive ID</string>
</resources> </resources>

View File

@ -324,10 +324,12 @@
<string name="email_title">邮件主题</string> <string name="email_title">邮件主题</string>
<string name="feishu_webhook">Webhook 地址</string> <string name="feishu_webhook">Webhook 地址</string>
<string name="feishu_secret">加签 Secret (没有可不填)</string> <string name="feishu_secret">加签 Secret (没有可不填)</string>
<string name="feishu_receive_id_type">消息接收者ID类型</string>
<string name="feishu_msg_type">消息类型</string> <string name="feishu_msg_type">消息类型</string>
<string name="feishu_msg_type_text">纯文本</string> <string name="feishu_msg_type_text">纯文本</string>
<string name="feishu_msg_type_interactive">消息卡片</string> <string name="feishu_msg_type_interactive">消息卡片</string>
<string name="feishu_msg_type_interactive_title">标题模板</string> <string name="feishu_msg_type_interactive_title">标题模板</string>
<string name="feishu_msg_type_interactive_message_card">自定义消息卡片</string>
<string name="Customize_API">自定义API</string> <string name="Customize_API">自定义API</string>
<string name="Corp_ID">企业ID</string> <string name="Corp_ID">企业ID</string>
<string name="Agent_ID">AgentId</string> <string name="Agent_ID">AgentId</string>
@ -1332,4 +1334,8 @@
<string name="logs">【日志】</string> <string name="logs">【日志】</string>
<string name="close_logs">关闭日志</string> <string name="close_logs">关闭日志</string>
<string name="stopped">已停止</string> <string name="stopped">已停止</string>
<string name="open_id">Open ID</string>
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">消息接收者ID</string>
</resources> </resources>

View File

@ -324,10 +324,12 @@
<string name="email_title">郵件主題</string> <string name="email_title">郵件主題</string>
<string name="feishu_webhook">Webhook 地址</string> <string name="feishu_webhook">Webhook 地址</string>
<string name="feishu_secret">加簽 Secret (沒有可不填)</string> <string name="feishu_secret">加簽 Secret (沒有可不填)</string>
<string name="feishu_receive_id_type">訊息接收者ID類型</string>
<string name="feishu_msg_type">消息類型</string> <string name="feishu_msg_type">消息類型</string>
<string name="feishu_msg_type_text">純文本</string> <string name="feishu_msg_type_text">純文本</string>
<string name="feishu_msg_type_interactive">消息卡片</string> <string name="feishu_msg_type_interactive">消息卡片</string>
<string name="feishu_msg_type_interactive_title">標題模板</string> <string name="feishu_msg_type_interactive_title">標題模板</string>
<string name="feishu_msg_type_interactive_message_card">自定義消息卡片</string>
<string name="Customize_API">自定義API</string> <string name="Customize_API">自定義API</string>
<string name="Corp_ID">企業ID</string> <string name="Corp_ID">企業ID</string>
<string name="Agent_ID">AgentId</string> <string name="Agent_ID">AgentId</string>
@ -1333,4 +1335,8 @@
<string name="logs">【日誌】</string> <string name="logs">【日誌】</string>
<string name="close_logs">關閉日誌</string> <string name="close_logs">關閉日誌</string>
<string name="stopped">已停止</string> <string name="stopped">已停止</string>
<string name="open_id">Open ID</string>
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">訊息接收者ID</string>
</resources> </resources>

View File

@ -324,10 +324,12 @@
<string name="email_title">邮件主题</string> <string name="email_title">邮件主题</string>
<string name="feishu_webhook">Webhook 地址</string> <string name="feishu_webhook">Webhook 地址</string>
<string name="feishu_secret">加签 Secret (没有可不填)</string> <string name="feishu_secret">加签 Secret (没有可不填)</string>
<string name="feishu_receive_id_type">消息接收者ID类型</string>
<string name="feishu_msg_type">消息类型</string> <string name="feishu_msg_type">消息类型</string>
<string name="feishu_msg_type_text">纯文本</string> <string name="feishu_msg_type_text">纯文本</string>
<string name="feishu_msg_type_interactive">消息卡片</string> <string name="feishu_msg_type_interactive">消息卡片</string>
<string name="feishu_msg_type_interactive_title">标题模板</string> <string name="feishu_msg_type_interactive_title">标题模板</string>
<string name="feishu_msg_type_interactive_message_card">自定义消息卡片</string>
<string name="Customize_API">自定义API</string> <string name="Customize_API">自定义API</string>
<string name="Corp_ID">企业ID</string> <string name="Corp_ID">企业ID</string>
<string name="Agent_ID">AgentId</string> <string name="Agent_ID">AgentId</string>
@ -1332,4 +1334,8 @@
<string name="logs">【日志】</string> <string name="logs">【日志】</string>
<string name="close_logs">关闭日志</string> <string name="close_logs">关闭日志</string>
<string name="stopped">已停止</string> <string name="stopped">已停止</string>
<string name="open_id">Open ID</string>
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">消息接收者ID</string>
</resources> </resources>