Commit da4433e8 authored by SBassett's avatar SBassett
Browse files

UserTracker - implement PhabricatorTracker

Implemented PhabricatorTracker, minimally.  For now it queries
api/maniphest.search and finds task activity after a certain timestamp for a
specific Phabricator user.  I would eventually like to check a few more Phab
API endpoints and better handle Phab's API limit (100 results) with paging
(noted as TODOs.)

Bug: T212508
Change-Id: Id2b6787a72cb6e18acfe850efbca5fbf84952f78
parent 6a0317d6
...@@ -45,8 +45,156 @@ Subject: %s ...@@ -45,8 +45,156 @@ Subject: %s
class PhabricatorTracker(): class PhabricatorTracker():
""" Class for tracking a user's activity within Phabricator """ """ Class for tracking a user's activity within Phabricator """
def __init__(self): def __init__(self, emails, email_debug, time_interval,
pass phab_user_name, phab_api_key):
""" Instance Vars """
self.emails = emails
self.email_debug = email_debug
self.previous_time = int(self.process_time_interval(time_interval))
self.phab_user_name = phab_user_name
self.phab_api_key = phab_api_key
self.phab_base_url = 'https://phabricator.wikimedia.org/'
self.phab_api_end_point_urls = {
'user.search': ''.join([self.phab_base_url, 'api/user.search']),
'phid.query': ''.join([self.phab_base_url, 'api/phid.query']),
'maniphest.search': ''.join([self.phab_base_url,
'api/maniphest.search']),
'file.search': ''.join([self.phab_base_url, 'api/file.search']),
'paste.query': ''.join([self.phab_base_url, 'api/paste.query']),
'phame.post.search': ''.join([self.phab_base_url,
'api/phame.post.search']),
'phurls.search': ''.join([self.phab_base_url,
'api/phurls.search']),
'project.search': ''.join([self.phab_base_url,
'api/project.search'])
}
def process_time_interval(self, ti):
""" Process various time inteval formats (ns, nm, nh, nd) """
seconds = 0
m = re.match(r'^(\d+)([a-zA-Z])$', ti)
if m.group(1) and m.group(2):
if m.group(2) == 's':
seconds = int(m.group(1))
elif m.group(2) == 'm':
seconds = int(m.group(1)) * 60
elif m.group(2) == 'h':
seconds = int(m.group(1)) * 3600
elif m.group(2) == 'd':
seconds = int(m.group(1)) * 86400
else:
raise ValueError('Incorrect format for \
time interval argument.')
""" Return current time() - interval """
return time.time() - seconds
else:
raise ValueError('Incorrect format for \
time interval argument.')
def get_end_point_data(self, end_point_key, post_params):
""" Get JSON data from gerrit API, process and load """
all_post_data = {}
api_token_dict = {'api.token': self.phab_api_key}
if isinstance(post_params, dict):
all_post_data = api_token_dict.update(post_params)
else:
raise ValueError('Incorrect format for post_params')
r = requests.post(
self.phab_api_end_point_urls[end_point_key],
data=api_token_dict
)
return json.loads(r.text)
def analyze_end_point_data(self):
""" Check gerrit API data for relevant user activity """
tracking_data = {}
""" Get PHID of user """
phid_json_data = self.get_end_point_data(
'user.search',
{'constraints[usernames][0]': self.phab_user_name}
)
user_phid = phid_json_data.get('result').get('data')[0].get('phid')
# TODO: make all of the below paginate through
# 100-item limit for Phab API requests
""" Find Phab maniphest/task activity """
maniphest_user_type_constraints = [
'assigned',
'authorPHIDs',
'closerPHIDs',
'subscribers'
]
for user_type in maniphest_user_type_constraints:
maniphest_json_data = self.get_end_point_data(
'maniphest.search',
{
''.join(['constraints[', user_type, '][0]']): user_phid,
'constraints[modifiedStart]': self.previous_time,
'order': 'updated'
}
)
for item in maniphest_json_data.get('result').get('data'):
task = ''.join(['T', str(item.get('id'))])
if task not in tracking_data.keys():
tracking_data[task] = user_type.rstrip('s').rstrip('PHID')
# TODO: implement
""" Find Phab file activity """
""" Find Phab paste activity """
""" Find Phab phame activity """
""" Find Phab phurls activity """
""" Find Phab projects activity """
return tracking_data
def send_alert(self):
""" Analyze tracking data and email report, if necessary """
alert_data = self.analyze_end_point_data()
alert_msg = ''
for k, v in alert_data.items():
alert_msg = ''.join([alert_msg, '* <', self.phab_base_url,
str(k), '> [', str(v), ']\n'])
if len(alert_msg) > 0:
previous_date_formatted = str(
datetime.datetime.utcfromtimestamp(self.previous_time)
.strftime('%Y-%m-%d %H:%M'))
log_msg = 'Recent phabricator activity since {} for user {}: {}'\
.format(previous_date_formatted, self.phab_user_name,
str(alert_data.keys())[10:-1])
email_sender = 'PhabricatorTracker'
email_subject = ''.join(['Phabricator User Tracking Results - ',
self.phab_user_name])
email_body = """\
The following Phabricator objects related to user {}
were found to have activity since UTC {}:
{}
""".format(
self.phab_user_name,
previous_date_formatted,
alert_msg)
send_email_notification(
email_sender,
[self.emails],
email_subject,
email_body,
self.email_debug)
if self.email_debug:
print(log_msg)
else:
syslog.syslog(log_msg)
else:
print('No recent phabricator activity found for user {}.'.format(
self.phab_user_name))
class GerritTracker(): class GerritTracker():
...@@ -150,6 +298,7 @@ class GerritTracker(): ...@@ -150,6 +298,7 @@ class GerritTracker():
return tracking_data return tracking_data
def send_alert(self): def send_alert(self):
""" Analyze tracking data and email report, if necessary """
alert_data = self.analyze_end_point_data() alert_data = self.analyze_end_point_data()
alert_msg = '' alert_msg = ''
for k, v in alert_data.items(): for k, v in alert_data.items():
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" User-tracking tools for various wmf-related systems
Author: sbassett@wikimedia.org
License: Apache 2.0
"""
import argparse
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from UserTracker import PhabricatorTracker
""" Args """
parser = argparse.ArgumentParser()
parser.add_argument('-e', '--emails',
help='email or comma-separated \
list of emails to notify')
parser.add_argument('-d', '--emaildebug', default=False,
help='email debug flag')
parser.add_argument('-t', '--timeinterval', default='5m',
help='time interval corresponding to \
job frequency')
parser.add_argument('-u', '--pusername', default='',
help='phab username to track')
parser.add_argument('-k', '--papikey', default='',
help='phab user id to track \
(corresponds to --gusername)')
args, unknown = parser.parse_known_args()
""" Instantiate and send """
pt = PhabricatorTracker(
args.emails,
args.emaildebug,
args.timeinterval,
args.pusername,
args.papikey)
pt.send_alert()
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