From d974d323948afbf598d1ab0c530ad8570ba70b46 Mon Sep 17 00:00:00 2001 From: misaka4e21 Date: Tue, 2 Jan 2018 11:36:05 +0800 Subject: [PATCH 1/6] Add Discourse Babble support. Customize for hitorino. --- .gitignore | 2 + fishroom/DiscourseBabble.py | 240 ++++++++++++++++++++++++++++++++++++ fishroom/models.py | 1 + fishroom/photostore.py | 14 ++- fishroom/telegram.py | 4 +- fishroom/wechat.py | 2 +- fishroom/xss.py | 27 ++++ 7 files changed, 283 insertions(+), 7 deletions(-) create mode 100644 fishroom/DiscourseBabble.py create mode 100644 fishroom/xss.py diff --git a/.gitignore b/.gitignore index 9631938..23b1b1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /fishroom/config.py /test/config.py config.py.production +**/__pycache__ +**/*.py[cod] diff --git a/fishroom/DiscourseBabble.py b/fishroom/DiscourseBabble.py new file mode 100644 index 0000000..470cf4d --- /dev/null +++ b/fishroom/DiscourseBabble.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +import requests +import requests.exceptions +import tornado +import tornado.web + +import time +import re + +from . import xss + +from .base import BaseBotInstance, EmptyBot +from .bus import MessageBus, MsgDirection +from .models import ( + Message, ChannelType, MessageType, RichText, TextStyle, Color +) +from .textformat import TextFormatter +from .helpers import get_now_date_time, get_logger +from .config import config +from .IRC import IRCHandle + +logger = get_logger("DiscourseBabble") + +IRC_COLOR_RGB = [ + '#ffffff', # 0 + '#000000', # 1 + '#00007f', + '#009300', + '#ff0000', + '#7f0000', + '#9c009c', + '#fc7f00', + '#ffff00', + '#00fc00', + '#009300', + '#00ffff', + '#0000fc', + '#ff00ff', + '#7f7f7f', + '#d2d2d2', #15 + '#888', # 16 +] + +def getWebhookHandler(dbh): + class WebhookHandler(tornado.web.RequestHandler): + def post(self): + json = tornado.escape.json_decode(self.request.body) + topic_id = json.get('topic_id',0) + current_user = json.get('current_user', '未知用户') + message = json.get('message', '未知消息') + dbh.on_sendmessage(topic_id, current_user, message) + self.write('Got a message.') + return WebhookHandler + +class DiscourseBabbleHandle(BaseBotInstance): + ChanTag = ChannelType.DiscourseBabble + SupportMultiline = True + #rich_message = IRCHandle.rich_message + send_to_bus = None + def __init__(self, base_url, username, api_key, topic_ids): + debug=config['debug'] + self.username = username + self.base_url = base_url + self.api_key = api_key + self.topic_ids = topic_ids + application = tornado.web.Application([ + (r"/sendmessage", getWebhookHandler(self)), + ],debug=debug, autoreload=debug) + application.listen(config['babble']['webhook_port'],address=config['babble'].get('webhook_host', '0.0.0.0')) + + def listen(self): + tornado.ioloop.IOLoop.instance().start() + + def on_sendmessage(self, topic_id, current_user, message): + if current_user == self.username: + return + date, time = get_now_date_time() + # images = [m.group(1) for m in re.finditer(r'!\[.*\]\(.+\)',message)] + logger.debug(message) + m = re.search(r'', message) + media_url = '' + mtype = MessageType.Text + if m: + logger.debug(m) + mtype = MessageType.Photo + media_url = m.group(1) + if re.search(r'^http', media_url)==None: + if media_url.startswith('/uploads/'): + media_url = self.base_url + media_url + logger.debug(media_url) + msg = Message( + ChannelType.DiscourseBabble, + current_user, topic_id, + xss.cooked_unescape(message), + mtype=mtype,media_url=media_url, + date=date,time=time + ) + self.send_to_bus(self,msg) + + def do_send_request(self, topic_id, text): + if topic_id not in self.topic_ids: + return + requests.post(self.base_url + +'/babble/topics/' + +'%d'%int(topic_id) + +'/posts', + data = { + 'api_user':self.username, + 'api_key':self.api_key, + 'raw': text, + 'topic_id': '%d'%int(topic_id) + }) + + def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs): + # color that fits both dark and light background + color_avail = (2, 3, 4, 5, 6, 7, 10, 12, 13) + color = None + + if sender: + # color defined at http://www.mirc.com/colors.html + # background_num = sum([ord(i) for i in sender]) % 16 + cidx = sum([ord(i) for i in sender]) % len(color_avail) + foreground_num = color_avail[cidx] + color = Color(foreground_num) # + ',' + str(background_num) + + reply_quote = "" + if 'reply_text' in kwargs: + reply_to = kwargs['reply_to'] + reply_text = kwargs['reply_text'] + if len(reply_text) > 8: + reply_text = reply_text[:8] + '...' + reply_quote = "[b]{reply_to}[/b]
{reply_text}".format(reply_text=reply_text.strip(), reply_to=reply_to) + + channel = raw.channel.capitalize() + channel = xss.replace(channel, [[r'[Ii][Rr][Cc]',r'IRC'],['Babble',r'hitorino\\*']]) + msg = self.rich_message(content, sender=sender, color=color, + reply_quote=reply_quote, channel=channel) + msg = self.formatRichText(msg) + if raw is not None: + if raw.mtype in (MessageType.Photo, MessageType.Sticker): + msg += "\n![](%s)" % (raw.media_url,) + self.do_send_request(target, msg) + time.sleep(0.5) + + def rich_message(self, content, sender=None, color=None, reply_quote="", channel=""): + if color and sender: + return RichText([ + (TextStyle(color=color,bold=1), "{}".format(sender)), + (TextStyle(color=Color(16)), " {} 用户\n".format(channel)), + (TextStyle(color=Color(16)), "{}\n".format(reply_quote)), + (TextStyle(), "{}".format(xss.md_escape(content))), + ]) + else: + tmpl = "{content}" if sender is None else "[{sender}] {content}" + return RichText([ + (TextStyle(), tmpl.format(content=content, sender=sender)) + ]) + + def formatRichText(self, rich_text: RichText): + formated_text = "" + for ts, text in rich_text: + if not text: + continue + if ts.is_normal(): + formated_text += text + continue + ctrl = [] + def bold(text): + if not ts.is_bold(): + return text + return "[b]{}[/b]".format(text) + def italic(text): + if not ts.is_italic(): + return text + return "[i]{}[/i]".format(text) + def underline(text): + if not ts.is_underline(): + return text + return "[u]{}[/u]".format(text) + def fgcolor(text,color): + return '[color={}]{}[/color]'.format(IRC_COLOR_RGB[color],text) + def bgcolor(text,color): + return '[bgcolor={}]{}[/bgcolor]'.format(IRC_COLOR_RGB[color],text) + def color(text): + if not ts.has_color(): + return text + if ts.color.bg: + return bgcolor(fgcolor(text,ts.color.fg),ts.color.bg) + else: + return fgcolor(text, ts.color.fg) + formated_text += (underline(italic(bold(color(text))))) + return formated_text + +def Babble2FishroomThread(irc_handle: DiscourseBabbleHandle, bus: MessageBus): + if irc_handle is None or isinstance(irc_handle, EmptyBot): + return + def send_to_bus(self, msg): + logger.debug(msg) + bus.publish(msg) + irc_handle.send_to_bus=send_to_bus + irc_handle.listen() + + +def Fishroom2BabbleThread(irc_handle, bus): + if irc_handle is None or isinstance(irc_handle, EmptyBot): + return + for msg in bus.message_stream(): + irc_handle.forward_msg_from_fishroom(msg) + +def init(): + from .db import get_redis + redis_client = get_redis() + im2fish_bus = MessageBus(redis_client, MsgDirection.im2fish) + fish2im_bus = MessageBus(redis_client, MsgDirection.fish2im) + + babble_idnumbers = [b["babble"] for _, b in config['bindings'].items() if "babble" in b] + base_url = config['babble']['base_url'] + username = config['babble']['username'] + api_key = config['babble']['api_key'] + + return ( + DiscourseBabbleHandle(base_url, username, api_key, babble_idnumbers), + im2fish_bus, fish2im_bus, + ) + + +def main(): + if "babble" not in config: + logger.error("Babble config not found in config.py! exiting...") + return + + from .runner import run_threads + bot, im2fish_bus, fish2im_bus = init() + run_threads([ + (Babble2FishroomThread, (bot, im2fish_bus, ), ), + (Fishroom2BabbleThread, (bot, fish2im_bus, ), ), + ]) + +main() +# vim: ts=4 sw=4 sts=4 expandtab diff --git a/fishroom/models.py b/fishroom/models.py index d838baa..c59dab9 100755 --- a/fishroom/models.py +++ b/fishroom/models.py @@ -16,6 +16,7 @@ class ChannelType(object): Wechat = "wechat" Web = "web" API = "api" + DiscourseBabble = "babble" class MessageType(object): diff --git a/fishroom/photostore.py b/fishroom/photostore.py index df1f582..6464db6 100644 --- a/fishroom/photostore.py +++ b/fishroom/photostore.py @@ -5,6 +5,7 @@ import requests.exceptions from base64 import b64encode from .helpers import get_logger +import shutil,os logger = get_logger(__name__) @@ -15,6 +16,13 @@ class BasePhotoStore(object): def upload_image(self, filename, **kwargs): raise Exception("Not Implemented") +class LocalPhotoStore(object): + def __init__(self, path, **kwargs): + self.path = path + + def upload_image(self, filename=None, filedata=None, **kwargs): + if filedata is None: + shutil.copy2(filename, os.path.join(path, os.path.dirname(filename))) class Imgur(BasePhotoStore): @@ -64,10 +72,8 @@ def upload_image(self, filename=None, filedata=None, **kwargs): class VimCN(BasePhotoStore): - url = "https://img.vim-cn.com/" - - def __init__(self, **kwargs): - pass + def __init__(self, url="https://img.vim-cn.com/", **kwargs): + self.url = url def upload_image(self, filename=None, filedata=None, **kwargs) -> str: if filedata is None: diff --git a/fishroom/telegram.py b/fishroom/telegram.py index 6727f79..b2462e0 100644 --- a/fishroom/telegram.py +++ b/fishroom/telegram.py @@ -667,7 +667,7 @@ def send_msg(self, peer, content, sender=None, escape=True, rich_text=None, self._must_post(api, json=data) def msg_tmpl(self, sender=None): - return "{content}" if sender is None else "[{sender}] {content}" + return "{content}" if sender is None else "{sender}\n{content}" @classmethod def formatRichText(cls, rich_text: RichText, escape=True): @@ -712,7 +712,7 @@ def photo_store_init(): options = config['photo_store']['options'] return Imgur(**options) elif provider == "vim-cn": - return VimCN() + return VimCN(**config['photo_store']['options']) elif provider == "qiniu": return get_qiniu(redis_client, config) diff --git a/fishroom/wechat.py b/fishroom/wechat.py index d160973..8c562f3 100644 --- a/fishroom/wechat.py +++ b/fishroom/wechat.py @@ -247,7 +247,7 @@ def init(): options = config['photo_store']['options'] photo_store = Imgur(**options) elif provider == "vim-cn": - photo_store = VimCN() + photo_store = VimCN(**config['photo_store']['options']) elif provider == "qiniu": photo_store = get_qiniu(redis_client, config) diff --git a/fishroom/xss.py b/fishroom/xss.py new file mode 100644 index 0000000..79e9b79 --- /dev/null +++ b/fishroom/xss.py @@ -0,0 +1,27 @@ +#coding=utf-8 +import re +import html + +def md_escape(text): + replacements = [ + [r'\*', r'\\*'], + [r'#', r'\\#'], + [r'\/', r'\\/'], + [r'\(', r'\\('], + [r'\)', r'\\)'], + [r'\[', r'\\['], + [r'\]', r'\\]'], + [r'\<', r'<'], + [r'\>', r'>'], + [r'_', r'\\_'], + [r'`', r'\\`'], + ] + return replace(text,replacements) + +def replace(text,rs): + for r in rs: + text = re.sub(r[0],r[1],text) + return text + +def cooked_unescape(message): + return html.unescape(re.sub(r'<[^>]+>','', message)) From 3a5434b7540876c9f11fc5a2f10cf3c608eb0879 Mon Sep 17 00:00:00 2001 From: misaka4e21 Date: Sun, 12 Aug 2018 07:32:04 +0800 Subject: [PATCH 2/6] Remove the star after hitorino. --- fishroom/DiscourseBabble.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fishroom/DiscourseBabble.py b/fishroom/DiscourseBabble.py index 470cf4d..de4398d 100644 --- a/fishroom/DiscourseBabble.py +++ b/fishroom/DiscourseBabble.py @@ -132,7 +132,7 @@ def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs reply_quote = "[b]{reply_to}[/b]
{reply_text}".format(reply_text=reply_text.strip(), reply_to=reply_to) channel = raw.channel.capitalize() - channel = xss.replace(channel, [[r'[Ii][Rr][Cc]',r'IRC'],['Babble',r'hitorino\\*']]) + channel = xss.replace(channel, [[r'[Ii][Rr][Cc]',r'IRC'],['Babble','hitorino']]) msg = self.rich_message(content, sender=sender, color=color, reply_quote=reply_quote, channel=channel) msg = self.formatRichText(msg) From eec40a6a32c0ff181084467d10c9efaf33bf5527 Mon Sep 17 00:00:00 2001 From: misaka4e21 Date: Sun, 12 Aug 2018 07:41:05 +0800 Subject: [PATCH 3/6] Support native Discourse Webhook for new Babble versions --- fishroom/DiscourseBabble.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fishroom/DiscourseBabble.py b/fishroom/DiscourseBabble.py index de4398d..9d625d8 100644 --- a/fishroom/DiscourseBabble.py +++ b/fishroom/DiscourseBabble.py @@ -45,10 +45,17 @@ def getWebhookHandler(dbh): class WebhookHandler(tornado.web.RequestHandler): def post(self): json = tornado.escape.json_decode(self.request.body) - topic_id = json.get('topic_id',0) - current_user = json.get('current_user', '未知用户') - message = json.get('message', '未知消息') - dbh.on_sendmessage(topic_id, current_user, message) + post = json.get('post', None) + if post: + topic_id = post.get('id', 0) + current_user = post.get('username', '未知用户') + message = post.get('cooked', '未知消息') + dbh.on_sendmessage(topic_id, current_user, message) + else: + topic_id = json.get('topic_id',0) + current_user = json.get('current_user', '未知用户') + message = json.get('message', '未知消息') + dbh.on_sendmessage(topic_id, current_user, message) self.write('Got a message.') return WebhookHandler From a96db5fecded5eb7bf09a1372f4b5d8a695e94ea Mon Sep 17 00:00:00 2001 From: Mingye Wang Date: Fri, 17 Aug 2018 18:58:31 +0800 Subject: [PATCH 4/6] discbbl: Reformat; remove Image type Enabling the Image type causes everything else in the message to disappear. As Discourse messages are just very rich text, why don't we forget about making stuff as this type altogether? We will now display the raw BBCode-Markdown markup. --- fishroom/DiscourseBabble.py | 84 +++++++++++++++++++------------------ fishroom/xss.py | 4 +- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/fishroom/DiscourseBabble.py b/fishroom/DiscourseBabble.py index 9d625d8..9195dd9 100644 --- a/fishroom/DiscourseBabble.py +++ b/fishroom/DiscourseBabble.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +""" +Support for the Discourse Babble plugin: +https://github.com/gdpelican/babble +""" import requests import requests.exceptions import tornado @@ -17,7 +21,6 @@ from .textformat import TextFormatter from .helpers import get_now_date_time, get_logger from .config import config -from .IRC import IRCHandle logger = get_logger("DiscourseBabble") @@ -41,19 +44,27 @@ '#888', # 16 ] + def getWebhookHandler(dbh): class WebhookHandler(tornado.web.RequestHandler): def post(self): + """ + Process the JSON post object. + """ json = tornado.escape.json_decode(self.request.body) post = json.get('post', None) if post: + # new api topic_id = post.get('id', 0) current_user = post.get('username', '未知用户') - message = post.get('cooked', '未知消息') + # get bbcode/markdown hybrid: + # more consice than html, still allows for image links + message = post.get('raw', '未知消息') dbh.on_sendmessage(topic_id, current_user, message) else: - topic_id = json.get('topic_id',0) + topic_id = json.get('topic_id', 0) current_user = json.get('current_user', '未知用户') + # what kind of data is this? message = json.get('message', '未知消息') dbh.on_sendmessage(topic_id, current_user, message) self.write('Got a message.') @@ -62,7 +73,6 @@ def post(self): class DiscourseBabbleHandle(BaseBotInstance): ChanTag = ChannelType.DiscourseBabble SupportMultiline = True - #rich_message = IRCHandle.rich_message send_to_bus = None def __init__(self, base_url, username, api_key, topic_ids): debug=config['debug'] @@ -73,7 +83,7 @@ def __init__(self, base_url, username, api_key, topic_ids): application = tornado.web.Application([ (r"/sendmessage", getWebhookHandler(self)), ],debug=debug, autoreload=debug) - application.listen(config['babble']['webhook_port'],address=config['babble'].get('webhook_host', '0.0.0.0')) + application.listen(config['babble']['webhook_port'], address=config['babble'].get('webhook_host', '0.0.0.0')) def listen(self): tornado.ioloop.IOLoop.instance().start() @@ -82,25 +92,18 @@ def on_sendmessage(self, topic_id, current_user, message): if current_user == self.username: return date, time = get_now_date_time() - # images = [m.group(1) for m in re.finditer(r'!\[.*\]\(.+\)',message)] logger.debug(message) - m = re.search(r'', message) - media_url = '' mtype = MessageType.Text - if m: - logger.debug(m) - mtype = MessageType.Photo - media_url = m.group(1) - if re.search(r'^http', media_url)==None: - if media_url.startswith('/uploads/'): - media_url = self.base_url + media_url - logger.debug(media_url) + # Replace discourse-relative media with absolute links + message = re.sub(r'!\[.*\]\(/uploads/.+\)', + r'![\1](' + self.base_url + r'/uploads/\2)', + message) msg = Message( ChannelType.DiscourseBabble, current_user, topic_id, xss.cooked_unescape(message), - mtype=mtype,media_url=media_url, - date=date,time=time + mtype=mtype, media_url='', + date=date, time=time ) self.send_to_bus(self,msg) @@ -108,17 +111,18 @@ def do_send_request(self, topic_id, text): if topic_id not in self.topic_ids: return requests.post(self.base_url - +'/babble/topics/' - +'%d'%int(topic_id) - +'/posts', + + '/babble/topics/' + + '%d' % int(topic_id) + + '/posts', data = { - 'api_user':self.username, - 'api_key':self.api_key, + 'api_user': self.username, + 'api_key': self.api_key, 'raw': text, 'topic_id': '%d'%int(topic_id) }) def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs): + # --- Pick a color from username # color that fits both dark and light background color_avail = (2, 3, 4, 5, 6, 7, 10, 12, 13) color = None @@ -128,7 +132,7 @@ def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs # background_num = sum([ord(i) for i in sender]) % 16 cidx = sum([ord(i) for i in sender]) % len(color_avail) foreground_num = color_avail[cidx] - color = Color(foreground_num) # + ',' + str(background_num) + color = Color(foreground_num) reply_quote = "" if 'reply_text' in kwargs: @@ -136,10 +140,11 @@ def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs reply_text = kwargs['reply_text'] if len(reply_text) > 8: reply_text = reply_text[:8] + '...' - reply_quote = "[b]{reply_to}[/b]
{reply_text}".format(reply_text=reply_text.strip(), reply_to=reply_to) + reply_text = reply_text.strip() + reply_quote = "[b]{reply_to}[/b]
{reply_text}".format(locals()) channel = raw.channel.capitalize() - channel = xss.replace(channel, [[r'[Ii][Rr][Cc]',r'IRC'],['Babble','hitorino']]) + channel = channel.replace('Babble', config['babble'].get('site_name', 'Discourse')) msg = self.rich_message(content, sender=sender, color=color, reply_quote=reply_quote, channel=channel) msg = self.formatRichText(msg) @@ -152,7 +157,7 @@ def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs def rich_message(self, content, sender=None, color=None, reply_quote="", channel=""): if color and sender: return RichText([ - (TextStyle(color=color,bold=1), "{}".format(sender)), + (TextStyle(color=color, bold=1), "{}".format(sender)), (TextStyle(color=Color(16)), " {} 用户\n".format(channel)), (TextStyle(color=Color(16)), "{}\n".format(reply_quote)), (TextStyle(), "{}".format(xss.md_escape(content))), @@ -171,7 +176,6 @@ def formatRichText(self, rich_text: RichText): if ts.is_normal(): formated_text += text continue - ctrl = [] def bold(text): if not ts.is_bold(): return text @@ -184,35 +188,35 @@ def underline(text): if not ts.is_underline(): return text return "[u]{}[/u]".format(text) - def fgcolor(text,color): - return '[color={}]{}[/color]'.format(IRC_COLOR_RGB[color],text) - def bgcolor(text,color): - return '[bgcolor={}]{}[/bgcolor]'.format(IRC_COLOR_RGB[color],text) + def fgcolor(text, color): + return '[color={}]{}[/color]'.format(IRC_COLOR_RGB[color], text) + def bgcolor(text, color): + return '[bgcolor={}]{}[/bgcolor]'.format(IRC_COLOR_RGB[color], text) def color(text): if not ts.has_color(): return text if ts.color.bg: - return bgcolor(fgcolor(text,ts.color.fg),ts.color.bg) + return bgcolor(fgcolor(text,ts.color.fg), ts.color.bg) else: return fgcolor(text, ts.color.fg) formated_text += (underline(italic(bold(color(text))))) return formated_text -def Babble2FishroomThread(irc_handle: DiscourseBabbleHandle, bus: MessageBus): - if irc_handle is None or isinstance(irc_handle, EmptyBot): +def Babble2FishroomThread(disbbl_handle: DiscourseBabbleHandle, bus: MessageBus): + if disbbl_handle is None or isinstance(disbbl_handle, EmptyBot): return def send_to_bus(self, msg): logger.debug(msg) bus.publish(msg) - irc_handle.send_to_bus=send_to_bus - irc_handle.listen() + disbbl_handle.send_to_bus=send_to_bus + disbbl_handle.listen() -def Fishroom2BabbleThread(irc_handle, bus): - if irc_handle is None or isinstance(irc_handle, EmptyBot): +def Fishroom2BabbleThread(disbbl_handle, bus): + if disbbl_handle is None or isinstance(disbbl_handle, EmptyBot): return for msg in bus.message_stream(): - irc_handle.forward_msg_from_fishroom(msg) + disbbl_handle.forward_msg_from_fishroom(msg) def init(): from .db import get_redis diff --git a/fishroom/xss.py b/fishroom/xss.py index 79e9b79..155bd3f 100644 --- a/fishroom/xss.py +++ b/fishroom/xss.py @@ -16,11 +16,11 @@ def md_escape(text): [r'_', r'\\_'], [r'`', r'\\`'], ] - return replace(text,replacements) + return replace(text, replacements) def replace(text,rs): for r in rs: - text = re.sub(r[0],r[1],text) + text = re.sub(r[0], r[1], text) return text def cooked_unescape(message): From 188b79955fd20dcb56d75b65c243e29297b1fd4a Mon Sep 17 00:00:00 2001 From: misaka4e21 Date: Sun, 6 Jan 2019 15:33:13 +0800 Subject: [PATCH 5/6] fishroom/DiscourseBabble: fix raw.channel == None. 515d28aa11985af3d136d209aa88f2f511895719 --- fishroom/DiscourseBabble.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fishroom/DiscourseBabble.py b/fishroom/DiscourseBabble.py index 9195dd9..26865d6 100644 --- a/fishroom/DiscourseBabble.py +++ b/fishroom/DiscourseBabble.py @@ -143,8 +143,11 @@ def send_msg(self, target, content, sender=None, first=False, raw=None, **kwargs reply_text = reply_text.strip() reply_quote = "[b]{reply_to}[/b]
{reply_text}".format(locals()) - channel = raw.channel.capitalize() - channel = channel.replace('Babble', config['babble'].get('site_name', 'Discourse')) + try: + channel = raw.channel.capitalize() + channel = channel.replace('Babble', config['babble'].get('site_name', 'Discourse')) + except AttributeError: + channel = None msg = self.rich_message(content, sender=sender, color=color, reply_quote=reply_quote, channel=channel) msg = self.formatRichText(msg) From 0b7e74e7ba2f0ebc65bce6d1b7f11decb3ea737c Mon Sep 17 00:00:00 2001 From: Mingye Wang Date: Mon, 7 Jan 2019 10:13:28 +0800 Subject: [PATCH 6/6] config: add discourse-babble example --- fishroom/config.py.example | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fishroom/config.py.example b/fishroom/config.py.example index 1c19131..aab06e3 100644 --- a/fishroom/config.py.example +++ b/fishroom/config.py.example @@ -54,6 +54,14 @@ config = { # "bot_msg_pattern": "^mubot|^!wikipedia", # }, + # Uncomment these if you want discourse babble access + # "babble": { + # "username": "fishroom", + # "api_key": "", + # "base_url": "https://forum.foo.moe/", + # "webhook_port": 2334 + # }, + # Uncomment these if you want WeChat access # "wechat": {},