Coverage for modules/org/openteacher/profileRunners/ircBot/bot : 1%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
|
#! /usr/bin/env python3 # -*- coding: utf-8 -*-
# Copyright 2012-2014, 2017, Marten de Vries # Copyright 2012, Milan Boers # # This file is part of OpenTeacher. # # OpenTeacher is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # OpenTeacher is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with OpenTeacher. If not, see <http://www.gnu.org/licenses/>.
#ATTENTION: fixmes/todos in this module won't be shown in the overview, #since the word 'fixme' is used multiple times for other reasons.
from launchpadlib import launchpad import re import urllib.parse import urllib.error import urllib.request import json import os
class OpenTeacherBot(pydle.Client): factoids = { ".downloads": "http://openteacher.org/en/download.html", ".sf": "http://sourceforge.net/projects/openteacher", ".stats": "http://sourceforge.net/projects/openteacher/files/stats", ".lp": "https://launchpad.net/openteacher", ".github": "https://github.com/openteacher", ".blueprints": "https://blueprints.launchpad.net/openteacher", ".code": "https://code.launchpad.net/openteacher", ".bugs": "https://bugs.launchpad.net/openteacher", ".answers": "https://answers.launchpad.net/openteacher", ".translations": "https://translations.launchpad.net/openteacher", ".website": "http://openteacher.org/", ".about": "http://openteacher.org/en/about.html", ".documentation": "http://openteacher.org/en/documentation.html", ".codedocs": "https://web.openteacher.org/code-documentation/", ".contribute": "http://openteacher.org/en/contribute.html", ".forum": "http://forum.ubuntu-nl.org/etalage/openteacher-overhoorprogramma-voor-linux/new/#new", ".ogd": "http://opengamedesign.sourceforge.net/", ".ogd-lp": "https://launchpad.net/opengamedesigner", ".ogd-sf": "http://sourceforge.net/projects/opengamedesign", ".twitter": "https://twitter.com/openteacher", ".facebook": "http://www.facebook.com/OpenTeacher", ".openhub": "https://www.openhub.net/p/openteacher", ".mailarchive": "https://lists.launchpad.net/openteachermaintainers/", ".paste": "http://paste.ubuntu.com/", ".etherpad": "https://public.etherpad-mozilla.org/", ".jfl": "https://launchpad.net/justforlearning/", ".ot-mobile": "https://web.openteacher.org/mobile/", ".ot-test-coverage": "https://web.openteacher.org/builds/linux/coverage/", ".priorities": "https://web.openteacher.org/code-documentation/priorities.html", ".fixmes": "https://web.openteacher.org/code-documentation/fixmes.html", ".modulemap": "https://web.openteacher.org/code-documentation/module_graph.svg", ".peps": "http://www.python.org/dev/peps/", ".api": "https://web.openteacher.org/services/", ".profiling": "https://web.openteacher.org/builds/linux/profiling", ".website-preview": "https://web.openteacher.org/builds/linux/website/en/", ".developer-documentation": "https://web.openteacher.org/code-documentation/dev_docs/", ".code-complexity": "https://web.openteacher.org/builds/linux/code-complexity.txt", ".dependencies": "https://web.openteacher.org/code-documentation/dev_docs/dependencies.rst", ".bitesize": "https://bugs.launchpad.net/openteacher/+bugs?field.tag=bitesize", ".travis": "https://travis-ci.org/openteacher/openteacher-ci", ".web": "https://web.openteacher.org/", ".appveyor": "https://ci.appveyor.com/project/openteacher/openteacher-ci", ".openteacher-ci": "https://github.com/openteacher/openteacher-ci", ".builds": "https://web.openteacher.org/builds/", } factoids[".launchpad"] = factoids[".lp"] factoids[".gh"] = factoids[".github"] factoids[".download"] = factoids[".downloads"] factoids[".homepage"] = factoids[".website"] factoids[".codedocumentation"] = factoids[".codedocs"] factoids[".code-documentation"] = factoids[".codedocs"] factoids[".code-docs"] = factoids[".codedocs"] factoids[".forumtopic"] = factoids[".forum"] factoids[".mailinglist"] = factoids[".mailarchive"] factoids[".pastebin"] = factoids[".paste"] factoids[".openteacher-mobile"] = factoids[".ot-mobile"] factoids[".mobile"] = factoids[".ot-mobile"] factoids[".ot-coverage"] = factoids[".ot-test-coverage"] factoids[".coverage"] = factoids[".ot-test-coverage"] factoids[".fixme"] = factoids[".fixmes"] factoids[".todos"] = factoids[".fixmes"] factoids[".todo"] = factoids[".fixmes"] factoids[".priority"] = factoids[".priorities"] factoids[".module-map"] = factoids[".modulemap"] factoids[".modulegraph"] = factoids[".modulemap"] factoids[".module-graph"] = factoids[".modulemap"] factoids[".profile"] = factoids[".profiling"] factoids[".cProfile"] = factoids[".profiling"] factoids[".performance"] = factoids[".profiling"] factoids[".website-dev"] = factoids[".website-preview"] factoids[".dev-docs"] = factoids[".developer-documentation"] factoids[".devdocs"] = factoids[".developer-documentation"] factoids[".developer-docs"] = factoids[".developer-documentation"] factoids[".dev-documentation"] = factoids[".developer-documentation"] factoids[".wiki"] = factoids[".developer-documentation"] factoids[".complexity"] = factoids[".code-complexity"] factoids[".cyclomatic-complexity"] = factoids[".code-complexity"] factoids[".mccabe"] = factoids[".code-complexity"] factoids[".requirements"] = factoids[".dependencies"] factoids[".simplebugs"] = factoids[".bitesize"] factoids[".bitesizebugs"] = factoids[".bitesize"] factoids['.ohloh'] = factoids['.openhub'] factoids['.tests'] = factoids['.travis'] factoids['.ci'] = factoids['.openteacher-ci'] factoids['.otweb'] = factoids['.web'] factoids['.build'] = factoids['.builds']
def __init__(self, channels, nickname, realname, admins, **kwargs): self.allowedChannels = channels self.nickname = nickname self.admins = admins
self.launchpad = launchpad.Launchpad.login_anonymously("OpenTeacher bot", "production", "~/.config/launchpadlib", version="devel")
super().__init__(self.nickname, realname=realname)
def on_connect(self): super().on_connect()
print("Signed on. Now joining channels.")
for channel in self.allowedChannels: self.join(channel)
def on_join(self, channel, username): if username == self.nickname: print("Joined %s." % channel)
def _buildBugResponse(self, msg, user): #bugs match = re.search("(?:bugs? ?/?|#|lp:)([0-9]+)", msg) if match: number = match.group(1) bug = self.launchpad.bugs[number] if bug: try: task = bug.bug_tasks[0] #should not crash, but to be sure except IndexError: pass else: return "bug #%s: %s (status: %s, importance: %s) - %s" % ( bug.id, bug.title, task.status, task.importance, bug.web_link )
def _buildBranchResponse(self, msg, user): #branches match = re.search("lp:[^ ]*(?=[^,.?!])[^ ]", msg) if match: branch = self.launchpad.branches.getByUrl(url=match.group(0)) if branch: text = "branch %s (status: %s, %s revisions) - %s" % ( branch.bzr_identity, branch.lifecycle_status, branch.revision_count, branch.web_link, ) return text
def _buildPyModResponse(self, msg, user): if msg.startswith(".pymod "): mod = msg.split(" ")[1] url = u"http://docs.python.org/library/%s.html" % mod try: urllib.request.urlopen(url) except urllib.error.HTTPError: return u"Can't find documentation for that module." else: return url
def _buildGoogleResponse(self, msg, user): if msg.startswith(".google "): q = msg.split(" ", 1)[1] q = urllib.parse.quote_plus(q) return u"http://google.com/search?q=%s" % q
def _buildQtResponse(self, msg, user): if msg.startswith(".qt "): cls = msg.split(" ")[1] url = u"http://qt-project.org/doc/qt-5/%s.html" % cls try: urllib.request.urlopen(url) except urllib.error.HTTPError: return u"Can't find documentation for that class." else: return url
def _buildAnswerResponse(self, msg, user): if msg.startswith(".answer ") or msg.startswith(".ask ") or msg.startswith(".question "): q = msg.split(" ", 1)[1].replace(self.nickname, "") q = urllib.parse.quote_plus(q) return u"http://www.wolframalpha.com/input/?i=%s" % q
def _buildPepResponse(self, msg, user): if msg.startswith(".pep "): try: number = int(msg.split(" ", 1)[1].replace(self.nickname, "")) except ValueError: return u"Couldn't parse pep number." else: url = u"http://www.python.org/dev/peps/pep-%04d/" % number try: urllib.request.urlopen(url) except urllib.error.HTTPError: return u"No pep found for that number." else: return url
def _buildBlueprintResponse(self, msg, user): #blueprints match = re.search("(?:specs?[ /]+|blueprints? )([^ ,.?!/]+)", msg) if match: spec = self.launchpad.projects["openteacher"].getSpecification(name=match.group(1)) if spec: return u"blueprint %s: %s (def. status: %s, impl. status: %s, priority: %s) - %s" % ( spec.name, spec.title, spec.definition_status, spec.implementation_status, spec.priority, spec.web_link, )
def _buildFactoidResponse(self, msg, user): #factoids #sorted on key so the longest factoid keys are tried first. #Needed in this situation: .codedocumentation while there's a #factoid .code. for key, factoid in reversed(sorted(self.factoids.items(), key=lambda t: len(t[0]))): if key + " " in msg + " ": return factoid
@pydle.coroutine def isAdmin(self, user): return user in self.admins and (yield self.whois(user))['identified']
@pydle.coroutine def on_message(self, channel, user, msg): print("%s: %s: %s" % (user, channel, msg)) target = channel if channel in self.allowedChannels else user
#quit client if msg == ".quit" and (yield self.isAdmin(user)): self.quit()
builders = [ self._buildAnswerResponse, self._buildBlueprintResponse, self._buildBranchResponse, self._buildBugResponse, self._buildFactoidResponse, self._buildGoogleResponse, self._buildPepResponse, self._buildPyModResponse, self._buildQtResponse, ]
for buildResponse in builders: resp = buildResponse(msg, user) if resp is not None: #found a message break else: #no message found return
#send the message self.message(target, resp)
def run(): print("For a nice quit, tell the bot to .quit on irc.\n")
with open(os.path.join(os.path.dirname(__file__), 'config.json'), encoding='UTF-8') as f: config = json.load(f) client = OpenTeacherBot(**config) client.connect('irc.freenode.net', tls=True, password=config['password']) client.handle_forever()
if __name__ == "__main__": run() |