class DingtalkRobot(object): """ 钉钉机器人类 :param param1: this is a first param :param param2: this is a second param :returns: this is a description of what is returned :raises keyError: raises an exception @author: jhuang @time:02/04/2018 """ def __init__(self, access_token): self.access_token = access_token self.send_api = 'https://oapi.dingtalk.com/robot/send' self.ohttp = HttpClass(headers={"Content-Type": "application/json"}) def send_text_msg(self, text): """ 钉钉机器人发送消息 :param param1: this is a first param :param param2: this is a second param :returns: this is a description of what is returned :raises keyError: raises an exception @author: jhuang @time:02/04/2018 """ jsons = {"msgtype": "text", "text": {"content": text}} jsons = json.dumps(jsons) ret = self.ohttp.post('%s?access_token=%s' % (self.send_api, self.access_token), payload=jsons) api_ret_json = json.loads(ret[1]) if int(api_ret_json['errcode']) > 0: raise Exception('接口返回错误:%s' % ret[1]) return ret def send_link_msg(self, title, text, picUrl, messageUrl): jsons = {"msgtype": "link", "link": {"text": text, "title": title, "picUrl": picUrl, "messageUrl": messageUrl } } jsons = json.dumps(jsons) ret = self.ohttp.post('%s?access_token=%s' % (self.send_api, self.access_token), payload=jsons) api_ret_json = json.loads(ret[1]) if int(api_ret_json['errcode']) > 0: raise Exception('接口返回错误:%s' % ret[1]) return ret
class Dingtalk(object): def __init__(self, corpid, corpsecret): self.corpid = corpid self.corpsecret = corpsecret self.access_token = '' self.http_obj = HttpClass(headers={"Content-Type": "application/json"}) self.__gettoken() def get_data_by_get(self, api): try: res, res_text, res_time = self.http_obj.get(api) res_dict = json.loads(res_text) if res_dict['errcode'] == 0: return res_dict else: raise Exception('errcode: ' + str(res_dict['errcode']) + res_dict['errmsg'].encode('utf8')) except Exception as e: logger.error(e) raise # logger.error("请求dingding API返回: " + e.message) # raise Exception("请求dingding API返回: " + e.message) def get_data_by_post(self, api, payload): try: res, res_text = self.http_obj.post(api, payload) res_dict = json.loads(res_text) if res_dict['errcode'] == 0: return res_dict else: raise Exception('errcode: ' + str(res_dict['errcode']) + res_dict['errmsg'].encode('utf8')) except Exception as e: logger.error(e) raise # logger.error("请求dingding API返回: " + e.message) # raise Exception("请求dingding API返回: " + e.message) @retry(stop_max_attempt_number=20, wait_fixed=8000) def __gettoken(self): # api https://oapi.dingtalk.com/gettoken?corpid=id&corpsecret=secrect # 检查mysql 连接是否可用 try: from django.db import connections for conn in connections.all(): conn.close_if_unusable_or_obsolete() except Exception as e: logger.error( '关闭无效数据库连接失败 %s conn.close_if_unusable_or_obsolete()' % e) try: logger.info('从数据库获取dingtalk_token_info') obj_sysparam = SysParam.objects.get( param_name='dingtalk_token_info') dingtalk_token_info = obj_sysparam.param_value except ObjectDoesNotExist as e: dingtalk_token_info = None except Exception as e: logger.error(e) raise def __set_token(): api = """{}/gettoken?corpid={}&corpsecret={}""".format( Dingtalk_API, self.corpid, self.corpsecret) res_dict = self.get_data_by_get(api) self.access_token = res_dict['access_token'] dingtalk_token_info = "%s|%s|%s" % ( time.time(), res_dict['expires_in'], res_dict['access_token']) obj_sysparam = SysParam.objects.get( param_name='dingtalk_token_info') obj_sysparam.param_value = dingtalk_token_info obj_sysparam.save() logger.info('dingtalk_token_info %s,获取dingtalk token' % dingtalk_token_info) if dingtalk_token_info is None: logger.info('dingtalk_token_info not exists, 重新设置token') __set_token() else: get_time = float(dingtalk_token_info.split('|')[0]) expires_in = float(dingtalk_token_info.split('|')[1]) access_token = str(dingtalk_token_info.split('|')[2]) now_time = time.time() if now_time - get_time >= expires_in: logger.info('dingtalk_token_info %s已经过期,重新获取' % dingtalk_token_info) __set_token() else: self.access_token = access_token def get_all_department(self, only_get_id=True): """ 获取部门列表(非详情) @author: lanxiong @time:2018/8/15 """ dpt_list = list() api = """{}/department/list?access_token={}""".format( Dingtalk_API, self.access_token) res_dict = self.get_data_by_get(api) if only_get_id is True: for dpt in res_dict['department']: dpt_list.append(dpt['id']) return dpt_list else: return res_dict['department'] def get_department_member_userids_list_by_dptid(self, department_id): """ 获取部门用户userid列表 @author: lanxiong @time:2018/8/15 """ # https: //oapi.dingtalk.com/user/getDeptMember?access_token = ACCESS_TOKEN & deptId = 1 api = """{}/user/getDeptMember?access_token={}&deptId={}""".format( Dingtalk_API, self.access_token, department_id) res_dict = self.get_data_by_get(api) return res_dict['userIds'] def get_all_member(self, only_get_id=True): """ 获取所有员工 @author: lanxiong @time:2018/8/16 """ all_user = list() all_user_id = list() dptid_list = self.get_all_department(only_get_id=True) for dptid in dptid_list: dept_users_list = self.get_department_member_userids_list_by_dptid( dptid) for i in dept_users_list: all_user_id.append(i) if only_get_id is True: return all_user_id else: for id in all_user_id: user = self.get_user_detail_by_userid(id) all_user.append(user) return all_user def get_user_detail_by_userid(self, userid): """ 获取员工详情 @author: lanxiong @time:2018/8/15 """ api = """{}/user/get?access_token={}&userid={}""".format( Dingtalk_API, self.access_token, userid) res_dict = self.get_data_by_get(api) return res_dict def get_attendance_by_departmentid(self, department_id, checkDateFrom, checkDateTo): """ 获取部门考勤详细信息 https://oapi.dingtalk.com/attendance/listRecord?access_token=ACCESS_TOKEN @author: lanxiong @time:2018/8/15 """ pass def get_attendance_by_userids_list(self, userids_list, checkDateFrom, checkDateTo): """ 获取员工详细考勤信息 { "userIds": ["001","002"], "checkDateFrom": "yyyy-MM-dd hh:mm:ss", "checkDateTo": "yyyy-MM-dd hh:mm:ss", "isI18n":"false" } @author: lanxiong @time:2018/8/15 """ api = """{}/attendance/listRecord?access_token={}""".format( Dingtalk_API, self.access_token) payload = { "userIds": userids_list, "checkDateFrom": str(checkDateFrom), "checkDateTo": str(checkDateTo), "isI18n": "false" } res_dict = self.get_data_by_post(api, json.dumps(payload)) return res_dict def get_attendance_by_userid(self, userid, checkDateFrom, checkDateTo): """ 获取员工详细考勤信息 { "userIds": ["001"], "checkDateFrom": "yyyy-MM-dd hh:mm:ss", "checkDateTo": "yyyy-MM-dd hh:mm:ss", "isI18n":"false" } @author: lanxiong @time:2018/8/15 """ api = """{}/attendance/listRecord?access_token={}""".format( Dingtalk_API, self.access_token) payload = { "userIds": [userid], "checkDateFrom": str(checkDateFrom), "checkDateTo": str(checkDateTo), "isI18n": "false" } res_dict = self.get_data_by_post(api, json.dumps(payload)) return res_dict def get_processinstance_by_id(self, process_instance_id): """ 获取单个审批实例 Doc: https://open-doc.dingtalk.com/microapp/serverapi2/xgqkvx API: https://oapi.dingtalk.com/topapi/processinstance/get?access_token=ACCESS_TOKEN @author: lanxiong @time:2018/8/16 """ api = """{}/topapi/processinstance/get?access_token={}""".format( Dingtalk_API, self.access_token) payload = {"process_instance_id": process_instance_id} logger.info(self.access_token) res_dict = self.get_data_by_post(api, json.dumps(payload)) return res_dict def get_processinstance_list(self, process_code, start_time, **kwargs): """ 批量获取审批实例 Doc: https://open-doc.dingtalk.com/microapp/serverapi2/fpn98d API: https://oapi.dingtalk.com/topapi/processinstance/list?access_token=ACCESS_TOKEN process_code: 流程模板唯一标识 start_time: 时间戳毫秒 @author: lanxiong @time:2018/8/16 """ api = """{}/topapi/processinstance/list?access_token={}""".format( Dingtalk_API, self.access_token) payload = { "process_code": process_code, "start_time": start_time, "cursor": 0 } payload.update(kwargs) processinstance_list = list() while True: res_dict = self.get_data_by_post(api, json.dumps(payload)) if res_dict['result']['list']: processinstance_list.extend(res_dict['result']['list']) if 'next_cursor' in res_dict['result']: payload['cursor'] += 1 else: break return processinstance_list def get_processinstance_list_all(self, start_time, **kwargs): """ 获取所有审批实例 start_time 必填 默认获取从指定日期到当前 @author: lanxiong @time:2018/8/18 """ processinstance_all_list = list() for process_code in self.get_process_code_list(): processinstance_list = self.get_processinstance_list( process_code, start_time, **kwargs) if processinstance_list: processinstance_all_list.append(processinstance_list) return processinstance_all_list def get_process_list(self, offset=0, size=100): """ 获取用户可见的审批模板 https://open-doc.dingtalk.com/microapp/serverapi2/fpn98d API: https://oapi.dingtalk.com/topapi/process/listbyuserid?access_token=ACCESS_TOKEN @author: lanxiong @time:2018/8/16 """ # https://oapi.dingtalk.com/topapi/process/listbyuserid?access_token=ACCESS_TOKEN api = """{}/topapi/process/listbyuserid?access_token={}""".format( Dingtalk_API, self.access_token) process_list = list() payload = {"offset": offset, "size": size} while True: res_dict = self.get_data_by_post(api, json.dumps(payload)) for proc in res_dict['result']['process_list']: process_list.append(proc) if 'next_cursor' in res_dict['result']: offset += 1 else: break return process_list def get_process_code_list(self, proc_name_like=''): """ 获取用户可见的审批模板id @author: lanxiong @time:2018/8/16 """ process_code_list = list() for proc in self.get_process_list(): process_code_list.append(proc['process_code']) return process_code_list def get_leave_approve_duration(self, userid, from_date, to_date): """ 获取请假时长 分钟 Doc: https://open-doc.dingtalk.com/microapp/serverapi2/bdz3a3 API: https://oapi.dingtalk.com/topapi/attendance/getleaveapproveduration?access_token=ACCESS_TOKEN @author: lanxiong @time:2018/8/17 """ api = """{}/topapi/attendance/getleaveapproveduration?access_token={}""".format( Dingtalk_API, self.access_token) payload = { "userid": userid, "from_date": from_date, "to_date": to_date } res_dict = self.get_data_by_post(api, json.dumps(payload)) duration_in_minutes = res_dict['result']['duration_in_minutes'] return duration_in_minutes def get_attendance_getsimplegroups(self, **payload): """ 获取考勤组详情 Doc: https://open-doc.dingtalk.com/microapp/serverapi2/tc6f5p API: https://oapi.dingtalk.com/topapi/attendance/getsimplegroups?access_token=ACCESS_TOKEN @author: lanxiong @time:2018/8/20 """ api = """{}/topapi/attendance/getsimplegroups?access_token={}""".format( Dingtalk_API, self.access_token) res_dict = self.get_data_by_post(api, json.dumps(payload)) return res_dict def get_no_attendance(self, userid, start_time, end_time): process_list = self.get_process_list() def get_checkin_by_dpt_id(self, department_id, start_time, end_time): """ 获取签到 Doc: https://open-doc.dingtalk.com/microapp/serverapi2/xmfmlh API: https://oapi.dingtalk.com/checkin/record?access_token=ACCESS_TOKEN&department_id=1&start_time=1467707227000&end_time=1467707240000&offset=0&size=100&order=asc start_time 开始时间。Unix时间戳,如:1520956800000 """ api = """{Dingtalk_API}/checkin/record?access_token={access_token}&department_id={department_id}&start_time={start_time:}&end_time={end_time}""".format( Dingtalk_API=Dingtalk_API, access_token=self.access_token, department_id=department_id, start_time=start_time, end_time=end_time) res_dict = self.get_data_by_get(api) return res_dict['data']
class JiraClass(): def __init__(self): self.username = None self.password = None self.jira = None self.jira_server_url = None def web_login(self, url, username, password): """ | ##@函数目的: 登录 | ##@参数说明: | ##@返回值:登录句柄 | ##@函数逻辑: | ##@开发人:jhuang | ##@时间: """ self.jira_server_url = url if self.jira_server_url[-1] == '/': self.jira_server_url = self.jira_server_ur[:-1] data = {'login': '******', 'os_username': username, 'os_password': password, 'os_destination': '', 'atl_token': type } self.ohttp = HttpClass() logger.debug('登录Jira..user:%s,pwd:%s' % (username, '*')) ret, html = self.ohttp.post(self.jira_server_url + '/login.jsp', data) if not '登录' in html: logger.debug('登录JIRA成功!') else: logger.exception('登录JIRA失败!') return self.ohttp def connect(self, jira_server_url, username, password): ''' [方法说明] 初始化连接(认证,获取对象) [参数说明] server:服务器URL username:登陆用户名 password:登陆密码 [实例] jira_connect('http://www.tjhcc.com.cn:91','jhuang', '****.') ''' self.jira_server_url = jira_server_url if self.jira_server_url[-1] == '/': self.jira_server_url = self.jira_server_url[:-1] self.username = username self.password = password jira_options = {'server': jira_server_url, 'verify': False} logger.debug('连接Jira:%s (%s)' % (jira_server_url, username)) jira = JIRA(options=jira_options, basic_auth=(username, password)) self.jira = jira return self.jira def update_fields(self, issue_key, fields_dict): """ 更新jira自定义字段:https://jira.readthedocs.io/en/master/examples.html#fields :param fields_dict: {'customfield_11403': 1} :param issue_key: pms-299 :returns: this is a description of what is returned :raises keyError: raises an exception @author: jhuang @time:10/10/2018 """ issue = self.jira.issue(issue_key) for idct_key in fields_dict: fields = idct_key all_fields_dict = issue.raw['fields'] text = 0 for all_fields_dict_one in all_fields_dict: if all_fields_dict_one.find(fields): text = 1 if text == 0: return 0 try: issue.update(fields=fields_dict) except Exception as e: return get_except(e) def comment(self, issueKey, comment): ''' 添加评论 [参数说明] issuenum:issue号 ''' # 解决命令行参数:中文问题.decode("GBK") logger.debug('提交jira备注:%s至:%s' % (comment, issueKey)) # comment = self.jira.add_comment(issueKey, comment.decode("GBK")) comment = self.jira.add_comment(issueKey, comment) def resolve_issue(self, issueKey, resolution='6'): ''' 解决ISSUE [参数说明] issuenum:issue号 ''' try: logger.debug('解决jira::%s' % (issueKey)) self.jira.transition_issue(issueKey, '%s' % ('5'), None, resolution={'id': '%s' % resolution}) except Exception as e: get_except(e) def queryIssueLink(self, issueKey): """查询关联的ISSUE""" oIssue = self.jira.issue('ZJYYXM-201') ''' In [2]: issue. issue.delete issue.fields issue.id issue.raw issue.update issue.expand issue.find issue.key issue.self In [2]: issue.fields. issue.fields.aggregateprogress issue.fields.customfield_11531 issue.fields.aggregatetimeestimate issue.fields.customfield_11631 issue.fields.aggregatetimeoriginalestimate issue.fields.customfield_11930 issue.fields.aggregatetimespent issue.fields.customfield_12130 issue.fields.assignee issue.fields.customfield_12131 issue.fields.attachment issue.fields.description issue.fields.comment issue.fields.environment issue.fields.components issue.fields.fixVersions issue.fields.created issue.fields.issuelinks issue.fields.customfield_10150 issue.fields.issuetype issue.fields.customfield_10160 issue.fields.labels issue.fields.customfield_10161 issue.fields.mro issue.fields.customfield_10180 issue.fields.progress issue.fields.customfield_10230 issue.fields.project issue.fields.customfield_10575 issue.fields.reporter issue.fields.customfield_10610 issue.fields.resolution issue.fields.customfield_10650 issue.fields.resolutiondate issue.fields.customfield_10651 issue.fields.status issue.fields.customfield_10680 issue.fields.subtasks issue.fields.customfield_10723 issue.fields.summary issue.fields.customfield_11130 issue.fields.timeestimate issue.fields.customfield_11230 issue.fields.timeoriginalestimate issue.fields.customfield_11431 issue.fields.timespent issue.fields.customfield_11433 issue.fields.updated issue.fields.customfield_11434 issue.fields.versions issue.fields.customfield_11435 issue.fields.votes issue.fields.customfield_11436 issue.fields.watches issue.fields.customfield_11437 issue.fields.workratio''' # logger.info ('关联的ISSUE:%s' %(oIssue.fields.attachment)) for IssueLink in oIssue.fields.RemoteLinks: print IssueLink def _search_issue(self, searchText, childTask=False): """ |##desc: 子函数 支持包含多个KEY的LIST 返回: list |##:param: None |##:return: None |##@author: jhuang |##@time:2017/8/22 """ if isinstance(searchText, list) is True: keys = ','.join(searchText) JiraList = [] searchJQL = 'key in (%s)' % (keys) searchText = searchJQL logger.debug('jira搜索:%s' % (searchJQL)) issues = self.jira.search_issues(searchText) arrays = [] attachmentList = [] for issue in issues: dic = {} dic['jira_name'] = issue.key dic['jira_summary'] = issue.fields.summary dic['environment'] = issue.fields.environment dic['jira_status'] = issue.fields.status.name dic['jira_status_id'] = issue.fields.status.id dic['description'] = issue.fields.description dic['issue_type'] = issue.fields.issuetype.name # 获取修复版本 str_fix_version = '' for fixVersion in issue.fields.fixVersions: str_fix_version = str_fix_version + fixVersion.name + ',' dic['str_fix_version'] = str_fix_version[:-1] dic['reporter'] = str(issue.fields.reporter) # 报告人 dic['reporter_email'] = str(issue.fields.reporter.emailAddress) # 报告人邮箱 dic['assignee_email'] = str(issue.fields.assignee.emailAddress) # 经办人邮箱 dic['assignee'] = str(issue.fields.assignee) # 经办人 dic['status'] = str(issue.fields.status) dic['issue_url'] = '%s/browse/%s' % (self.jira_server_url, issue.key) theIssue = self.jira.issue(issue.key) # logger.info ('获取附件信息:%s' %(theIssue.fields.attachment)) for attachment in theIssue.fields.attachment: attachmentDic = {} attachmentDic['id'] = attachment.id attachmentDic['filename'] = attachment.filename attachmentList.append(attachmentDic) logger.debug(attachmentList) dic['attachment'] = attachmentList arrays.append(dic) return arrays def jql_search_to_list(self, searchText, searchChildIssue=False, searchRelIssue=False, both=False, maxResult=500): """ |##@函数目的:issue 的高级搜索 结果输出为LIST |##@参数说明:affectedVersion ='SRMC-15 |##@返回值: |##@函数逻辑: |##@开发人:JHUANG |##@时间: """ try: logger.debug(searchText) lists = [] issues = self.jira.search_issues(searchText, 0, maxResult) n = 0 for issue in issues: pdic = {} try: customfield_10800 = issue.fields.customfield_10800 except: customfield_10800 = '' pdic['customfield_10800'] = customfield_10800 pdic['index'] = n pdic['rel_type'] = 'parentIssue' pdic['parent_issue_key'] = '' pdic['rel_issues'] = '' pdic['jira_name'] = str(issue.key) parentKey = str(issue.key) pdic['jira_summary'] = issue.fields.summary pdic['environment'] = issue.fields.environment pdic['jira_status'] = issue.fields.status.name pdic['jira_statu_id'] = issue.fields.status.id pdic['description'] = issue.fields.description # 问题类型 缺陷/严重等 pdic['issue_type'] = issue.fields.issuetype.name # 获取修复版本 str_fix_version = '' for fixVersion in issue.fields.fixVersions: str_fix_version = str_fix_version + fixVersion.name + ',' pdic['str_fix_version'] = str_fix_version[:-1] pdic['reporter'] = str(issue.fields.reporter) # 报告人 pdic['assignee'] = str(issue.fields.assignee) # 经办人 pdic['reporter_email'] = str(issue.fields.reporter.emailAddress) # 报告人邮箱 pdic['assignee_email'] = str(issue.fields.assignee.emailAddress) # 经办人邮箱 # dic['status'] = str(issue.fields.status) # for issueLink in issue.fields.linkedIssues: # print issueLink pdic['issue_url'] = '%s/browse/%s' % (self.jira_server_url, issue.key) pdic['created_time'] = str(issue.fields.created).replace('T', ' ')[0:19] pdic['updated_time'] = str(issue.fields.updated).replace('T', ' ')[0:19] pdic['duedate'] = str(issue.fields.duedate).replace('T', ' ')[0:19] pdic['resolution'] = str(issue.fields.resolution) pdic['resolutiondate'] = str(issue.fields.resolutiondate).replace('T', ' ')[0:19] n += 1 relIssueList = [] if both: logger.debug('查询子任务+关联任务...%s' % parentKey) childIssues = self.jira.search_issues( 'parent =%s or issue in linkedIssues(%s)' % (parentKey, parentKey)) for issue in childIssues: dic = {} dic['index'] = n dic['rel_type'] = 'childIussue+relIssue' dic['parent_issue_key'] = parentKey dic['jira_name'] = str(issue.key) relIssueList.append(str(issue.key)) dic['jira_summary'] = issue.fields.summary dic['environment'] = issue.fields.environment dic['jira_status'] = issue.fields.status.name dic['jira_statu_id'] = issue.fields.status.id dic['description'] = issue.fields.description # 问题类型 缺陷/严重等 dic['issue_type'] = issue.fields.issuetype.name # 获取修复版本 str_fix_version = '' for fixVersion in issue.fields.fixVersions: str_fix_version = str_fix_version + fixVersion.name + ',' dic['str_fix_version'] = str_fix_version[:-1] dic['reporter'] = str(issue.fields.reporter) # 报告人 dic['assignee'] = str(issue.fields.assignee) # 经办人 dic['reporter_email'] = str(issue.fields.reporter.emailAddress) # 报告人邮箱 dic['assignee_email'] = str(issue.fields.assignee.emailAddress) # 经办人邮箱 # dic['status'] = str(issue.fields.status) # for issueLink in issue.fields.linkedIssues: # print issueLink dic['issue_url'] = '%s/browse/%s' % (self.jira_server_url, issue.key) dic['createdTime'] = str(issue.fields.created).replace('T', ' ')[0:19] dic['updated_time'] = str(issue.fields.updated).replace('T', ' ')[0:19] dic['duedate'] = str(issue.fields.duedate).replace('T', ' ')[0:19] dic['resolution'] = str(issue.fields.resolution) dic['resolutiondate'] = str(issue.fields.resolutiondate).replace('T', ' ')[0:19] n += 1 lists.append(dic) if searchChildIssue and both == False: logger.debug('查询子任务...%s' % parentKey) childIssues = self.jira.search_issues('parent = %s' % (parentKey)) for issue in childIssues: dic = {} dic['index'] = n dic['rel_type'] = 'childIussue' dic['parent_issue_key'] = parentKey dic['jira_name'] = str(issue.key) relIssueList.append(str(issue.key)) dic['jira_summary'] = issue.fields.summary dic['environment'] = issue.fields.environment dic['jira_status'] = issue.fields.status.name dic['jira_statu_id'] = issue.fields.status.id dic['description'] = issue.fields.description # 问题类型 缺陷/严重等 dic['issue_type'] = issue.fields.issuetype.name # 获取修复版本 str_fix_version = '' for fixVersion in issue.fields.fixVersions: str_fix_version = str_fix_version + fixVersion.name + ',' dic['str_fix_version'] = str_fix_version[:-1] dic['reporter'] = str(issue.fields.reporter) # 报告人 dic['assignee'] = str(issue.fields.assignee) # 经办人 dic['reporter_email'] = str(issue.fields.reporter.emailAddress) # 报告人邮箱 dic['assignee_email'] = str(issue.fields.assignee.emailAddress) # 经办人邮箱 # dic['status'] = str(issue.fields.status) # for issueLink in issue.fields.linkedIssues: # print issueLink dic['issue_url'] = '%s/browse/%s' % (self.jira_server_url, issue.key) dic['createdTime'] = str(issue.fields.created).replace('T', ' ')[0:19] dic['updated_time'] = str(issue.fields.updated).replace('T', ' ')[0:19] dic['duedate'] = str(issue.fields.duedate).replace('T', ' ')[0:19] dic['resolution'] = str(issue.fields.resolution) dic['resolutiondate'] = str(issue.fields.resolutiondate).replace('T', ' ')[0:19] n += 1 lists.append(dic) if searchRelIssue and both == False: logger.debug('查询相关任务...') childIssues = self.jira.search_issues('issue in linkedIssues(%s)' % (parentKey)) for issue in childIssues: dic = {} dic['index'] = n dic['rel_type'] = 'relIssue' dic['parent_issue_key'] = parentKey dic['jira_name'] = str(issue.key) relIssueList.append(str(issue.key)) dic['jira_summary'] = issue.fields.summary dic['environment'] = issue.fields.environment dic['jira_status'] = issue.fields.status.name dic['jira_statu_id'] = issue.fields.status.id dic['description'] = issue.fields.description # 问题类型 缺陷/严重等 dic['issue_type'] = issue.fields.issuetype.name # 获取修复版本 str_fix_version = '' for fixVersion in issue.fields.fixVersions: str_fix_version = str_fix_version + fixVersion.name + ',' dic['str_fix_version'] = str_fix_version[:-1] dic['reporter'] = str(issue.fields.reporter) # 报告人 dic['assignee'] = str(issue.fields.assignee) # 经办人 dic['reporter_email'] = str(issue.fields.reporter.emailAddress) # 报告人邮箱 dic['assignee_email'] = str(issue.fields.assignee.emailAddress) # 经办人邮箱 # dic['status'] = str(issue.fields.status) # for issueLink in issue.fields.linkedIssues: # print issueLink dic['issue_url'] = '%s/browse/%s' % (self.jira_server_url, issue.key) dic['createdTime'] = str(issue.fields.created).replace('T', ' ') dic['updated_time'] = str(issue.fields.updated).replace('T', ' ') dic['duedate'] = str(issue.fields.duedate).replace('T', ' ') dic['resolution'] = str(issue.fields.resolution) dic['resolutiondate'] = str(issue.fields.resolutiondate).replace('T', ' ') n += 1 lists.append(dic) pdic['relissues'] = relIssueList lists.append(pdic) return lists except Exception as e: logger.exception('异常信息') lists = [] def search_issue(self, searchText): ''' 搜索issue列表 返回结果是jira搜索结果数组 ''' searchText = str(searchText).replace(' ', '') str1 = 'key = "' + searchText + '" OR text ~ "' + searchText + '"' str1 = 'key = "' + searchText + '"' str2 = 'summary ~ ' + searchText try: arrays = self._search_issue(str1) except Exception as e: logger.exception('异常信息') try: arrays = self._search_issue(self, str2) except Exception as e: logger.exception('异常信息') arrays = [] return arrays, str(e) return arrays, '1' def jql_search(self, searchText, type=0): """ |##@函数目的:issue 的高级搜索 |##@参数说明:affectedVersion ='SRMC-15 |##@返回值:type =1 执行原生高级搜索 |##@函数逻辑: |##@开发人:runksun |##@时间:2017年2月23日 """ r = re.findall('^\w+-\d+$', searchText) if r: logger.debug('用户输入的纯JIRA号,进行高级搜索格式化...') searchText = 'key = "' + r[0] + '" OR text ~ "' + r[0] + '"' else: logger.debug(searchText) try: if type == 0: arrays = self._search_issue(searchText) else: return self.jira.search_issues(searchText), type except Exception as e: logger.exception('异常信息') arrays = [] return arrays, '1' def search_issue_status(self, jira_name): """ |##@函数目的:查询issue的状态 |##@参数说明:jira_name 支持 包含多个key 的list |##@返回值:list |##@函数逻辑: |##@开发人:runksun,jhuang |##@时间:2017年1月17日 JQL高级搜索文档:https://confluence.atlassian.com/jira060/advanced-searching-370704913.html """ # tstart=time.time() # 将多个KEY 进行高级搜索,一次查询,速度快 if isinstance(jira_name, list) is True: if len(jira_name) <= 0: return None keys = ','.join(jira_name) JiraList = [] searchJQL = 'key in (%s)' % (keys) print searchJQL issues = self.jira.search_issues(searchJQL, 0, 1000) for issue in issues: dic = {} # print issue.key dic['key'] = issue.key dic['statu'] = issue.fields.status.name dic['jira_statu_id'] = issue.fields.status.id dic['issuetype'] = issue.fields.issuetype dic['assignee'] = str(issue.fields.assignee) # 经办人 JiraList.append(dic) logger.debug('查询状态完成!') return JiraList else: jira_name = str(jira_name).replace(' ', '') str1 = 'key =' + jira_name try: issue = self.jira.search_issues(str1) jira_status = issue[0].fields.status.name except: jira_status = '状态未知' finally: return jira_status
class Confluence(object): def __init__(self): self.username = None self.password = None self.ohttp = None self.confluence_server_url = None def login(self, url, username, password): """ | ##@函数目的: 登录 | ##@参数说明: | ##@返回值:登录句柄 | ##@函数逻辑: | ##@开发人:jhuang | ##@时间: """ self.confluence_server_url = url data = {'login': '******', 'os_username': username, 'os_password': password, 'os_destination': '', 'atl_token': type } # if self.ohttp ==None: self.ohttp = HttpClass() logger.debug('登录Confluence...') ret, html = self.ohttp.post(self.confluence_server_url + '/login.jsp', data) # else: # logger.info ( u'已登录Confluence,无需登录!') # logger.info ( html) return self.ohttp def logout(self): self.ohttp.get('%s/logout.action' % (self.confluence_server_url)) self.ohttp.close() def get_avatar(self, username): """ | ##@函数目的: 获取用户头像 | ##@参数说明: | ##@返回值: | ##@函数逻辑: | ##@开发人:jhuang | ##@时间: """ ret, html,respone_time = self.ohttp.get( self.confluence_server_url + '/rest/spacedirectory/1/search?label=~' + username + '%3Afavourite&label=~' + username + '%3Afavorite&_=1483072547386') try: R = re.findall('"image/png" href="(http.*?(?:jpg|png))', html) if len(R) > 1: return R[1] else: return None except Exception as e: get_except(e) return None def get_page_title(self, pageid): """ | ##@函数目的: 获取文档标题 | ##@参数说明: | ##@返回值: | ##@函数逻辑: | ##@开发人:jhuang | ##@时间: """ ret, html = self.ohttp.get('%s/pages/viewpage.action?pageId=%s' % (self.confluence_server_url, pageid)) r = re.findall('<meta name="ajs-page-title" content="(.*?)">', html, re.M) if len(r) > 0: return r[0] else: return None