Unverified Commit 0a0568b7 authored by irwinsun's avatar irwinsun Committed by GitHub
Browse files

Merge pull request #5240 from irwinsun/issue_notify_1.5

feat: 提供企业微信“蓝盾bot”,用于推送蓝盾相关信息 #3797  [1.5]
parents 494f3f1d 75a1224e
Showing with 351 additions and 10 deletions
+351 -10
......@@ -37,6 +37,10 @@ BK_SSM_PORT=
BK_TURBO_PRIVATE_URL=http://bk-turbo.service.consul
# BK_TURBO_PUBLIC_URL默认为http://turbo.$BK_DOMAIN. 按需修改. turbo网关
BK_TURBO_PUBLIC_URL=http://turbo.$BK_DOMAIN
# BK_CI_WEWORK_HOST 默认值为:https://qyapi.weixin.qq.com, 企业微信服务端host,用于调用企业微信api接口
BK_CI_WEWORK_HOST=https://qyapi.weixin.qq.com
# BK_CI_WEWORK_API_URL 默认值为:https://qyapi.weixin.qq.com, 企业微信服务端host,用于调用企业微信api接口
BK_CI_WEWORK_API_URL=
##########
# 1-基础配置
......@@ -199,7 +203,12 @@ BK_CI_REPOSITORY_SVN_API_URL=
BK_CI_REPOSITORY_SVN_WEBHOOK_URL=
# BK_CI_STORE_USER_AVATARS_URL默认为$BK_PAAS_PUBLIC_URL/console/static/img/getheadimg.jpg?. 无需修改. PaaS用户头像, 目前仅显示默认头像.
BK_CI_STORE_USER_AVATARS_URL=$BK_PAAS_PUBLIC_URL/console/static/img/getheadimg.jpg?
# BK_CI_FQDN_CERT BKCI站点的HTTPS证书存储位置, 默认值为空表示没有开启HTTPS,用于Agent与BKCI走HTTPS通信使用
BK_CI_FQDN_CERT=
# BK_CI_NOTIFY_WEWORK_API_URL 默认值为:https://qyapi.weixin.qq.com, 企业微信服务端host,用于调用企业微信api接口.
BK_CI_NOTIFY_WEWORK_API_URL=https://qyapi.weixin.qq.com
# BK_CI_NOTIFY_WEWORK_SEND_CHANNEL 发送rtx的通道: weworkAgent 企业微信应用,blueking 蓝鲸消息
BK_CI_NOTIFY_WEWORK_SEND_CHANNEL=weworkAgent
##########
# 4-微服务依赖
##########
......
......@@ -47,6 +47,7 @@ dependencies {
implementation(project(":core:log:biz-log-sample"))
implementation(project(":core:misc:biz-misc-sample"))
implementation(project(":core:notify:biz-notify-blueking"))
implementation(project(":core:notify:biz-notify-wework"))
implementation(project(":core:openapi:biz-openapi"))
implementation(project(":core:plugin:biz-plugin"))
implementation(project(":core:process:plugin-load"))
......
......@@ -154,12 +154,13 @@ object OkhttpUtils {
url: String,
uploadFile: File,
headers: Map<String, String?>? = null,
fileFieldName: String = "file"
fileFieldName: String = "file",
fileName: String = uploadFile.name
): Response {
val fileBody = RequestBody.create(octetStream, uploadFile)
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(fileFieldName, uploadFile.name, fileBody)
.addFormDataPart(fileFieldName, fileName, fileBody)
.build()
val requestBuilder = Request.Builder()
.url(url)
......
......@@ -104,6 +104,7 @@ object MQ {
const val QUEUE_PIPELINE_BUILD_FINISH_LOG = "q.engine.pipeline.build.log"
const val QUEUE_PIPELINE_BUILD_FINISH_SUBPIPEINE = "q.engine.pipeline.build.subpipeline"
const val QUEUE_PIPELINE_BUILD_FINISH_WEBHOOK_QUEUE = "q.engine.pipeline.build.finish.webhook.queue"
const val QUEUE_PIPELINE_BUILD_FINISH_NOTIFY_QUEUE = "q.engine.pipeline.build.finish.notify.queue"
const val QUEUE_PIPELINE_BUILD_FINISH_EXT = "q.engine.pipeline.build.finish.ext"
const val QUEUE_PIPELINE_BUILD_FINISH_DISPATCHER = "q.engine.pipeline.build.dispatcher"
......
......@@ -31,5 +31,6 @@ enum class NotifyType {
RTX,
EMAIL,
WECHAT,
SMS
SMS,
WEWORK
}
......@@ -32,11 +32,13 @@ const val QUEUE_NOTIFY_RTX = "queue_notify_rtx"
const val QUEUE_NOTIFY_WECHAT = "queue_notify_wechat"
const val QUEUE_NOTIFY_EMAIL = "queue_notify_email"
const val QUEUE_NOTIFY_SMS = "queue_notify_sms"
const val QUEUE_NOTIFY_WEWORK = "queue_notify_wework"
const val EXCHANGE_NOTIFY = "exchange_notify"
const val ROUTE_RTX = "rtx"
const val ROUTE_WECHAT = "wechat"
const val ROUTE_EMAIL = "email"
const val ROUTE_SMS = "sms"
const val ROUTE_WEWORK = "wework"
const val PIPELINE_QUALITY_AUDIT_NOTIFY_TEMPLATE = "QUALITY_AUDIT_NOTIFY_TEMPLATE"
const val PIPELINE_QUALITY_END_NOTIFY_TEMPLATE = "QUALITY_END_NOTIFY_TEMPLATE"
......@@ -35,7 +35,7 @@ import java.io.InputStream
@ApiModel("企业微信文本消息")
data class WeworkNotifyMediaMessage(
@ApiModelProperty("接收人Id", required = true)
val receivers: List<String>,
val receivers: Collection<String>,
@ApiModelProperty("接收人类型", required = true)
val receiverType: WeworkReceiverType,
@ApiModelProperty("媒体内容", required = true)
......
......@@ -34,7 +34,7 @@ import io.swagger.annotations.ApiModelProperty
@ApiModel("企业微信多媒体消息")
data class WeworkNotifyTextMessage(
@ApiModelProperty("接收人Id", required = true)
val receivers: List<String>,
val receivers: Collection<String>,
@ApiModelProperty("接收人类型", required = true)
val receiverType: WeworkReceiverType,
@ApiModelProperty("文本内容类型", required = true)
......
......@@ -30,11 +30,12 @@ import com.tencent.devops.notify.pojo.WeworkNotifyMediaMessage
import com.tencent.devops.notify.pojo.WeworkNotifyTextMessage
import com.tencent.devops.notify.service.WeworkService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Configuration
@Service
@Suppress("ALL")
class WeworkServiceImpl @Autowired constructor() : WeworkService {
@Configuration
@ConditionalOnProperty(prefix = "notify", name = ["weworkChannel"], havingValue = "blueking")
class BlueKingWeworkServiceImpl @Autowired constructor() : WeworkService {
override fun sendMediaMessage(weworkNotifyMediaMessage: WeworkNotifyMediaMessage) {
TODO("Not yet implemented")
......
/*
* Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
*
* A copy of the MIT License is included in this file.
*
*
* Terms of the MIT License:
* ---------------------------------------------------
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
* the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
dependencies {
implementation(project(":core:notify:api-notify"))
implementation(project(":core:notify:biz-notify"))
implementation(project(":core:notify:model-notify"))
implementation(project(":core:common:common-db"))
implementation(project(":core:common:common-notify"))
}
package com.tencent.devops.notify.wework.config
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
@Configuration
class WeworkConfiguration {
@Value("\${wework.corpId:}")
lateinit var corpId: String
@Value("\${wework.corpSecret:}")
lateinit var corpSecret: String
@Value("\${wework.apiUrl:https://qyapi.weixin.qq.com}")
lateinit var apiUrl: String
@Value("\${wework.agentId:}")
lateinit var agentId: String
@Value("\${wework.tempDirectory:}")
lateinit var tempDirectory: String
/**
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
*/
@Value("\${wework.safe:#{null}}")
val safe: String? = null
/**
* 表示是否开启重复消息检查,0表示否,1表示是,默认0
*/
@Value("\${wework.enableDuplicateCheck:#{null}}")
val enableDuplicateCheck: String? = null
/**
* 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时
*/
@Value("\${wework.duplicateCheckInterval:#{null}}")
val duplicateCheckInterval: String? = null
/**
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
*/
@Value("\${wework.enableIdTrans:#{null}}")
val enableIdTrans: String? = null
}
package com.tencent.devops.notify.wework.pojo
import com.fasterxml.jackson.annotation.JsonProperty
@Suppress("UnnecessaryAbstractClass")
abstract class AbstractSendMessageRequest(
/**
* 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值
*/
@JsonProperty("agentid")
@get:JsonProperty("agentid")
open val agentId: Int,
@JsonProperty("duplicate_check_interval")
/**
* 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时
*/
open val duplicateCheckInterval: Int? = null,
/**
* 表示是否开启重复消息检查,0表示否,1表示是,默认0
*/
@JsonProperty("enable_duplicate_check")
@get:JsonProperty("enable_duplicate_check")
open val enableDuplicateCheck: Int? = null,
@JsonProperty("msgtype")
@get:JsonProperty("msgtype")
open val msgType: String,
/**
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
*/
@JsonProperty("safe")
@get:JsonProperty("safe")
open val safe: Int? = null,
/**
* 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。
* 当touser为”@all”时忽略本参数
*/
@JsonProperty("toparty")
@get:JsonProperty("toparty")
open val toParty: String = "",
/**
* 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。
* 当touser为”@all”时忽略本参数
*/
@JsonProperty("totag")
@get:JsonProperty("totag")
open val toTag: String = "",
/**
* 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。
* 特殊情况:指定为”@all”,则向该企业应用的全部成员发送
*/
@JsonProperty("touser")
@get:JsonProperty("touser")
open val toUser: String = ""
) {
data class MediaMessageContent(
/**
* 媒体文件id,可以调用上传临时素材接口获取
*/
@JsonProperty("media_id")
@get:JsonProperty("media_id")
val mediaId: String,
/**
* 视频消息的标题,不超过128个字节,超过会自动截断,视频才有
*/
@JsonProperty("description")
@get:JsonProperty("description")
var description: String? = null,
/**
* 视频消息的描述,不超过512个字节,超过会自动截断,视频才有
*/
@JsonProperty("title")
@get:JsonProperty("title")
var title: String? = null
)
}
package com.tencent.devops.notify.wework.pojo
import com.fasterxml.jackson.annotation.JsonProperty
data class AccessTokenResp(
@JsonProperty("access_token")
val accessToken: String?,
@JsonProperty("errcode")
val errCode: Int?,
@JsonProperty("errmsg")
val errMsg: String?,
@JsonProperty("expires_in")
val expiresIn: Int?
) {
fun isOk(): Boolean {
return errCode == 0 && accessToken != null
}
}
package com.tencent.devops.notify.wework.pojo
data class FileSendMessageRequest(
override val agentId: Int,
override val duplicateCheckInterval: Int?,
override val enableDuplicateCheck: Int?,
override val safe: Int?,
override val toParty: String,
override val toTag: String,
override val toUser: String,
val file: MediaMessageContent
) : AbstractSendMessageRequest(
agentId = agentId,
duplicateCheckInterval = duplicateCheckInterval,
enableDuplicateCheck = enableDuplicateCheck,
msgType = "file",
safe = safe,
toParty = toParty,
toTag = toTag,
toUser = toUser
)
package com.tencent.devops.notify.wework.pojo
data class ImageSendMessageRequest(
override val agentId: Int,
override val duplicateCheckInterval: Int?,
override val enableDuplicateCheck: Int?,
override val safe: Int?,
override val toParty: String,
override val toTag: String,
override val toUser: String,
val image: MediaMessageContent
) : AbstractSendMessageRequest(
agentId = agentId,
duplicateCheckInterval = duplicateCheckInterval,
enableDuplicateCheck = enableDuplicateCheck,
msgType = "image",
safe = safe,
toParty = toParty,
toTag = toTag,
toUser = toUser
)
package com.tencent.devops.notify.wework.pojo
data class MarkdownSendMessageRequest(
override val agentId: Int,
override val duplicateCheckInterval: Int?,
override val enableDuplicateCheck: Int?,
override val safe: Int?,
override val toParty: String,
override val toTag: String,
override val toUser: String,
val markdown: TextMessageContent
) : AbstractSendMessageRequest(
agentId = agentId,
duplicateCheckInterval = duplicateCheckInterval,
enableDuplicateCheck = enableDuplicateCheck,
msgType = "markdown",
safe = safe,
toParty = toParty,
toTag = toTag,
toUser = toUser
)
package com.tencent.devops.notify.wework.pojo
import com.fasterxml.jackson.annotation.JsonProperty
data class SendMessageResp(
@JsonProperty("errcode")
val errCode: Int?,
@JsonProperty("errmsg")
val errMsg: String?,
@JsonProperty("invalidparty")
val invalidParty: String?,
@JsonProperty("invalidtag")
val invalidTag: String?,
@JsonProperty("invaliduser")
val invalidUser: String?
)
package com.tencent.devops.notify.wework.pojo
import com.fasterxml.jackson.annotation.JsonProperty
data class TextSendMessageRequest(
override val agentId: Int,
override val duplicateCheckInterval: Int?,
override val enableDuplicateCheck: Int?,
/**
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
*/
@JsonProperty("enable_id_trans")
val enableIdTrans: Int? = null,
override val safe: Int?,
override val toParty: String,
override val toTag: String,
override val toUser: String,
val text: TextMessageContent
) : AbstractSendMessageRequest(
agentId = agentId,
duplicateCheckInterval = duplicateCheckInterval,
enableDuplicateCheck = enableDuplicateCheck,
msgType = "text",
safe = safe,
toParty = toParty,
toTag = toTag,
toUser = toUser
)
data class TextMessageContent(
/**
* 消息内容,最长不超过2048个字节,超过将截断(支持id转译)
*/
val content: String
)
package com.tencent.devops.notify.wework.pojo
import com.fasterxml.jackson.annotation.JsonProperty
data class UploadMediaResp(
@JsonProperty("created_at")
val createdAt: String?,
@JsonProperty("errcode")
val errCode: Int?,
@JsonProperty("errmsg")
val errMsg: String?,
@JsonProperty("media_id")
val mediaId: String?,
@JsonProperty("type")
val type: String?
)
package com.tencent.devops.notify.wework.pojo
class VideoSendMessageRequest(
override val agentId: Int,
override val duplicateCheckInterval: Int?,
override val enableDuplicateCheck: Int?,
override val safe: Int?,
override val toParty: String,
override val toTag: String,
override val toUser: String,
val video: MediaMessageContent
) : AbstractSendMessageRequest(
agentId = agentId,
duplicateCheckInterval = duplicateCheckInterval,
enableDuplicateCheck = enableDuplicateCheck,
msgType = "video",
safe = safe,
toParty = toParty,
toTag = toTag,
toUser = toUser
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment