python+tapd+企微機(jī)器人+jenkins實(shí)現(xiàn)工單機(jī)器人

需求背景:

目前業(yè)務(wù)線上問(wèn)題登記在tapd的項(xiàng)目中般渡,客服提單后,各產(chǎn)研無(wú)法感知到有新工單進(jìn)來(lái)。為了提高產(chǎn)研對(duì)線上問(wèn)題的感知度馏艾、提高工單收斂速度。開發(fā)了實(shí)時(shí)機(jī)器人每5分鐘拉取數(shù)據(jù)推送到產(chǎn)研群里奴愉,開發(fā)了超時(shí)機(jī)器人每日下班前推送還未解決的工單琅摩。

技術(shù)棧:

python +mysql+tapd+企微機(jī)器人+jenkins

實(shí)現(xiàn)思路:

一、讀取tapd數(shù)據(jù)

二锭硼、組裝企微機(jī)器人消息體

參考企微官方-群機(jī)器人配置api
https://developer.work.weixin.qq.com/document/path/91770

群機(jī)器人

三房资、企微群中新建機(jī)器人,拿到webhookurl

新建群機(jī)器人

四檀头、python腳本調(diào)用企微機(jī)器人發(fā)送接口推送消息

超時(shí)機(jī)器人效果圖
實(shí)時(shí)機(jī)器人效果圖

五轰异、持續(xù)集成到j(luò)enkins定時(shí)執(zhí)行推送

調(diào)用click模塊封裝好岖沛,編寫shell腳本調(diào)用,jenkins中構(gòu)建添加shell腳本就行搭独。

實(shí)時(shí)機(jī)器人示例:python xx/tapd_remind_robot.py -rtu https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=x -rtn 請(qǐng)?zhí)幚韝x人抓緊處理新工單婴削! -t xx產(chǎn)品中心 -g xx 

完整代碼
-初學(xué)python寫的很臭很長(zhǎng)勿噴

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# @Time    : 2021/5/14 17:06
# @Author  : yanfa
# @File    : tapd_remind_robot.py
# TAPD工單統(tǒng)計(jì)機(jī)器人-超時(shí)、實(shí)時(shí)

import logging
import click
import pymysql
from sshtunnel import SSHTunnelForwarder
import requests
import json

# ssh
SSH_HOST = "xxx"
SSH_PORT = 22
SSH_USERNAME = "xxxx"
SSH_PASSWORD = "xxxx"
REMOTE_BIND_HOST = "xxx"
REMOTE_BIND_PORT = xxxx

# mysql
MYSQL_HOST = "127.0.0.1"
MYSQL_PORT = ""
MYSQL_USER = "xxx"
MYSQL_PASSWD = "xxx"
MYSQL_DB = "xxx"  # tadp主庫(kù)
MYSQL_DB_01 = "xxx"  # 獲取用戶userid
MYSQL_CHARSET = "utf8"

# 定義工單鏈接前半部分
project_path = "https://www.tapd.cn/xxx/bugtrace/bugs/view?bug_id="


