You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
9.4 KiB

#!/usr/bin/env python3
import http
import hmac
import json
import socket
import threading
import logging
from flask import Flask, request
from pprint import pprint
from hashlib import sha256
from phabricator import Phabricator
from time import sleep
website = "https://phab.lubuntu.me"
phab = Phabricator(host=website+"/api/", token="API KEY")
global username
username = "lugito"
server = "irc.freenode.net"
port = 6667
channel = "#lubuntu-devel"
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG)
logger = logging.getLogger(__name__)
app = Flask(__name__)
def connecttoirc():
global conn, username
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect((server, port))
setup = False
usersuffix = 0
while setup == False:
response = conn.recv(512).decode("utf-8")
if "No Ident response" in response:
conn.send("NICK {}\r\n".format(username).encode("utf-8"))
conn.send("USER {} * * :{}\r\n".format(username, username).encode("utf-8"))
if "376" in response:
conn.send("JOIN {}\r\n".format(channel).encode("utf-8"))
if "433" in response:
usersuffix = usersuffix + 1
username = username + str(usersuffix)
conn.send("NICK {}\r\n".format(username).encode("utf-8"))
conn.send("USER {} * * :{}\r\n".format(username, username).encode("utf-8"))
if "PING" in response:
conn.send("PONG :{}\r\n".format(response.split(":")[1]).encode("utf-8"))
if "366" in response:
setup = True
logger.info("Successfully connected to the IRC server.")
def isnewtask(task):
modified = None
for data in task:
if modified:
if data["dateCreated"] == data["dateModified"] and data["dateCreated"] == modified:
modified = data["dateCreated"]
newtask = True
else:
newtask = False
break
else:
modified = data["dateCreated"]
return newtask
def sendnotice(message):
conn.send("NOTICE {} :{}\r\n".format(channel, message).encode("utf-8"))
def ircmessage(objectstr, who, body, link):
# e.g. [T31: Better IRC integration]
message = "\x033[\x03\x0313" + objectstr + "\x03\x033]\x03 "
# e.g. tsimonq2 (Simon Quigley)
message = message + "\x0315" + who + "\x03 "
# e.g. commented on the task:
message = message + body + ": "
# e.g. https://phab.lubuntu.me/T40#779
message = message + "\x032" + link + "\x03"
# Make sure we can debug this if it goes haywire
logger.debug(message)
# Sleep for a second, so when we have a bunch of messages we have a buffer
sleep(1)
# Aaaaand, send it off!
sendnotice(message)
def gettaskinfo(task):
sendmessage = ""
try:
# We only need the task number.
taskinfo = phab.maniphest.info(task_id=int(task.split("T")[1]))
sendmessage = sendmessage + "\x033[\x03"
# The color of the priority text should correspond to its value.
color = taskinfo["priorityColor"]
if color == "violet":
sendmessage = sendmessage + "\x036Needs Triage"
elif color == "pink":
sendmessage = sendmessage + "\x035Unbreak Now!"
elif color == "red":
sendmessage = sendmessage + "\x034High"
elif color == "orange":
sendmessage = sendmessage + "\x037Medium"
elif color == "yellow":
sendmessage = sendmessage + "\x038Low"
elif color == "sky":
sendmessage = sendmessage + "\x037Wishlist"
# Put the task status in the message.
sendmessage = sendmessage + ", " + taskinfo["statusName"] + "\x03"
sendmessage = sendmessage + "\x033]\x03 "
# Put the title in there as well.
sendmessage = sendmessage + taskinfo["title"].strip() + ": "
# And the link.
sendmessage = sendmessage + "\x032" + taskinfo["uri"] + "\x03"
# Send it off!
sendnotice(sendmessage)
# If someone wrote something like "Tblah", obviously that's not right.
except ValueError:
sendnotice("\x034Error: " + task.strip() + "is an invalid task reference.\x03")
return None
def ircbot(message, msgtype):
if msgtype == "info":
message = message.split(" :" + username + ": info")[1]
for item in message.split():
if item.startswith("T"):
gettaskinfo(item.strip())
elif msgtype == "link":
for item in message.split("https://phab.lubuntu.me/"):
if item.split()[0].strip().startswith("T"):
gettaskinfo(item.split()[0].strip())
else:
sendnotice("\x034Error: unknown command.\x03")
return None
def listenirc():
while True:
ircmsg = conn.recv(512)
if len(ircmsg) == 0:
logger.warn("Connection lost, reconnecting!")
connecttoirc()
continue
ircmsg = ircmsg.decode("UTF-8").strip('\n\r')
logger.debug(ircmsg)
if ircmsg.find("PING :") != -1:
conn.send(bytes("PONG :pingis\n", "UTF-8"))
elif ircmsg.find(" :" + username + ": info") != -1:
ircbot(ircmsg, "info")
elif ircmsg.find("https://phab.lubuntu.me/T") != -1:
ircbot(ircmsg, "link")
@app.route("/irc", methods=["POST"])
def main():
data = request.data
hash = hmac.new(bytes(u"HMAC KEY", "utf-8"), data, sha256)
# We MUST ensure that the request came from Phab.
if hash.hexdigest() == request.headers["X-Phabricator-Webhook-Signature"]:
data = json.loads(data)
logger.debug(data)
exists = True
try:
# Try to find the object.
search = phab.transaction.search(objectIdentifier=data["object"]["phid"])["data"]
# Find the author too.
userlookup = search[0]["authorPHID"]
who = str(dict(phab.phid.query(phids=[userlookup]))[userlookup]["fullName"])
# If the object exists, no worries, let's just return a good response.
except http.client.HTTPException:
exists = False
if exists:
logger.debug("Object exists, checking to see if it's a task or a commit.")
if data["object"]["type"] == "TASK":
logger.debug("This is a task. Checking if it's new.")
newtask = isnewtask(search)
if newtask:
logger.debug("Yes, it's a new task.")
else:
logger.debug("No, it's not a new task.")
# If it's not a new task, let's see if it's a comment, and if it's just an edit.
comment = None
commentid = None
edited = None
if not newtask:
commentid = None
edited = False
for task in search:
dataepoch = data["action"]["epoch"]
datemodified = task["dateModified"]
# All comments within ten seconds of the request are fair game.
if datemodified >= (dataepoch - 10) and datemodified <= (dataepoch + 10) and task["comments"] != []:
logger.debug("It's a comment, yes.")
comment = True
commentid = task["id"]
if datemodified != task["dateCreated"]:
logger.debug("The comment was edited.")
edited = True
else:
logger.debug("The comment was NOT edited.")
edited = False
break
else:
comment = False
if comment or edited or newtask:
objectstr = phab.phid.query(phids=[data["object"]["phid"]])[data["object"]["phid"]]["fullName"]
if comment:
body = "commented on the task"
elif edited:
body = "edited a message on the task"
elif newtask:
body = "just created this task"
# Assuming this is a comment, there should always be a URI associated with it.
link = phab.phid.query(phids=[data["object"]["phid"]])[data["object"]["phid"]]["uri"]
# Even though this can be off sometimes, let's include the comment ID in the link too.
# FIXME: Make this more accurate, and figure out why it's inaccurate at times.
if commentid:
link = link + "#" + str(commentid)
ircmessage(objectstr, who, body, link)
elif data["object"]["type"] == "CMIT":
logger.debug("It's a commit!")
commitphid = data["object"]["phid"]
objectstr = phab.phid.query(phids=[commitphid])[commitphid]["fullName"]
body = "committed"
# The URI for this one is waaaaaaay too long. Let's assemble it ourselves.
link = website + "/" + phab.phid.query(phids=[commitphid])[commitphid]["name"]
ircmessage(objectstr, who, body, link)
return "OK"
if __name__ == "__main__":
connecttoirc()
t = threading.Thread(target=listenirc)
t.daemon = True
t.start()
app.run(host="0.0.0.0", port=5000)