三个月前发布了一篇打通 Jira 与钉钉和企业微信不再难实践文章,朋友圈有个 飞书 同学说他家IM也可以打通,5月份研究了一把,基本完成了Jira与飞书IM打通目标。总体感受是,相对于与钉钉与企业微信的打通方式,与飞书打通显得复杂一些。

Jira 与飞书 打通

飞书IM的 webhook 应用

由于需要根据JQL动态查询Jira列表后输出到飞书IM,必须使用smart values语法来做遍历,输出符合飞书要求的markdown格式webhook消息体。第一个挑战就是markdown,钉钉与企业微信的markdown格式大同小异,切换起来非常容易。但是,飞书格式完全是另外的套路,而且格式似乎没法排版,都在content里。

{
    "msg_type": "interactive",
    
    "card": {
    
        "config": {
        
        "wide_screen_mode": true
   },

    "header": {

        "title": {

            "tag": "plain_text",

            "content": "【小蜜提醒】-项目逾期任务"

        },

        "template":"red"

    },

    "elements": [{

      "tag": "markdown",

      "content": "截至当前,本项目有 **{{issues.size}}** 个任务已逾期,请相关同学尽快处理!{{#issues}}\n --------------\n**项目名称:**{{project.name}} - {{sprint.name}}\n**问题概述:**[{{key}}]({{url}}) {{summary}}\n**结束日期:**{{customField_10307}}\n**经办人:**{{assignee.displayName}}\n{{/}}"
   }]
}}

在官网文档中,发现飞书群自定义机器人支持通过邮箱等@到具体的人,当时对这个功能点很兴奋,因为jira账号是企业邮箱前缀,那么,在jira账号后拼接@company.com,放在webhook消息体内可以完美实现@Jira经办人、报告人、工作日志登记人等。这点在钉钉和企业微信群自定义机器人中是不支持通过邮箱@人的。折腾了几把,总@空人,后来咨询了飞书售前、客服等人都不知道什么原因。最后,来了一个高级技术支持,告诉我只有自建应用才支持通过邮箱来@人。出于安全考虑, 群自定义机器人只能通过open_id来@人。当时心情很复杂,在群聊中也表达了当时的心情,不支持就在官网文档中写明,而不是让用户折腾好久后,被告之此路不通!飞书同学也坦言,涉及到跨团队共同完善用户手册,内部存在一点协同问题。

众所周知,Jira支持Issue层级的自定义字段扩展,但是好像不支持基于User层级的自定义字段扩展(至少一周前是这么认为)。后来再次研究smart values官网手册发现有个Entity Properties概念,可以用来设置User层级的属性,比如:用户手机号、邮箱、家庭住址等等。那么,它也支持在user层级扩展一个飞书open_id字段。通过Jira配置->用户管理->点击用户名->编辑用户属性->添加key/value为openid及其值,来实现为该用户添加一个自定义属性openid,使用实现@人,完整代码如下:

{

    "msg_type": "interactive",

    "card": {

        "config": {

        "wide_screen_mode": true

   },

    "header": {

        "title": {

            "tag": "plain_text",

            "content": "【小蜜提醒】-项目逾期任务"

        },

        "template":"red"

    },

    "elements": [{

      "tag": "markdown",

      "content": "截至当前,本项目有 **{{issues.size}}** 个任务已逾期,请相关同学尽快处理!{{#issues}}\n --------------\n**项目名称:**{{project.name}} - {{sprint.name}}\n**问题概述:**[{{key}}]({{url}}) {{summary}}\n**结束日期:**{{customField_10307}}\n**经办人:**{{assignee.displayName}} <at id = {{assignee.legacyProperties."jira.meta.openid"}}><at>\n{{/}}"

   }]
}}

接下来面临的问题是,如何批量获取飞书open_id?又如何批量更新到Jira系统呢?前者有官网文档说明(不做赘述),后者需要研究下相关Jira数据库表。最终选择的解决方案如下:

CREATE PROCEDURE AddUserPropertywithFeishuOpenID ( userName VARCHAR ( 100 ), openID VARCHAR ( 100 ) ) BEGIN
	DECLARE
		userID INTEGER;
	DECLARE
		propertyID INTEGER;

	SET userID = ( SELECT ID FROM app_user WHERE lower_user_name = userName );

	-- 仅针对未添加用户属性,才执行下面语句
	IF userID is not NULL AND NOT EXISTS(SELECT * FROM propertyentry WHERE ENTITY_NAME = "ApplicationUser" AND ENTITY_ID = userID AND PROPERTY_KEY = "jira.meta.openid") THEN
		BEGIN 
			SET propertyID = ( SELECT MAX( ID ) + 1 FROM propertyentry );
			
			INSERT INTO propertyentry ( ID, ENTITY_NAME, ENTITY_ID, PROPERTY_KEY, propertytype )
			VALUES
				( propertyID, "ApplicationUser", userID, "jira.meta.openid", 5 );
				
			INSERT INTO propertystring ( ID, propertyvalue )
			VALUES
				( propertyID, openID );
		END;
	ELSE
			SELECT userName + "已经存在";
	END IF;

END

-- 调用存储过程添加用户属性:飞书OpenID
CALL AddUserPropertywithFeishuOpenID('yyge','ou_xxxxxxxxxx');

-- 检查脚本
SELECT e.user_key, e.lower_user_name, t.property_key, s.propertyvalue as FieldValue
FROM app_user e 
JOIN propertyentry t ON e.ID = t.entity_id
JOIN propertystring s ON t.ID = s.ID
WHERE t.property_key = "jira.meta.openid"

-- 删除脚本
DELETE FROM propertystring WHERE ID IN (SELECT ID FROM propertyentry WHERE property_key = "jira.meta.openid");
DELETE FROM propertyentry WHERE property_key = "jira.meta.openid";

-- 注意必须将sequence_value_item中的SEQ_ID更新到较大的值,否则上面脚本可能导致无法通过Jira配置后台手工添加user property
select * from sequence_value_item where seq_name = 'OSPropertyEntry';

最后,欢迎加我个人微信交流 craigyoung1985,一起学习和交流。请备注:姓名/城市/工作岗位,我可以拉到 Jira 和Confluence中国社区群。

Categories:

Tags:

Comments are closed