From a7746f3b8d1ec11c438ef7dcd29650bb432766e4 Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Fri, 15 Jul 2022 01:02:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A`=E9=92=89=E9=92=89?= =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=86=85=E6=9C=BA=E5=99=A8=E4=BA=BA`?= =?UTF-8?q?=E5=8F=91=E9=80=81=E9=80=9A=E9=81=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../sms/forwarder/database/entity/Sender.kt | 6 +- .../entity/result/DingtalkInnerRobotResult.kt | 13 + ...etting.kt => DingtalkGroupRobotSetting.kt} | 2 +- .../setting/DingtalkInnerRobotSetting.kt | 37 ++ .../sms/forwarder/fragment/SendersFragment.kt | 10 +- ...gment.kt => DingtalkGroupRobotFragment.kt} | 24 +- .../senders/DingtalkInnerRobotFragment.kt | 299 ++++++++++++ .../idormy/sms/forwarder/utils/Constants.kt | 6 +- .../sms/forwarder/utils/HttpServerUtils.kt | 7 +- .../idormy/sms/forwarder/utils/SendUtils.kt | 6 +- ...alkUtils.kt => DingtalkGroupRobotUtils.kt} | 11 +- .../utils/sender/DingtalkInnerRobotUtils.kt | 242 +++++++++ .../res/drawable/icon_dingtalk_inner.webp | Bin 0 -> 1682 bytes ...fragment_senders_dingtalk_group_robot.xml} | 0 .../fragment_senders_dingtalk_inner_robot.xml | 459 ++++++++++++++++++ app/src/main/res/values-en/strings.xml | 9 +- app/src/main/res/values/strings.xml | 11 +- 18 files changed, 1110 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/entity/result/DingtalkInnerRobotResult.kt rename app/src/main/java/com/idormy/sms/forwarder/entity/setting/{DingtalkSetting.kt => DingtalkGroupRobotSetting.kt} (85%) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkInnerRobotSetting.kt rename app/src/main/java/com/idormy/sms/forwarder/fragment/senders/{DingtalkFragment.kt => DingtalkGroupRobotFragment.kt} (91%) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkInnerRobotFragment.kt rename app/src/main/java/com/idormy/sms/forwarder/utils/sender/{DingtalkUtils.kt => DingtalkGroupRobotUtils.kt} (92%) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt create mode 100644 app/src/main/res/drawable/icon_dingtalk_inner.webp rename app/src/main/res/layout/{fragment_senders_dingtalk.xml => fragment_senders_dingtalk_group_robot.xml} (100%) create mode 100644 app/src/main/res/layout/fragment_senders_dingtalk_inner_robot.xml diff --git a/README.md b/README.md index ba6e2478..654ba8be 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ 短信转发器——不仅只转发短信,备用机必备神器! -监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。 +监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉群自定义机器人、钉钉企业内机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。 包括主动控制服务端与客户端,让你轻松远程发短信、查短信、查通话、查话簿、查电量等。(V3.0 新增) diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt index bc4bd7c6..cf97405d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt @@ -23,7 +23,7 @@ data class Sender( companion object { fun getImageId(type: Int): Int = when (type) { - TYPE_DINGDING -> R.drawable.icon_dingtalk + TYPE_DINGTALK_GROUP_ROBOT -> R.drawable.icon_dingtalk TYPE_EMAIL -> R.drawable.icon_email TYPE_BARK -> R.drawable.icon_bark TYPE_WEBHOOK -> R.drawable.icon_webhook @@ -35,6 +35,7 @@ data class Sender( TYPE_PUSHPLUS -> R.drawable.icon_pushplus TYPE_GOTIFY -> R.drawable.icon_gotify TYPE_SMS -> R.drawable.icon_sms + TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner else -> R.drawable.icon_sms } @@ -42,7 +43,7 @@ data class Sender( val imageId: Int get() = when (type) { - TYPE_DINGDING -> R.drawable.icon_dingtalk + TYPE_DINGTALK_GROUP_ROBOT -> R.drawable.icon_dingtalk TYPE_EMAIL -> R.drawable.icon_email TYPE_BARK -> R.drawable.icon_bark TYPE_WEBHOOK -> R.drawable.icon_webhook @@ -54,6 +55,7 @@ data class Sender( TYPE_PUSHPLUS -> R.drawable.icon_pushplus TYPE_GOTIFY -> R.drawable.icon_gotify TYPE_SMS -> R.drawable.icon_sms + TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner else -> R.drawable.icon_sms } diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/result/DingtalkInnerRobotResult.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/result/DingtalkInnerRobotResult.kt new file mode 100644 index 00000000..e1845b63 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/result/DingtalkInnerRobotResult.kt @@ -0,0 +1,13 @@ +package com.idormy.sms.forwarder.entity.result + +data class DingtalkInnerRobotResult( + //获取access_token返回 + var accessToken: String?, + var expireIn: Long?, + //消息id + var processQueryKey: String?, + //无效的用户userid列表 + //var invalidStaffIdList: String[], + //被限流的userid列表 + //var flowControlledStaffIdList: String[], +) \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkGroupRobotSetting.kt similarity index 85% rename from app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkSetting.kt rename to app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkGroupRobotSetting.kt index 02cce253..eada67be 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkSetting.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkGroupRobotSetting.kt @@ -2,7 +2,7 @@ package com.idormy.sms.forwarder.entity.setting import java.io.Serializable -data class DingtalkSetting( +data class DingtalkGroupRobotSetting( var token: String = "", var secret: String? = "", var atAll: Boolean? = false, diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkInnerRobotSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkInnerRobotSetting.kt new file mode 100644 index 00000000..77aa1311 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/DingtalkInnerRobotSetting.kt @@ -0,0 +1,37 @@ +package com.idormy.sms.forwarder.entity.setting + +import com.idormy.sms.forwarder.R +import java.io.Serializable +import java.net.Proxy + +data class DingtalkInnerRobotSetting( + val agentID: String = "", + val appKey: String = "", + val appSecret: String = "", + val userIds: String = "", + val msgKey: String = "sampleText", + val titleTemplate: String? = "", + val proxyType: Proxy.Type = Proxy.Type.DIRECT, + val proxyHost: String? = "", + val proxyPort: String? = "", + val proxyAuthenticator: Boolean? = false, + val proxyUsername: String? = "", + val proxyPassword: String? = "", +) : Serializable { + + fun getProxyTypeCheckId(): Int { + return when (proxyType) { + Proxy.Type.HTTP -> R.id.rb_proxyHttp + Proxy.Type.SOCKS -> R.id.rb_proxySocks + else -> R.id.rb_proxyNone + } + } + + fun getMsgTypeCheckId(): Int { + return if (msgKey == "sampleMarkdown") { + R.id.rb_msg_type_markdown + } else { + R.id.rb_msg_type_text + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt index ebfc92fb..3cca41c5 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt @@ -95,7 +95,7 @@ class SendersFragment : BaseFragment(), SenderPagingAda R.id.iv_copy -> { PageOption.to( when (item.type) { - TYPE_DINGDING -> DingtalkFragment::class.java + TYPE_DINGTALK_GROUP_ROBOT -> DingtalkGroupRobotFragment::class.java TYPE_EMAIL -> EmailFragment::class.java TYPE_BARK -> BarkFragment::class.java TYPE_WEBHOOK -> WebhookFragment::class.java @@ -107,7 +107,8 @@ class SendersFragment : BaseFragment(), SenderPagingAda TYPE_FEISHU -> FeishuFragment::class.java TYPE_PUSHPLUS -> PushplusFragment::class.java TYPE_GOTIFY -> GotifyFragment::class.java - else -> DingtalkFragment::class.java + TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java + else -> DingtalkGroupRobotFragment::class.java } ).setNewActivity(true) .putLong(KEY_SENDER_ID, item.id) @@ -118,7 +119,7 @@ class SendersFragment : BaseFragment(), SenderPagingAda R.id.iv_edit -> { PageOption.to( when (item.type) { - TYPE_DINGDING -> DingtalkFragment::class.java + TYPE_DINGTALK_GROUP_ROBOT -> DingtalkGroupRobotFragment::class.java TYPE_EMAIL -> EmailFragment::class.java TYPE_BARK -> BarkFragment::class.java TYPE_WEBHOOK -> WebhookFragment::class.java @@ -130,7 +131,8 @@ class SendersFragment : BaseFragment(), SenderPagingAda TYPE_FEISHU -> FeishuFragment::class.java TYPE_PUSHPLUS -> PushplusFragment::class.java TYPE_GOTIFY -> GotifyFragment::class.java - else -> DingtalkFragment::class.java + TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java + else -> DingtalkGroupRobotFragment::class.java } ).setNewActivity(true) .putLong(KEY_SENDER_ID, item.id) diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkGroupRobotFragment.kt similarity index 91% rename from app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkFragment.kt rename to app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkGroupRobotFragment.kt index a0d2b121..740c41d6 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkGroupRobotFragment.kt @@ -15,11 +15,11 @@ import com.idormy.sms.forwarder.database.AppDatabase import com.idormy.sms.forwarder.database.entity.Sender import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel -import com.idormy.sms.forwarder.databinding.FragmentSendersDingtalkBinding +import com.idormy.sms.forwarder.databinding.FragmentSendersDingtalkGroupRobotBinding import com.idormy.sms.forwarder.entity.MsgInfo -import com.idormy.sms.forwarder.entity.setting.DingtalkSetting +import com.idormy.sms.forwarder.entity.setting.DingtalkGroupRobotSetting import com.idormy.sms.forwarder.utils.* -import com.idormy.sms.forwarder.utils.sender.DingtalkUtils +import com.idormy.sms.forwarder.utils.sender.DingtalkGroupRobotUtils import com.xuexiang.xaop.annotation.SingleClick import com.xuexiang.xpage.annotation.Page import com.xuexiang.xrouter.annotation.AutoWired @@ -34,11 +34,11 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import java.util.* -@Page(name = "钉钉机器人") +@Page(name = "钉钉群机器人") @Suppress("PrivatePropertyName") -class DingtalkFragment : BaseFragment(), View.OnClickListener, CompoundButton.OnCheckedChangeListener { +class DingtalkGroupRobotFragment : BaseFragment(), View.OnClickListener, CompoundButton.OnCheckedChangeListener { - private val TAG: String = DingtalkFragment::class.java.simpleName + private val TAG: String = DingtalkGroupRobotFragment::class.java.simpleName var titleBar: TitleBar? = null private val viewModel by viewModels { BaseViewModelFactory(context) } private var mCountDownHelper: CountDownButtonHelper? = null @@ -62,8 +62,8 @@ class DingtalkFragment : BaseFragment(), View.O override fun viewBindingInflate( inflater: LayoutInflater, container: ViewGroup, - ): FragmentSendersDingtalkBinding { - return FragmentSendersDingtalkBinding.inflate(inflater, container, false) + ): FragmentSendersDingtalkGroupRobotBinding { + return FragmentSendersDingtalkGroupRobotBinding.inflate(inflater, container, false) } override fun initTitle(): TitleBar? { @@ -117,7 +117,7 @@ class DingtalkFragment : BaseFragment(), View.O } binding!!.etName.setText(sender.name) binding!!.sbEnable.isChecked = sender.status == 1 - val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkSetting::class.java) + val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkGroupRobotSetting::class.java) Log.d(TAG, settingVo.toString()) if (settingVo != null) { binding!!.etToken.setText(settingVo.token) @@ -164,7 +164,7 @@ class DingtalkFragment : BaseFragment(), View.O val settingVo = checkSetting() Log.d(TAG, settingVo.toString()) val msgInfo = MsgInfo("sms", getString(R.string.test_phone_num), getString(R.string.test_sender_sms), Date(), getString(R.string.test_sim_info)) - DingtalkUtils.sendMsg(settingVo, msgInfo) + DingtalkGroupRobotUtils.sendMsg(settingVo, msgInfo) } catch (e: Exception) { e.printStackTrace() if (Looper.myLooper() == null) Looper.prepare() @@ -217,7 +217,7 @@ class DingtalkFragment : BaseFragment(), View.O } } - private fun checkSetting(): DingtalkSetting { + private fun checkSetting(): DingtalkGroupRobotSetting { val token = binding!!.etToken.text.toString().trim() if (CommonUtils.checkUrl(token, true)) { throw Exception(getString(R.string.invalid_token)) @@ -230,7 +230,7 @@ class DingtalkFragment : BaseFragment(), View.O throw Exception(getString(R.string.invalid_at_mobiles)) }*/ - return DingtalkSetting(token, secret, atAll, atMobiles) + return DingtalkGroupRobotSetting(token, secret, atAll, atMobiles) } override fun onDestroyView() { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkInnerRobotFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkInnerRobotFragment.kt new file mode 100644 index 00000000..deabaa8d --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/DingtalkInnerRobotFragment.kt @@ -0,0 +1,299 @@ +package com.idormy.sms.forwarder.fragment.senders + +import android.annotation.SuppressLint +import android.os.Looper +import android.text.TextUtils +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.CompoundButton +import android.widget.EditText +import android.widget.RadioGroup +import androidx.fragment.app.viewModels +import com.google.gson.Gson +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.core.BaseFragment +import com.idormy.sms.forwarder.database.AppDatabase +import com.idormy.sms.forwarder.database.entity.Sender +import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory +import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel +import com.idormy.sms.forwarder.databinding.FragmentSendersDingtalkInnerRobotBinding +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.setting.DingtalkInnerRobotSetting +import com.idormy.sms.forwarder.utils.* +import com.idormy.sms.forwarder.utils.sender.DingtalkInnerRobotUtils +import com.xuexiang.xaop.annotation.SingleClick +import com.xuexiang.xpage.annotation.Page +import com.xuexiang.xrouter.annotation.AutoWired +import com.xuexiang.xrouter.launcher.XRouter +import com.xuexiang.xui.utils.CountDownButtonHelper +import com.xuexiang.xui.widget.actionbar.TitleBar +import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction +import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.net.Proxy +import java.util.* + +@Page(name = "钉钉企业机器人") +@Suppress("PrivatePropertyName") +class DingtalkInnerRobotFragment : BaseFragment(), View.OnClickListener, CompoundButton.OnCheckedChangeListener { + + private val TAG: String = DingtalkInnerRobotFragment::class.java.simpleName + var titleBar: TitleBar? = null + private val viewModel by viewModels { BaseViewModelFactory(context) } + private var mCountDownHelper: CountDownButtonHelper? = null + + @JvmField + @AutoWired(name = KEY_SENDER_ID) + var senderId: Long = 0 + + @JvmField + @AutoWired(name = KEY_SENDER_TYPE) + var senderType: Int = 0 + + @JvmField + @AutoWired(name = KEY_SENDER_CLONE) + var isClone: Boolean = false + + override fun initArgs() { + XRouter.getInstance().inject(this) + } + + override fun viewBindingInflate( + inflater: LayoutInflater, + container: ViewGroup, + ): FragmentSendersDingtalkInnerRobotBinding { + return FragmentSendersDingtalkInnerRobotBinding.inflate(inflater, container, false) + } + + override fun initTitle(): TitleBar? { + titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.dingtalk_inner_robot) + return titleBar + } + + /** + * 初始化控件 + */ + override fun initViews() { + //测试按钮增加倒计时,避免重复点击 + mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout) + mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener { + override fun onCountDown(time: Int) { + binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time) + } + + override fun onFinished() { + binding!!.btnTest.text = getString(R.string.test) + } + }) + + //新增 + if (senderId <= 0) { + titleBar?.setSubTitle(getString(R.string.add_sender)) + binding!!.btnDel.setText(R.string.discard) + return + } + + //编辑 + binding!!.btnDel.setText(R.string.del) + AppDatabase.getInstance(requireContext()) + .senderDao() + .get(senderId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + + override fun onError(e: Throwable) { + e.printStackTrace() + } + + override fun onSuccess(sender: Sender) { + if (isClone) { + titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name) + binding!!.btnDel.setText(R.string.discard) + } else { + titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name) + } + binding!!.etName.setText(sender.name) + binding!!.sbEnable.isChecked = sender.status == 1 + val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkInnerRobotSetting::class.java) + Log.d(TAG, settingVo.toString()) + if (settingVo != null) { + binding!!.etAgentID.setText(settingVo.agentID) + binding!!.etAppKey.setText(settingVo.appKey) + binding!!.etAppSecret.setText(settingVo.appSecret) + binding!!.etUserIds.setText(settingVo.userIds) + binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId()) + binding!!.etTitleTemplate.setText(settingVo.titleTemplate) + binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId()) + binding!!.etProxyHost.setText(settingVo.proxyHost) + binding!!.etProxyPort.setText(settingVo.proxyPort) + binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true + binding!!.etProxyUsername.setText(settingVo.proxyUsername) + binding!!.etProxyPassword.setText(settingVo.proxyPassword) + } + } + }) + } + + override fun initListeners() { + binding!!.btInsertSender.setOnClickListener(this) + binding!!.btInsertExtra.setOnClickListener(this) + binding!!.btInsertTime.setOnClickListener(this) + binding!!.btInsertDeviceName.setOnClickListener(this) + binding!!.btnTest.setOnClickListener(this) + binding!!.btnDel.setOnClickListener(this) + binding!!.btnSave.setOnClickListener(this) + binding!!.sbProxyAuthenticator.setOnCheckedChangeListener(this) + binding!!.rgProxyType.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int -> + if (checkedId == R.id.rb_proxyHttp || checkedId == R.id.rb_proxySocks) { + binding!!.layoutProxyHost.visibility = View.VISIBLE + binding!!.layoutProxyPort.visibility = View.VISIBLE + binding!!.layoutProxyAuthenticator.visibility = if (binding!!.sbProxyAuthenticator.isChecked) View.VISIBLE else View.GONE + } else { + binding!!.layoutProxyHost.visibility = View.GONE + binding!!.layoutProxyPort.visibility = View.GONE + binding!!.layoutProxyAuthenticator.visibility = View.GONE + } + } + binding!!.rgMsgType.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int -> + binding!!.layoutCustomTemplate.visibility = if (checkedId == R.id.rb_msg_type_markdown) View.VISIBLE else View.GONE + } + } + + @SuppressLint("SetTextI18n") + override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { + when (buttonView.id) { + R.id.sb_proxyAuthenticator -> { + binding!!.layoutProxyAuthenticator.visibility = if (isChecked) View.VISIBLE else View.GONE + } + else -> {} + } + } + + @SingleClick + override fun onClick(v: View) { + try { + val etTitleTemplate: EditText = binding!!.etTitleTemplate + when (v.id) { + R.id.bt_insert_sender -> { + CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from)) + return + } + R.id.bt_insert_extra -> { + CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot)) + return + } + R.id.bt_insert_time -> { + CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time)) + return + } + R.id.bt_insert_device_name -> { + CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name)) + return + } + R.id.btn_test -> { + mCountDownHelper?.start() + Thread { + try { + val settingVo = checkSetting() + Log.d(TAG, settingVo.toString()) + val msgInfo = MsgInfo("sms", getString(R.string.test_phone_num), getString(R.string.test_sender_sms), Date(), getString(R.string.test_sim_info)) + DingtalkInnerRobotUtils.sendMsg(settingVo, msgInfo) + } catch (e: Exception) { + e.printStackTrace() + if (Looper.myLooper() == null) Looper.prepare() + XToastUtils.error(e.message.toString()) + Looper.loop() + } + }.start() + return + } + R.id.btn_del -> { + if (senderId <= 0 || isClone) { + popToBack() + return + } + + MaterialDialog.Builder(requireContext()) + .title(R.string.delete_sender_title) + .content(R.string.delete_sender_tips) + .positiveText(R.string.lab_yes) + .negativeText(R.string.lab_no) + .onPositive { _: MaterialDialog?, _: DialogAction? -> + viewModel.delete(senderId) + XToastUtils.success(R.string.delete_sender_toast) + popToBack() + } + .show() + return + } + R.id.btn_save -> { + val name = binding!!.etName.text.toString().trim() + if (TextUtils.isEmpty(name)) { + throw Exception(getString(R.string.invalid_name)) + } + + val status = if (binding!!.sbEnable.isChecked) 1 else 0 + val settingVo = checkSetting() + if (isClone) senderId = 0 + val senderNew = Sender(senderId, senderType, name, Gson().toJson(settingVo), status) + Log.d(TAG, senderNew.toString()) + + viewModel.insertOrUpdate(senderNew) + XToastUtils.success(R.string.tipSaveSuccess) + popToBack() + return + } + } + } catch (e: Exception) { + XToastUtils.error(e.message.toString()) + e.printStackTrace() + } + } + + private fun checkSetting(): DingtalkInnerRobotSetting { + val agentID = binding!!.etAgentID.text.toString().trim() + val appKey = binding!!.etAppKey.text.toString().trim() + val appSecret = binding!!.etAppSecret.text.toString().trim() + val userIds = binding!!.etUserIds.text.toString().trim() + if (TextUtils.isEmpty(agentID) || TextUtils.isEmpty(appKey) || TextUtils.isEmpty(appSecret) || TextUtils.isEmpty(userIds)) { + throw Exception(getString(R.string.invalid_dingtalk_inner_robot)) + } + + val proxyType: Proxy.Type = when (binding!!.rgProxyType.checkedRadioButtonId) { + R.id.rb_proxyHttp -> Proxy.Type.HTTP + R.id.rb_proxySocks -> Proxy.Type.SOCKS + else -> Proxy.Type.DIRECT + } + val proxyHost = binding!!.etProxyHost.text.toString().trim() + val proxyPort = binding!!.etProxyPort.text.toString().trim() + + if (proxyType != Proxy.Type.DIRECT && (TextUtils.isEmpty(proxyHost) || TextUtils.isEmpty(proxyPort))) { + throw Exception(getString(R.string.invalid_host_or_port)) + } + + val proxyAuthenticator = binding!!.sbProxyAuthenticator.isChecked + val proxyUsername = binding!!.etProxyUsername.text.toString().trim() + val proxyPassword = binding!!.etProxyPassword.text.toString().trim() + if (proxyAuthenticator && TextUtils.isEmpty(proxyUsername) && TextUtils.isEmpty(proxyPassword)) { + throw Exception(getString(R.string.invalid_username_or_password)) + } + + val msgKey = if (binding!!.rgMsgType.checkedRadioButtonId == R.id.rb_msg_type_markdown) "sampleMarkdown" else "sampleText" + val titleTemplate = binding!!.etTitleTemplate.text.toString().trim() + + return DingtalkInnerRobotSetting(agentID, appKey, appSecret, userIds, msgKey, titleTemplate, proxyType, proxyHost, proxyPort, proxyAuthenticator, proxyUsername, proxyPassword) + } + + override fun onDestroyView() { + if (mCountDownHelper != null) mCountDownHelper!!.recycle() + super.onDestroyView() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt index 1153e509..33a44105 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt @@ -148,7 +148,7 @@ val BARK_LEVEL_MAP = mapOf( ) //发送通道 -const val TYPE_DINGDING = 0 +const val TYPE_DINGTALK_GROUP_ROBOT = 0 const val TYPE_EMAIL = 1 const val TYPE_BARK = 2 const val TYPE_WEBHOOK = 3 @@ -160,8 +160,9 @@ const val TYPE_SMS = 8 const val TYPE_FEISHU = 9 const val TYPE_PUSHPLUS = 10 const val TYPE_GOTIFY = 11 +const val TYPE_DINGTALK_INNER_ROBOT = 12 var SENDER_FRAGMENT_LIST = listOf( - PageInfo(getString(R.string.dingtalk_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk), + PageInfo(getString(R.string.dingtalk_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkGroupRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk), PageInfo(getString(R.string.email), "com.idormy.sms.forwarder.fragment.senders.EmailFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_email), PageInfo(getString(R.string.bark), "com.idormy.sms.forwarder.fragment.senders.BarkFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_bark), PageInfo(getString(R.string.webhook), "com.idormy.sms.forwarder.fragment.senders.WebhookFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_webhook), @@ -173,6 +174,7 @@ var SENDER_FRAGMENT_LIST = listOf( PageInfo(getString(R.string.feishu), "com.idormy.sms.forwarder.fragment.senders.FeishuFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_feishu), PageInfo(getString(R.string.pushplus), "com.idormy.sms.forwarder.fragment.senders.PushplusFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_pushplus), PageInfo(getString(R.string.gotify), "com.idormy.sms.forwarder.fragment.senders.GotifyFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_gotify), + PageInfo(getString(R.string.dingtalk_inner_robot), "com.idormy.sms.forwarder.fragment.senders.DingtalkInnerRobotFragment", "{\"\":\"\"}", CoreAnim.slide, R.drawable.icon_dingtalk_inner), ) //前台服务 diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt index 45ca9a1e..a07349f3 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt @@ -3,6 +3,7 @@ package com.idormy.sms.forwarder.utils import android.text.TextUtils import android.util.Base64 +import android.util.Log import com.google.gson.Gson import com.idormy.sms.forwarder.R import com.idormy.sms.forwarder.core.Core @@ -136,7 +137,11 @@ class HttpServerUtils private constructor() { } val sign = calcSign(req.timestamp.toString(), signSecret.toString()) - if (sign != req.sign) throw HttpException(500, getString(R.string.sign_verify_failed)) + if (sign != req.sign) { + Log.e("calcSign", sign) + Log.e("reqSign", req.sign.toString()) + throw HttpException(500, getString(R.string.sign_verify_failed)) + } } //判断版本是否一致 diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt index 4d60a113..94a27145 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt @@ -71,9 +71,9 @@ object SendUtils { fun sendMsgSender(msgInfo: MsgInfo, rule: Rule, sender: Sender, logId: Long) { try { when (sender.type) { - TYPE_DINGDING -> { - val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkSetting::class.java) - DingtalkUtils.sendMsg(settingVo, msgInfo, rule, logId) + TYPE_DINGTALK_GROUP_ROBOT -> { + val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkGroupRobotSetting::class.java) + DingtalkGroupRobotUtils.sendMsg(settingVo, msgInfo, rule, logId) } TYPE_EMAIL -> { val settingVo = Gson().fromJson(sender.jsonSetting, EmailSetting::class.java) diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt similarity index 92% rename from app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkUtils.kt rename to app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt index 3e6ed0bf..d7818e98 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt @@ -7,7 +7,7 @@ import com.google.gson.Gson import com.idormy.sms.forwarder.database.entity.Rule import com.idormy.sms.forwarder.entity.MsgInfo import com.idormy.sms.forwarder.entity.result.DingtalkResult -import com.idormy.sms.forwarder.entity.setting.DingtalkSetting +import com.idormy.sms.forwarder.entity.setting.DingtalkGroupRobotSetting import com.idormy.sms.forwarder.utils.SendUtils import com.idormy.sms.forwarder.utils.SettingUtils import com.xuexiang.xhttp2.XHttp @@ -19,14 +19,15 @@ import java.nio.charset.StandardCharsets import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec +//钉钉群自定义机器人 @Suppress("PrivatePropertyName", "UNUSED_PARAMETER") -class DingtalkUtils private constructor() { +class DingtalkGroupRobotUtils private constructor() { companion object { - private val TAG: String = DingtalkUtils::class.java.simpleName + private val TAG: String = DingtalkGroupRobotUtils::class.java.simpleName fun sendMsg( - setting: DingtalkSetting, + setting: DingtalkGroupRobotSetting, msgInfo: MsgInfo, rule: Rule?, logId: Long?, @@ -114,7 +115,7 @@ class DingtalkUtils private constructor() { } - fun sendMsg(setting: DingtalkSetting, msgInfo: MsgInfo) { + fun sendMsg(setting: DingtalkGroupRobotSetting, msgInfo: MsgInfo) { sendMsg(setting, msgInfo, null, null) } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt new file mode 100644 index 00000000..4cb61627 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt @@ -0,0 +1,242 @@ +package com.idormy.sms.forwarder.utils.sender + +import android.text.TextUtils +import android.util.Log +import com.google.gson.Gson +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.result.DingtalkInnerRobotResult +import com.idormy.sms.forwarder.entity.setting.DingtalkInnerRobotSetting +import com.idormy.sms.forwarder.utils.MMKVUtils +import com.idormy.sms.forwarder.utils.SendUtils +import com.idormy.sms.forwarder.utils.SettingUtils +import com.xuexiang.xhttp2.XHttp +import com.xuexiang.xhttp2.cache.model.CacheMode +import com.xuexiang.xhttp2.callback.SimpleCallBack +import com.xuexiang.xhttp2.exception.ApiException +import com.xuexiang.xui.utils.ResUtils.getString +import com.xuexiang.xutil.net.NetworkUtils +import okhttp3.Credentials +import okhttp3.Response +import okhttp3.Route +import java.net.Authenticator +import java.net.InetSocketAddress +import java.net.PasswordAuthentication +import java.net.Proxy + +//钉钉企业内机器人 +@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") +class DingtalkInnerRobotUtils private constructor() { + companion object { + + private val TAG: String = DingtalkInnerRobotUtils::class.java.simpleName + + fun sendMsg( + setting: DingtalkInnerRobotSetting, + msgInfo: MsgInfo, + rule: Rule?, + logId: Long?, + ) { + + val accessToken: String? = MMKVUtils.getString("accessToken_" + setting.agentID, "") + val expiresIn: Long = MMKVUtils.getLong("expiresIn_" + setting.agentID, 0L) + if (!TextUtils.isEmpty(accessToken) && expiresIn > System.currentTimeMillis()) { + return sendTextMsg(setting, msgInfo, rule, logId) + } + + val requestUrl = "https://api.dingtalk.com/v1.0/oauth2/accessToken" + Log.d(TAG, "requestUrl:$requestUrl") + + val msgMap: MutableMap = mutableMapOf() + msgMap["appKey"] = setting.appKey + msgMap["appSecret"] = setting.appSecret + val requestMsg: String = Gson().toJson(msgMap) + Log.i(TAG, "requestMsg:$requestMsg") + + val request = XHttp.post(requestUrl) + + //设置代理 + if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS) + && !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort) + ) { + //代理服务器的IP和端口号 + Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}") + val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost) + if (!NetworkUtils.isIP(proxyHost)) { + throw Exception("代理服务器主机名解析失败:proxyHost=$proxyHost") + } + val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890 + + Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort") + request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort))) + + //代理的鉴权账号密码 + if (setting.proxyAuthenticator == true + && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword)) + ) { + Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}") + + if (setting.proxyType == Proxy.Type.HTTP) { + request.okproxyAuthenticator { _: Route?, response: Response -> + //设置代理服务器账号密码 + val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString()) + response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build() + } + } else { + Authenticator.setDefault(object : Authenticator() { + override fun getPasswordAuthentication(): PasswordAuthentication { + return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray()) + } + }) + } + } + } + + request.upJson(requestMsg) + .keepJson(true) + .ignoreHttpsCert() + .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s + .cacheMode(CacheMode.NO_CACHE) + .timeStamp(true) + .execute(object : SimpleCallBack() { + + override fun onError(e: ApiException) { + Log.e(TAG, e.detailMessage) + SendUtils.updateLogs(logId, 0, e.displayMessage) + } + + override fun onSuccess(response: String) { + Log.i(TAG, response) + + val resp = Gson().fromJson(response, DingtalkInnerRobotResult::class.java) + if (!TextUtils.isEmpty(resp.accessToken)) { + MMKVUtils.put("accessToken_" + setting.agentID, resp.accessToken) + MMKVUtils.put("expiresIn_" + setting.agentID, System.currentTimeMillis() + ((resp.expireIn ?: 7200) - 120) * 1000L) //提前2分钟过期 + sendTextMsg(setting, msgInfo, rule, logId) + } else { + SendUtils.updateLogs(logId, 0, String.format(getString(R.string.request_failed_tips), response)) + } + } + + }) + + } + + //发送文本消息 + private fun sendTextMsg( + setting: DingtalkInnerRobotSetting, + msgInfo: MsgInfo, + rule: Rule?, + logId: Long?, + ) { + val requestUrl = "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" + Log.d(TAG, "requestUrl:$requestUrl") + + val content: String = if (rule != null) { + msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) + } else { + msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + } + + val msgParam: MutableMap = mutableMapOf() + if ("sampleMarkdown" == setting.msgKey) { + msgParam["title"] = if (rule != null) { + msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace) + } else { + msgInfo.getTitleForSend(setting.titleTemplate.toString()) + } + msgParam["text"] = content + } else { + msgParam["content"] = content + } + + val textMsgMap: MutableMap = mutableMapOf() + textMsgMap["robotCode"] = setting.appKey + textMsgMap["userIds"] = setting.userIds.split('|').toTypedArray() + textMsgMap["msgKey"] = setting.msgKey + textMsgMap["msgParam"] = Gson().toJson(msgParam) + + val requestMsg: String = Gson().toJson(textMsgMap) + Log.i(TAG, "requestMsg:$requestMsg") + + val request = XHttp.post(requestUrl) + + //设置代理 + if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS) + && !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort) + ) { + //代理服务器的IP和端口号 + Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}") + val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost) + if (!NetworkUtils.isIP(proxyHost)) { + throw Exception("代理服务器主机名解析失败:proxyHost=$proxyHost") + } + val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890 + + Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort") + request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort))) + + //代理的鉴权账号密码 + if (setting.proxyAuthenticator == true + && (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword)) + ) { + Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}") + + if (setting.proxyType == Proxy.Type.HTTP) { + request.okproxyAuthenticator { _: Route?, response: Response -> + //设置代理服务器账号密码 + val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString()) + response.request().newBuilder() + .header("Proxy-Authorization", credential) + .build() + } + } else { + Authenticator.setDefault(object : Authenticator() { + override fun getPasswordAuthentication(): PasswordAuthentication { + return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray()) + } + }) + } + } + } + + request.upJson(requestMsg) + .headers("x-acs-dingtalk-access-token", MMKVUtils.getString("accessToken_" + setting.agentID, "")) + .keepJson(true) + .ignoreHttpsCert() + .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s + .cacheMode(CacheMode.NO_CACHE) + .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 + .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 + .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 + .timeStamp(true) + .execute(object : SimpleCallBack() { + + override fun onError(e: ApiException) { + Log.e(TAG, e.detailMessage) + SendUtils.updateLogs(logId, 0, e.displayMessage) + } + + override fun onSuccess(response: String) { + Log.i(TAG, response) + + val resp = Gson().fromJson(response, DingtalkInnerRobotResult::class.java) + if (!TextUtils.isEmpty(resp.processQueryKey)) { + SendUtils.updateLogs(logId, 2, response) + } else { + SendUtils.updateLogs(logId, 0, response) + } + } + + }) + } + + fun sendMsg(setting: DingtalkInnerRobotSetting, msgInfo: MsgInfo) { + sendMsg(setting, msgInfo, null, null) + } + + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_dingtalk_inner.webp b/app/src/main/res/drawable/icon_dingtalk_inner.webp new file mode 100644 index 0000000000000000000000000000000000000000..57d218f4a4226ec296a93c0efeb5482ad3aa9b16 GIT binary patch literal 1682 zcmV;D25tFLNk&GB1^@t8MM6+kP&il$0000G0001w0055w06|PpNb~^!01Y3*xNRFr zBiVE8J{Q}6xl=<#{ht8*rIuvlNg5vdWK!b+&Y6ZIREF;EpoU{ySWgIX z7<@lmyK>MuG<{0bubzMOmd_8)J;0}Iy7t~Mc*` zpTCZ(ha%FUYCU`LF2o$HTK7?HK`~oZ>*1|cDuYkg5PK+SD;~S>#K#QDUq*2+y{%9` z)7ArUWpOyNxJcEjP;l4xEJANg4_SsWyNr5QR-NRU|6I z|NsC0|NsC0g2)n48AP*oaVqDPW5Mkbiy|%$x;fm(nZw1I+19iA;L`hxDDB9ukU{3& zoIVsoL1Jh2!_LI|kXmc^Zig6(5xcm%f5#w)`km3qJHbE}Ktcz1kM92%GDxXvznr?Y zA4McFcklS&e%m3VQjFcv$7j#(+ul;cv09lOA3J&MV+hQXtm*^-4JX&%dg{cM zjh1)FDvK670n1AfP49Q@VC)C)nMr2RU9 zG(YJ)i6In}lpv_l2*QyVQbE{!YSZx>J62FQAaDc#0Pr0EodGJ40FVGakwBVCC8MGt zrIeiDuo4MC8u~RyLH;LNopN#6Pn>z#pSWall`zXkZQO- zQRTmvZOj0GZ56+Ju;tLA`gDf~D$Ci|^$Ow9JDt3bh*Ff@Xu(^=V!YtBk7l=KM2WFJC0092`{o?m4$f&#@_0x9g{+%sO<}>egsXTN4+^^9v z^N9Mz1g}+B{NI09g@5|wLNdPg*f|P+oL^|6EG< z-SbXn4emFr52KcM46-jDF&jiT?LAjEp`pj6?*ONCFUP4XX-|rdoyu)Vqxn!nqy#NU>upV^&6H7jxAW{I`0JBAf$o@OQ*sZdML!LZ& z=aijCJdjleh86U4LZxt0rV=EbO&M~K9xZhuVo8@SlQ#8lowoww7^h>Uei@rEO*2BJ zfh494JSK9P+b!syChva znNr|CW{~b>?u?|YgDX#pbSfZOp}*j+))xPI3za{(Sw4L17&RK+0aY%9@LV$WX-02$ z`zp=H#+_yv3!t!(4-2f)Sp96QCUK%ojcv^Zg3bgBr|A)~@~p*Y*KN;=l#5bV;r2@A zYm=_)GDAD`0N%ZX_tF6+2&0NHkmrGzo6h3>FP&%q;jJ&A^JuIugK}-UJ+q_l zYx-PnGA+tN0+zb?e*N>l-1$lRz`}-50tqG_Jtl0zoEJP&vX$;!368!OYTSYVCHe%g zUC)sxkA-mS^dwr_4T4J6Xdx;XSl|$1wN5T+vjhcP0O440oXuynlm%~&6HU-NjdWsI z3j(eBf;pX7+s^)RX}<20-a0OJHdZ2`kII5A8b#L6D{U+WBnW3){gM;$3XYj_`~9x* zi;?qz8%LAU99&2=ln{E-geI^7z>% literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/fragment_senders_dingtalk.xml b/app/src/main/res/layout/fragment_senders_dingtalk_group_robot.xml similarity index 100% rename from app/src/main/res/layout/fragment_senders_dingtalk.xml rename to app/src/main/res/layout/fragment_senders_dingtalk_group_robot.xml diff --git a/app/src/main/res/layout/fragment_senders_dingtalk_inner_robot.xml b/app/src/main/res/layout/fragment_senders_dingtalk_inner_robot.xml new file mode 100644 index 00000000..5e4589b5 --- /dev/null +++ b/app/src/main/res/layout/fragment_senders_dingtalk_inner_robot.xml @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 31d96cba..7b3d4930 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -286,6 +286,7 @@ WebHook is empty or not a valid URL Specified member cannot be empty or select @all CoreID, AgentID, and Secret cannot be empty + AgentId, AppKey, AppSecret, and UserIds cannot be empty The receiving phone number cannot be empty Malformed multiple match rule line %s Incorrect format on line %s of regex replacement @@ -314,6 +315,7 @@ Specified Member \@all Tip: List of member IDs that receive messages (multiple recipients are separated by \'|\', up to 1000) + Tip: The userid of the user who receives the message, up to 20 at a time (separated by \'|\') SendKey Message channel Tip: Dynamically specified, supports up to two channels, separated by a vertical bar | @@ -465,7 +467,8 @@ Priority(1 – 9) 5 Enable this rule - Dingtalk Bot + Dingtalk Group Bot + Dingtalk Inner Bot Email Bark Webhook @@ -874,4 +877,8 @@ Silent (disable forwarding) time period If the end time is less than the start time, it will span days; if it is equal, it will be disabled Do you want to download and restart to load! + AppKey + AppSecret + Sample Text + Sample Markdown diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 72150e17..20d70521 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -256,7 +256,7 @@ 该条发送通道已经删除! 选择发送通道类型 暂不支持这种转发 - 设置钉钉机器人 + 设置钉钉群机器人 设置邮箱 设置Webhook 设置企业微信群机器人 @@ -287,6 +287,7 @@ WebHook为空 或 不是有效URL 指定成员 不能为空 或者 选择@all 企业ID、AgentID、Secret都不能为空 + AgentId、AppKey、AppSecret、UserIds都不能为空 接收手机号不能为空 多重匹配规则的第 %s 行格式有误 正则替换内容的第 %s 行格式有误 @@ -315,6 +316,7 @@ 指定成员 \@all Tip:接收消息的成员ID列表(多个接收者用‘|’分隔,最多支持1000个) + Tip:接收用户的userid,每次最多传20个(用‘|’分隔) SendKey 消息通道 提示:动态指定,支持最多两个通道,用竖线|隔开 @@ -466,7 +468,8 @@ 优先级(1 – 9) 5 启用该条转发规则 - 钉钉机器人 + 钉钉群机器人 + 钉钉企业机器人 电子邮箱 Bark Webhook @@ -875,4 +878,8 @@ 免打扰(禁用转发)时间段 结束时间小于开始时间则跨天;相等则禁用 是否立即下载,并重启加载? + AppKey + AppSecret + 文本类型 + Markdown类型