class Tapd_Remind_Robot():
    # 初始化必傳的url
    def __init__(self, url):
        self.url = url

    # SSH跳板機(jī)鏈接MySQL數(shù)據(jù)庫(kù)-tadp主庫(kù)
    def connect_mysql(self):
        server = SSHTunnelForwarder(ssh_address_or_host=(SSH_HOST, SSH_PORT),
                                    ssh_username=SSH_USERNAME,
                                    ssh_password=SSH_PASSWORD,
                                    remote_bind_address=(REMOTE_BIND_HOST, REMOTE_BIND_PORT))
        server.start()
        conn = pymysql.connect(host='127.0.0.1',
                               port=server.local_bind_port,
                               user=MYSQL_USER,
                               passwd=MYSQL_PASSWD,
                               db=MYSQL_DB,
                               charset=MYSQL_CHARSET)
        return conn

    # SSH跳板機(jī)鏈接MySQL數(shù)據(jù)庫(kù)-獲取用戶userid
    def connect_mysql01(self):
        server = SSHTunnelForwarder(ssh_address_or_host=(SSH_HOST, SSH_PORT),
                                    ssh_username=SSH_USERNAME,
                                    ssh_password=SSH_PASSWORD,
                                    remote_bind_address=(REMOTE_BIND_HOST, REMOTE_BIND_PORT))
        server.start()
        conn = pymysql.connect(host='127.0.0.1',
                               port=server.local_bind_port,
                               user=MYSQL_USER,
                               passwd=MYSQL_PASSWD,
                               db=MYSQL_DB_01,
                               charset=MYSQL_CHARSET)
        return conn

    # 執(zhí)行SQL命令-tapd庫(kù)
    def execute_sql(self, sql):
        db = self.connect_mysql()
        cursor = db.cursor()

        try:
            cursor.execute(sql)
            results = cursor.fetchall()
            return results
        except:
            print("Error")

        db.close()

    # 執(zhí)行SQL命令-db_user_center庫(kù)
    def execute_sql01(self, sql):
        db = self.connect_mysql01()
        cursor = db.cursor()

        try:
            cursor.execute(sql)
            results = cursor.fetchall()
            return results
        except:
            print("Error")

        db.close()

    # 推送消息
    def post_bot(self, url, data):
        headers = {'Content-Type': 'application/json'}
        response = requests.post(url=url, headers=headers, data=json.dumps(data))
        # 后續(xù)可能有用
        return response

    # 定義tapd_name轉(zhuǎn)化為userid方法
    def find_userid(self, pending_list_01):
        # 不以;結(jié)尾特殊的元素末尾添加;
        list0 = []
        for j in pending_list_01:
            if j.endswith(';'):
                list0.append(j)
            else:
                j = j + ';'
                list0.append(j)
        # print("處理不以;結(jié)尾的元素后:", list0)
        # 第一次去重
        pending_list = list(set(list0))
        # print("第一次去重后的列表為:", pending_list)

        # 定義一個(gè)字符串存儲(chǔ)拼接的用戶信息
        list1 = ''
        for i in pending_list:
            list1 += i
        # print("拼接用戶信息后的列表:", list1)

        # 去除字符最后的字符";"
        list2 = list1.strip(';')
        # print("字符串去除尾部標(biāo)點(diǎn)為:", list2)

        # 切割
        list3 = list2.split(";")
        # print("字符串分割后:", list3)

        # 第二次去重
        list4 = list(set(list3))
        # print("第二次去重后的列表為:", list4)

        # 強(qiáng)轉(zhuǎn)成元祖后再?gòu)?qiáng)轉(zhuǎn)為str拼接在sql
        list5 = str(tuple(list4))
        # print("列表轉(zhuǎn)為元祖再轉(zhuǎn)為str:",list5)

        # 特殊處理元祖只有單個(gè)元素的','
        if len(list4) == 1:
            list6 = []
            for i in list5:
                list6.append(i)
            # print("遍歷字符串:", list6)

            # 刪除倒數(shù)第二個(gè)元素','
            del list6[-2]
            # print('處理嗓蘑,后:', list6)

            # 重新合并
            list7 = "".join(list6)
            # print('重新合并:', str(list7))

            # 拼接sql
            userid_list = "SELECT a.userid FROM t_admin_user a where a.tapd_name in" + list7 + ";"
            print("查詢userid的sql為:", userid_list)
        else:
            # 拼接sql
            userid_list = "SELECT a.userid FROM t_admin_user a where a.tapd_name in" + list5 + ";"
            print("查詢userid的sql為:", userid_list)
        userid_list01 = self.execute_sql01(userid_list)
        # print("處理人userid元祖為:", userid_list01)

        # 定義一個(gè)列表存儲(chǔ)遍歷元祖的值
        list8 = []
        for e in userid_list01:
            list8.append(e[0])  # 只查詢子元祖第一個(gè)值userid
        print('最終處理人列表為:', list8)
        return list8

    # 定義發(fā)送消息主方法
    def send_msg_time_out(self, timeout_notice, title, group_new):
        # 定義查詢語(yǔ)句-有截止時(shí)間,取【當(dāng)前時(shí)間 - 截止時(shí)間】>=0 算超時(shí)
        # 定義被刪除的部分
        deleted = """('xxx')"""
        sql01 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( deadline, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題' AND SUBSTR(a.id,1,12)=114249027600 AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline !='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 0;"
        sql02 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( deadline, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題' AND SUBSTR(a.id,1,12)=xxxAND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline !='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND  a.date >=3 AND a.date <5;"
        sql03 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( deadline, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題' AND SUBSTR(a.id,1,12)=xxxAND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline !='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 5 AND a.date <7;"
        sql04 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( deadline, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題' AND SUBSTR(a.id,1,12)=xxxAND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline !='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 7;"

        # 定義查詢語(yǔ)句-無(wú)截止時(shí)間虫溜,取【當(dāng)前時(shí)間 - 創(chuàng)建時(shí)間】>=3 算超時(shí)
        sql05 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( created, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題'     AND SUBSTR(a.id,1,12)=xxx AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline ='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 3 AND a.date <5;"
        sql06 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( created, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題'     AND SUBSTR(a.id,1,12)=114249027600 AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline ='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 5 AND a.date <7;"
        sql07 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( created, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題'     AND SUBSTR(a.id,1,12)=114249027600 AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline ='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 7;"
        sql08 = "SELECT count(0) FROM(SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( created, '%Y-%m-%d'), CURDATE() ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題'     AND SUBSTR(a.id,1,12)=114249027600 AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline ='0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 3;"
        sql09 = "SELECT * FROM((SELECT a.id, a.title AS '工單標(biāo)題', a.created AS '創(chuàng)建時(shí)間', a.current_owner AS '處理人', a.custom_field_two AS '所屬小組', a.date AS '超時(shí)天數(shù)' FROM (SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( deadline, '%Y-%m-%d'), CURDATE()) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題' AND SUBSTR(a.id,1,12)=114249027600 AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + "AND a.deadline != '0000-00-00 00:00:00' AND a.id NOT IN('xxx','xx','xx') AND a.date >= 0 ) UNION (SELECT a.id, a.title AS '工單標(biāo)題', a.created AS '創(chuàng)建時(shí)間', a.current_owner AS '處理人', a.custom_field_two AS '所屬小組', a.date AS '超時(shí)天數(shù)' FROM (SELECT *, TIMESTAMPDIFF( DAY, DATE_FORMAT( created, '%Y-%m-%d' ), CURDATE( ) ) AS date FROM t_tapd_bug_order ) AS a WHERE a.module = '技術(shù)問(wèn)題' AND SUBSTR(a.id,1,12)=114249027600 AND a.`status` IN ( 'in_progress', 'unconfirmed') AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " AND a.deadline = '0000-00-00 00:00:00' AND a.id NOT IN " + deleted + " AND a.date >= 3 )) AS e ORDER BY e.`超時(shí)天數(shù)` desc;"
        # print("sql01為:%s\nsql02為:%s\nsql03為:%s\nsql04為:%s\nsql05為:%s\nsql06為:%s\nsql06為:%s\nsql08為:%s\nsql09為:%s"%(sql01,sql02,sql03,sql04,sql05,sql06,sql07,sql08,sql09))

        # 超時(shí)定義:
        # 如果填寫了截止時(shí)間或者截止時(shí)間不等于00: 00:00 - ---則取當(dāng)前時(shí)間 - 截止時(shí)間 >= 0算超時(shí)
        # 否則沒(méi)填寫截止時(shí)間,則用當(dāng)前時(shí)間 - 創(chuàng)建時(shí)間 >= 3才算超時(shí)
        # 獲取超時(shí)工單總數(shù)/各天數(shù)股缸,數(shù)據(jù)庫(kù)返回一個(gè)元祖且元素也是元祖衡楞,通過(guò)下標(biāo)取2層值

        # 執(zhí)行后相加處理
        bug_count = self.execute_sql(sql01)[0][0] + self.execute_sql(sql08)[0][0]
        bug_03 = self.execute_sql(sql02)[0][0] + self.execute_sql(sql05)[0][0]
        bug_05 = self.execute_sql(sql03)[0][0] + self.execute_sql(sql06)[0][0]
        bug_07 = self.execute_sql(sql04)[0][0] + self.execute_sql(sql07)[0][0]
        bug_all = self.execute_sql(sql09)
        print("全部超時(shí)個(gè)數(shù)為:", bug_count)
        # print("超時(shí)3天個(gè)數(shù)為:", bug_03)
        # print("超時(shí)5天個(gè)數(shù)為:", bug_05)
        # print("超時(shí)7天個(gè)數(shù)為:", bug_07)
        # print("sql09為:",sql09)
        # print("bug_all為:", bug_all)

        # 推送的報(bào)文 %d格式化數(shù)值,%s格式化字符敦姻,多個(gè)值用%(a,b,c)
        # 定義匯總部分
        head = """>【%s】\n超時(shí)工單數(shù)量匯總:<font color = "warning">%d單</font>\n>超時(shí)三天: <font color = "comment">%d單</font>\n>超時(shí)五天: <font color = "comment">%d單</font>\n>超時(shí)七天: <font color = "comment">%d單</font>""" % (
            title, bug_count, bug_03, bug_05, bug_07)

        # 定義詳細(xì)清單-壓縮前
        body = ''
        pending_list_01 = []
        for i in bug_all:
            # 將處理人遍歷存儲(chǔ)至新列表pending_list_01
            pending_list_01.append(i[3])
            body01 = """\n\n>工單標(biāo)題:<font color="comment">%s</font>\n>工單鏈接:[%s%s](%s%s)\n>創(chuàng)建時(shí)間:<font color="comment">%s</font>\n>處理人:<font color="comment">%s</font>\n>所屬小組:<font color="comment">%s</font>\n>超時(shí)天數(shù):<font color="warning">%s天</font>""" % (
                i[1], project_path, i[0], project_path, i[0], i[2], i[3], i[4], i[5])
            # 前后加空格換行瘾境,+=遍歷疊加
            body += '\n\n' + body01 + '\n\n'
        # print("處理人列表為:", pending_list_01)
        # 定義請(qǐng)求報(bào)文,將2部分字符串拼接
        markdown = {
            "msgtype": "markdown",
            "markdown": {
                "content": head + body
            }
        }

        # 定義詳細(xì)清單-壓縮后(因?yàn)榻涌赾ontent字節(jié)數(shù)不能大于4096镰惦,所以需要壓縮)
        body_short = ''
        pending_list_01 = []
        for i in bug_all:
            # 將處理人遍歷存儲(chǔ)至新列表pending_list_01
            pending_list_01.append(i[3])
            body_short_01 = """\n\n>工單標(biāo)題:<font color="comment">%s</font>\n>處理人:<font color="comment">%s</font>\n>超時(shí)天數(shù):<font color="warning">%s天</font>""" % (
                i[1], i[3], i[5])
            # 前后加空格換行寄雀,+=遍歷疊加
            body_short += '\n\n' + body_short_01 + '\n\n'
        # print("處理人列表為:", pending_list_01)
        # 定義請(qǐng)求報(bào)文,將2部分字符串拼接
        markdown_short = {
            "msgtype": "markdown",
            "markdown": {
                "content": head + body_short
            }
        }

        # 獲取content字節(jié)數(shù),注意采用 UTF-8 編碼方式陨献,先
        # 使用 encode() 方法盒犹,將字符串進(jìn)行編碼后再獲取它的字節(jié)數(shù)
        count_byte = len((head + body).encode())
        short_count_byte = len((head + body_short).encode())
        print("壓縮前content字節(jié)數(shù)為:", count_byte)
        print("壓縮后content字節(jié)數(shù)為:", short_count_byte)

        # 添加判斷,超時(shí)工單數(shù)為0且大于4096字節(jié)則不執(zhí)行
        if bug_count != 0:
            if count_byte <= 4096:
                # print("超時(shí)工單匯總明細(xì)為:",markdown)
                resp01 = self.post_bot(url=self.url, data=markdown)
                # print("超時(shí)工單匯總明細(xì)-響應(yīng)為:", resp01.text)
                assert resp01.text.__contains__("""errmsg":"ok""")
                print("超時(shí)工單匯總明細(xì)-發(fā)送成功")

                # 定義@處理人的消息
                notice = {
                    "msgtype": "text",
                    "text": {
                        "content": timeout_notice,
                        "mentioned_list": self.find_userid(pending_list_01)  # 調(diào)用用戶userid轉(zhuǎn)化方法
                    }
                }
                resp02 = self.post_bot(url=self.url, data=notice)
                print("通知處理人消息為:", notice)
                # print("通知處理人消息-響應(yīng)為", resp02.text)
                assert resp02.text.__contains__("""errmsg":"ok""")
                print("通知處理人-發(fā)送成功")
            elif short_count_byte <= 4096:
                # print("超時(shí)工單匯總明細(xì)為:", markdown_short)
                resp01 = self.post_bot(self.url, markdown_short)
                # print("超時(shí)工單匯總明細(xì)-響應(yīng)為:", resp01.text)
                assert resp01.text.__contains__("""errmsg":"ok""")
                print("超時(shí)工單匯總明細(xì)-發(fā)送成功")

                # 定義@處理人的消息
                notice = {
                    "msgtype": "text",
                    "text": {
                        "content": timeout_notice,
                        "mentioned_list": self.find_userid(pending_list_01)  # 調(diào)用用戶userid轉(zhuǎn)化方法
                    }
                }
                print("通知處理人消息為:", notice)
                resp02 = self.post_bot(self.url, notice)
                # print("通知處理人消息-響應(yīng)為:", resp02.text)
                assert resp02.text.__contains__("""errmsg":"ok""")
                print("通知處理人-發(fā)送成功")
            else:
                # print("壓縮前-超時(shí)工單匯總明細(xì)為:",markdown)
                # print("壓縮后-超時(shí)工單匯總明細(xì)為:", markdown_short)
                head = """>\n【%s】\n超時(shí)工單數(shù)量匯總:<font color = "warning">%d單</font>\n>超時(shí)三天: <font color = "comment">%d單</font>\n>超時(shí)五天: <font color = "comment">%d單</font>\n>超時(shí)七天: <font color = "comment">%d單</font>\n\n""" % (
                    title, bug_count, bug_03, bug_05, bug_07)
                body_short = ''
                top = '\n【超時(shí)工單Top10】\n'
                pending_list_01 = []
                # 壓縮后還是大于4098則只取top10
                for i in bug_all[:10]:
                    # 將處理人遍歷存儲(chǔ)至新列表pending_list_01
                    pending_list_01.append(i[3])
                    body_short_01 = """>工單標(biāo)題:<font color="comment">%s</font>\n>處理人:<font color="comment">%s</font>\n>超時(shí)天數(shù):<font color="warning">%s天</font>""" % (
                        i[1], i[3], i[5])
                    # 前后加空格換行眨业,+=遍歷疊加
                    body_short += '\n\n' + body_short_01 + '\n\n'
                print("前10處理人列表為:", pending_list_01)
                short_count_byte = len((head + top + body_short).encode())
                print('壓縮后前10條長(zhǎng)度為:', short_count_byte)

                # 定義請(qǐng)求報(bào)文急膀,將2部分字符串拼接
                markdown_short = {
                    "msgtype": "markdown",
                    "markdown": {
                        "content": head + top + body_short
                    }
                }

                # 定義@處理人的消息
                notice = {
                    "msgtype": "text",
                    "text": {
                        "content": timeout_notice,
                        "mentioned_list": self.find_userid(pending_list_01)  # 調(diào)用用戶userid轉(zhuǎn)化方法
                    }
                }

                resp01 = self.post_bot(self.url, markdown_short)
                # print("超時(shí)工單匯總明細(xì)-響應(yīng)為:", resp01.text)
                assert resp01.text.__contains__("""errmsg":"ok""")
                print("超時(shí)工單匯總明細(xì)-發(fā)送成功")

                print("通知處理人消息為:", notice)
                resp02 = self.post_bot(self.url, notice)
                # print("通知處理人消息-響應(yīng)為:", resp02.text)
                assert resp02.text.__contains__("""errmsg":"ok""")
                print("通知處理人-發(fā)送成功")
                # logging.error("字節(jié)數(shù)為%s,markdown內(nèi)容最長(zhǎng)不超過(guò)4096個(gè)字節(jié)" % short_count_byte)
        else:
            logging.error("暫無(wú)超時(shí)記錄")

    def send_msg_real_time(self, realtime_notice, title, group_new):
        # 定義查詢語(yǔ)句
        realtime_count_sql = "SELECT COUNT(0) from(SELECT min(b.created),b.bug_id FROM t_tapd_bug_order a, t_tapd_bug_order_change b WHERE a.id = b.bug_id AND b.bug_id IN(SELECT b.bug_id FROM t_tapd_bug_order_change b WHERE b.created >= DATE_SUB( now(), INTERVAL 15 MINUTE ) AND SUBSTR( b.bug_id, 1, 12 ) = xxx AND b.old_value = 'feedback' AND b.new_value = 'unconfirmed') AND DATE_FORMAT( a.created, '%Y-%m-%d' ) = date_sub( curdate( ), INTERVAL 0 DAY ) AND a.module = '技術(shù)問(wèn)題' AND SUBSTR( a.id, 1, 12 ) = xxx AND a.`status` = 'unconfirmed' AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " GROUP BY b.bug_id ORDER BY b.bug_id) AS c;"
        realtime_list_sql = "SELECT a.id, a.title AS '工單標(biāo)題', a.custom_field_four AS '店鋪', a.bugtype AS '類型', a.`status` AS '英文狀態(tài)',( CASE WHEN a.`status` = 'feedback' THEN '待核實(shí)' WHEN a.`status` = 'acknowledged' THEN '已核實(shí)' WHEN a.`status` = 'unconfirmed' THEN '待評(píng)估' END) AS '狀態(tài)', a.current_owner AS '處理人', a.custom_field_two AS '所屬小組' FROM t_tapd_bug_order a, t_tapd_bug_order_change b WHERE a.id = b.bug_id AND b.created IN ( SELECT min( b.created ) FROM t_tapd_bug_order a, t_tapd_bug_order_change b WHERE a.id = b.bug_id AND b.bug_id IN ( SELECT DISTINCT b.bug_id FROM t_tapd_bug_order_change b WHERE b.created >= DATE_SUB( now( ), INTERVAL 15 MINUTE ) AND SUBSTR( b.bug_id, 1, 12 ) = xxx AND b.old_value = 'feedback' AND b.new_value = 'unconfirmed' ) AND DATE_FORMAT( a.created, '%Y-%m-%d' ) = date_sub( curdate( ), INTERVAL 0 DAY ) AND a.module = '技術(shù)問(wèn)題' AND SUBSTR( a.id, 1, 12 ) = xxx AND a.`status` = 'unconfirmed' AND SUBSTR(a.custom_field_two,1,6) = " + group_new + " GROUP BY b.bug_id ORDER BY b.bug_id );"

        print("第一個(gè)sql為:%s\n第二個(gè)sql為:%s" % (realtime_count_sql, realtime_list_sql))

        # 執(zhí)行查詢語(yǔ)句
        realtime_bug_count = self.execute_sql(realtime_count_sql)[0][0]
        realtime_bug_detail = self.execute_sql(realtime_list_sql)
        print("新增工單數(shù)為:", realtime_bug_count)

        # 推送的報(bào)文 %d格式化數(shù)值龄捡,%s格式化字符卓嫂,多個(gè)值用%(a,b,c)
        # 定義匯總部分
        head = """>【%s】\n當(dāng)前新增技術(shù)工單數(shù):<font color = "warning">%d單</font>""" % (title, realtime_bug_count)

        # 定義詳細(xì)清單-壓縮前
        body = ''
        pending_list_01 = []
        for i in realtime_bug_detail:
            pending_list_01.append(i[6])
            # 鏈接需要[鏈接名稱](http://www....)
            body01 = """\n\n>工單標(biāo)題:<font color="comment">%s</font>\n>工單鏈接:[%s%s](%s%s)\n>店鋪:<font color="comment">%s</font>\n>類型:<font color="comment">%s</font>\n>狀態(tài):<font color="comment">%s</font>\n>處理人:<font color="comment">%s</font>\n>所屬小組:<font color="comment">%s</font>""" % (
                i[1], project_path, i[0], project_path, i[0], i[2], i[3], i[5], i[6], i[7])

            # 前后加空格換行,+=遍歷疊加
            body += '\n\n' + body01 + '\n\n'

        # print("處理人列表為:", pending_list_01)

        # 定義請(qǐng)求報(bào)文聘殖,將2部分字符串拼接
        markdown = {
            "msgtype": "markdown",
            "markdown": {
                "content": head + body
            }
        }

        # 定義詳細(xì)清單-壓縮后
        body_short = ''
        pending_list_01 = []
        for i in realtime_bug_detail:
            pending_list_01.append(i[6])
            # 鏈接需要[鏈接名稱](http://www....)
            body_short_01 = """\n\n>工單標(biāo)題:<font color="comment">%s</font>\n>工單鏈接:[%s%s](%s%s)\n>處理人:<font color="comment">%s</font>""" % (
                i[1], project_path, i[0], project_path, i[0], i[6])

            # 前后加空格換行晨雳,+=遍歷疊加
            body_short += '\n\n' + body_short_01 + '\n\n'

        markdown_short = {
            "msgtype": "markdown",
            "markdown": {
                "content": head + body_short
            }
        }

        # 獲取content字節(jié)數(shù),注意采用 UTF-8 編碼方式,先
        # 使用 encode() 方法奸腺,將字符串進(jìn)行編碼后再獲取它的字節(jié)數(shù)
        count_byte = len((head + body).encode())
        short_count_byte = len((head + body_short).encode())
        # print("content字節(jié)數(shù)為:", count_byte)

        # 添加判斷餐禁,實(shí)時(shí)工單數(shù)為0且大于4096字節(jié)則不執(zhí)行
        if realtime_bug_count != 0:
            # 定義@處理人的消息
            notice = {
                "msgtype": "text",
                "text": {
                    "content": realtime_notice,
                    "mentioned_list": self.find_userid(pending_list_01)  # 調(diào)用用戶userid轉(zhuǎn)化方法
                }
            }
            if count_byte <= 4096:
                # print("新工單匯總明細(xì)為:",markdown)
                resp01 = self.post_bot(self.url, markdown)
                # print("新工單匯總明細(xì)-響應(yīng)為:", resp01.text)
                assert resp01.text.__contains__("""errmsg":"ok""")
                print("新工單匯總明細(xì)-發(fā)送成功")

                print("通知處理人消息為:", notice)
                resp02 = self.post_bot(self.url, notice)
                # print("通知處理人消息-響應(yīng)為:", resp02.text)
                assert resp02.text.__contains__("""errmsg":"ok""")
                print("通知處理人-發(fā)送成功")
            elif short_count_byte <= 4096:
                # print("新工單匯總明細(xì)為:", markdown_short)
                resp01 = self.post_bot(self.url, markdown_short)
                # print("新工單匯總明細(xì)-響應(yīng)為:", resp01.text)
                assert resp01.text.__contains__("""errmsg":"ok""")
                print("新工單匯總明細(xì)-發(fā)送成功")

                print("通知處理人消息為:", notice)
                resp02 = self.post_bot(self.url, notice)
                # print("通知處理人消息-響應(yīng)為:", resp02.text)
                assert resp02.text.__contains__("""errmsg":"ok""")
                print("通知處理人-發(fā)送成功")
            else:
                logging.error("字節(jié)數(shù)為%s,markdown內(nèi)容最長(zhǎng)不超過(guò)4096個(gè)字節(jié)" % short_count_byte)
        else:
            logging.error("暫無(wú)新記錄")

    # 定義產(chǎn)研自動(dòng)轉(zhuǎn)化分組方法
    def group_transform(self, group):
        group_list=['xx','xx','xx']
        if group in group_list:
            group = "'" + group + "產(chǎn)品中心'"
        else:
            logging.error("請(qǐng)?zhí)顚懻_的產(chǎn)研名稱")
        return group

@click.command()
@click.option('-rtu', '--realtime_url', required=False, help='定義實(shí)時(shí)工單機(jī)器人webhook,為url格式突照,如 https://qyapi.weixin.qq.com')
@click.option('-rtn', '--realtime_notice', required=False, default='請(qǐng)?zhí)幚砣俗ゾo處理新工單帮非!', type=str, help='定義實(shí)時(shí)工單處理人的提醒文案')
@click.option('-tou', '--timeout_url', required=False, help='定義超時(shí)工單機(jī)器人webhook,為url格式,如 https://qyapi.weixin.qq.com')
@click.option('-ton', '--timeout_notice', required=False, default='請(qǐng)?zhí)幚砣俗ゾo處理超時(shí)工單!', type=str, help='定義超時(shí)工單處理人的提醒文案')
@click.option('-t', '--title', required=False, default='數(shù)據(jù)產(chǎn)品中心', type=str, help='定義標(biāo)題末盔,如【數(shù)據(jù)產(chǎn)品中心】')
@click.option('-g', '--group', required=False, default='數(shù)據(jù)', type=str,
              help="定義處理人所在產(chǎn)研,如基礎(chǔ)或者9筑舅,映射關(guān)系為:1-直播 2-營(yíng)銷 3-xxxx 4-xxx ")
# 定義機(jī)器人運(yùn)行方法
# 實(shí)時(shí)機(jī)器人示例:python test/py_interface_automation/tapd_remind_robot.py -rtu https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=x -rtn 請(qǐng)?zhí)幚韝x人抓緊處理新工單! -t xx產(chǎn)品中心 -g xx
# 超時(shí)機(jī)器人示例:python test/py_interface_automation/tapd_remind_robot.py -tou https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx -ton 請(qǐng)?zhí)幚砣俗ゾo處理超時(shí)工單陨舱!-t xx產(chǎn)品中心 -g xx
def run_remind(timeout_url, realtime_url, timeout_notice='', realtime_notice='', title='', group=''):
    # 添加判斷超時(shí)機(jī)器人url對(duì)象存在且實(shí)時(shí)機(jī)器人url對(duì)象不存在
    if timeout_url is not None and realtime_url is None:
        print("url為:%s\n提醒信息為:%s\n標(biāo)題為:%s\n處理分組前:%s" % (timeout_url, timeout_notice, title, group))
        # 實(shí)例化
        trr = Tapd_Remind_Robot(timeout_url)
        # 調(diào)用發(fā)送超時(shí)工單提醒方法
        group_new = trr.group_transform(group)
        print("處理分組后:", group_new)
        trr.send_msg_time_out(timeout_notice, title, group_new)
    elif realtime_url is not None and timeout_url is None:
        print("url為:%s\n提醒信息為:%s\n標(biāo)題為:%s\n處理分組前:%s" % (realtime_url, realtime_notice, title, group))
        # 實(shí)例化
        trr = Tapd_Remind_Robot(realtime_url)
        # 調(diào)用發(fā)送實(shí)時(shí)工單提醒方法
        group_new = trr.group_transform(group)
        print("處理分組后:", group_new)
        trr.send_msg_real_time(realtime_notice, title, group_new)
    else:
        logging.error("請(qǐng)錄入正確的url")


if __name__ == '__main__':
    # 調(diào)用主運(yùn)行方法
    run_remind()```





?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載翠拣,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。
  • 序言:七十年代末游盲,一起剝皮案震驚了整個(gè)濱河市心剥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌背桐,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝉揍,死亡現(xiàn)場(chǎng)離奇詭異链峭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)又沾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門弊仪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人杖刷,你說(shuō)我怎么就攤上這事励饵。” “怎么了滑燃?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵役听,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我表窘,道長(zhǎng)典予,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任乐严,我火速辦了婚禮瘤袖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昂验。我一直安慰自己捂敌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布既琴。 她就那樣靜靜地躺著占婉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪甫恩。 梳的紋絲不亂的頭發(fā)上锐涯,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音填物,去河邊找鬼纹腌。 笑死霎终,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的升薯。 我是一名探鬼主播莱褒,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涎劈!你這毒婦竟也來(lái)了广凸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蛛枚,失蹤者是張志新(化名)和其女友劉穎谅海,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹦浦,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扭吁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盲镶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侥袜。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溉贿,靈堂內(nèi)的尸體忽然破棺而出枫吧,到底是詐尸還是另有隱情,我是刑警寧澤宇色,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布九杂,位于F島的核電站,受9級(jí)特大地震影響宣蠕,放射性物質(zhì)發(fā)生泄漏尼酿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一植影、第九天 我趴在偏房一處隱蔽的房頂上張望裳擎。 院中可真熱鬧,春花似錦思币、人聲如沸鹿响。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惶我。三九已至,卻和暖如春博投,著一層夾襖步出監(jiān)牢的瞬間绸贡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留听怕,地道東北人捧挺。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像尿瞭,于是被迫代替她去往敵國(guó)和親闽烙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容