From e93f0f4980df6e0ef179340ad7cac65d6ba419bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Cort=C3=A9z?= Date: Sun, 1 Feb 2015 00:49:03 -0600 Subject: [PATCH] User actions dialog now works, the spell checker module ignores twitter usernames, hashtags, URL and email addresses --- src/controller/mainController.py | 81 ++++++++++++++++++- src/controller/settings.py | 3 +- src/controller/userActionsController.py | 72 +++++++++++++++++ src/extra/SpellChecker/spellchecker.py | 6 +- src/extra/SpellChecker/twitterFilter.py | 15 ++++ src/sessionmanager/session.py | 5 ++ src/wxUI/dialogs/__init__.py | 2 +- src/wxUI/dialogs/configuration.py | 2 +- .../dialogs/{follow.py => userActions.py} | 21 +++-- 9 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 src/controller/userActionsController.py create mode 100644 src/extra/SpellChecker/twitterFilter.py rename src/wxUI/dialogs/{follow.py => userActions.py} (76%) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 6caa7ed3..2eb3b579 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from wxUI import (view, dialogs, commonMessageDialogs) +from twitter import utils from sessionmanager import manager import buffersController import messages @@ -22,6 +23,7 @@ import logging if platform.system() == "Windows": import keystrokeEditor from keyboard_handler.wx_handler import WXKeyboardHandler +import userActionsController log = logging.getLogger("mainController") @@ -108,7 +110,15 @@ class Controller(object): widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_favourites, self.view.unfav) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_item, self.view.view) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.delete, self.view.delete) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.follow, menuitem=self.view.follow) widgetUtils.connect_event(self.view, widgetUtils.MENU, self.send_dm, self.view.dm) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.unfollow, menuitem=self.view.unfollow) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.mute, menuitem=self.view.mute) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.unmute, menuitem=self.view.unmute) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.report, menuitem=self.view.report) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.block, menuitem=self.view.block) + widgetUtils.connect_event(self.view, widgetUtils.MENU, self.unblock, menuitem=self.view.unblock) + widgetUtils.connect_event(self.view.nb, widgetUtils.NOTEBOOK_PAGE_CHANGED, self.buffer_changed) def __init__(self): @@ -307,8 +317,75 @@ class Controller(object): session_.sessions[item].sound.cleaner.cancel() widgetUtils.exit_application() - def action(self, do_action): - pass + def follow(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users) + + def unfollow(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users, "unfollow") + + def mute(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users, "mute") + + def unmute(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users, "unmute") + + def block(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users, "block") + + def unblock(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users, "unblock") + + def report(self, *args, **kwargs): + buff = self.get_current_buffer() + if not hasattr(buff, "get_right_tweet"): return + tweet = buff.get_right_tweet() + if buff.type != "people": + users = utils.get_all_users(tweet, buff.session.db) + else: + users = [tweet["screen_name"]] + u = userActionsController.userActionsController(buff, users, "report") def post_tweet(self, event=None): buffer = self.get_best_buffer() diff --git a/src/controller/settings.py b/src/controller/settings.py index 427889c2..3f6f0e33 100644 --- a/src/controller/settings.py +++ b/src/controller/settings.py @@ -7,6 +7,7 @@ import widgetUtils import config import languageHandler from wxUI.dialogs import configuration +from wxUI import commonMessageDialogs from extra.autocompletionUsers import settings from extra.AudioUploader import dropbox_transfer from pubsub import pub @@ -154,7 +155,7 @@ class accountSettingsController(globalSettingsController): if self.dialog.ignored_clients.get_clients() == 0: return id = self.dialog.ignored_clients.get_client_id() self.config["twitter"]["ignored_clients"].pop(id) - self.dialog.ignored_clients.remove(id) + self.dialog.ignored_clients.remove_(id) def manage_dropbox(self, *args, **kwargs): if self.dialog.services.get_dropbox() == _(u"Link your Dropbox account"): diff --git a/src/controller/userActionsController.py b/src/controller/userActionsController.py new file mode 100644 index 00000000..79bd3eb9 --- /dev/null +++ b/src/controller/userActionsController.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +from wxUI.dialogs import userActions +import re +import widgetUtils +import output +from twython import TwythonError + +class userActionsController(object): + def __init__(self, buffer, users=[], default="follow"): + super(userActionsController, self).__init__() + self.buffer = buffer + self.session = buffer.session + self.dialog = userActions.UserActionsDialog(users, default) + if self.dialog.get_response() == widgetUtils.OK: + self.process_action() + + def process_action(self): + action = self.dialog.get_action() + user = self.dialog.get_user() + if user == "": return + getattr(self, action)(user) + + def follow(self, user): + try: + self.session.twitter.twitter.create_friendship(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def unfollow(self, user): + try: + id = self.session.twitter.twitter.destroy_friendship(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def mute(self, user): + try: + id = self.session.twitter.twitter.create_mute(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def unmute(self, user): + try: + id = self.session.twitter.twitter.destroy_mute(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def report(self, user): + try: + id = self.session.twitter.twitter.report_spam(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def block(self, user): + try: + id = self.session.twitter.twitter.create_block(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def unblock(self, user): + try: + id = self.session.twitter.twitter.destroy_block(screen_name=user ) + except TwythonError as err: + output.speak("Error %s: %s" % (err.error_code, err.msg), True) + + def ignore_client(self, user): + tweet = self.buffer.get_right_tweet() + if tweet.has_key("sender"): + output.speak(_(u"You can't ignore direct messages")) + return + client = re.sub(r"(?s)<.*?>", "", tweet["source"]) + if client not in self.session.settings["twitter"]["ignored_clients"]: + self.session.settings["twitter"]["ignored_clients"].append(client) \ No newline at end of file diff --git a/src/extra/SpellChecker/spellchecker.py b/src/extra/SpellChecker/spellchecker.py index a466bd2d..f04a0367 100644 --- a/src/extra/SpellChecker/spellchecker.py +++ b/src/extra/SpellChecker/spellchecker.py @@ -8,6 +8,8 @@ import config import languageHandler from enchant.checker import SpellChecker from enchant.errors import DictNotFoundError +from enchant import tokenize +import twitterFilter class spellChecker(object): def __init__(self, text, dictionary): @@ -17,10 +19,10 @@ class spellChecker(object): try: if config.app["app-settings"]["language"] == "system": log.debug("Using the system language") - self.checker = SpellChecker() + self.checker = SpellChecker(filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter]) else: log.debug("Using language: %s" % (languageHandler.getLanguage(),)) - self.checker = SpellChecker(languageHandler.getLanguage()) + self.checker = SpellChecker(languageHandler.getLanguage(), filters=[twitterFilter.TwitterFilter, tokenize.EmailFilter, tokenize.URLFilter]) self.checker.set_text(text) except DictNotFoundError: log.exception("Dictionary for language %s not found." % (dictionary,)) diff --git a/src/extra/SpellChecker/twitterFilter.py b/src/extra/SpellChecker/twitterFilter.py new file mode 100644 index 00000000..f5e308c3 --- /dev/null +++ b/src/extra/SpellChecker/twitterFilter.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +import re +from enchant.tokenize import Filter + +class TwitterFilter(Filter): + """Filter skipping over twitter usernames and hashtags. + This filter skips any words matching the following regular expression: + ^[#@](\S){1, }$ + That is, any words that resemble users and hashtags. + """ + _pattern = re.compile(r"^[#@](\S){1,}$") + def _skip(self,word): + if self._pattern.match(word): + return True + return False diff --git a/src/sessionmanager/session.py b/src/sessionmanager/session.py index 6a8dee65..994452e2 100644 --- a/src/sessionmanager/session.py +++ b/src/sessionmanager/session.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """ The main session object. Here are the twitter functions to interact with the "model" of TWBlue.""" +import urllib2 import twitter import application import session_exceptions as Exceptions @@ -303,3 +304,7 @@ class Session(object): if not hasattr(self, "timelinesStream"): self.get_timelines() self.reconnection_function_active = False + try: + urllib2.urlopen("http://74.125.228.231", timeout=5) + except urllib2.URLError: + pub.sendMessage("stream-error", session=self.session_id) \ No newline at end of file diff --git a/src/wxUI/dialogs/__init__.py b/src/wxUI/dialogs/__init__.py index b7945e73..d1e585a3 100644 --- a/src/wxUI/dialogs/__init__.py +++ b/src/wxUI/dialogs/__init__.py @@ -1 +1 @@ -import baseDialog, configuration, follow, lists, message, search, show_user, update_profile, urlList +import baseDialog, configuration, lists, message, search, show_user, update_profile, urlList diff --git a/src/wxUI/dialogs/configuration.py b/src/wxUI/dialogs/configuration.py index a581d614..90c805d2 100644 --- a/src/wxUI/dialogs/configuration.py +++ b/src/wxUI/dialogs/configuration.py @@ -96,7 +96,7 @@ class ignoredClients(wx.Panel): def get_client_id(self): return self.clients.GetSelection() - def remove(self, id): + def remove_(self, id): self.clients.Delete(id) class sound(wx.Panel): diff --git a/src/wxUI/dialogs/follow.py b/src/wxUI/dialogs/userActions.py similarity index 76% rename from src/wxUI/dialogs/follow.py rename to src/wxUI/dialogs/userActions.py index 61831b1d..39c427fc 100644 --- a/src/wxUI/dialogs/follow.py +++ b/src/wxUI/dialogs/userActions.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- import wx -class actionDialog(wx.Dialog): - def __init__(self, user=[], default="follow", *args, **kwargs): - super(actionDialog, self).__init__(parent=None, *args, **kwargs) +class UserActionsDialog(wx.Dialog): + def __init__(self, users=[], default="follow", *args, **kwargs): + super(UserActionsDialog, self).__init__(parent=None, *args, **kwargs) panel = wx.Panel(self) userSizer = wx.BoxSizer() self.SetTitle(_(u"Action")) - self.cb = wx.ComboBox(panel, -1, choices=user, value=user[0]) + self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0]) self.cb.SetFocus() userSizer.Add(self.cb) actionSizer = wx.BoxSizer(wx.VERTICAL) @@ -19,6 +19,7 @@ class actionDialog(wx.Dialog): self.block = wx.RadioButton(panel, -1, _(u"Block")) self.unblock = wx.RadioButton(panel, -1, _(u"Unblock")) self.reportSpam = wx.RadioButton(panel, -1, _(u"Report as spam")) + self.ignore_client = wx.RadioButton(panel, -1, _(u"Ignore tweets from this client")) self.setup_default(default) actionSizer.Add(label2) actionSizer.Add(self.follow) @@ -28,6 +29,7 @@ class actionDialog(wx.Dialog): actionSizer.Add(self.block) actionSizer.Add(self.unblock) actionSizer.Add(self.reportSpam) + actionSizer.Add(self.ignore_client) sizer = wx.BoxSizer(wx.VERTICAL) ok = wx.Button(panel, wx.ID_OK, _(u"OK")) ok.SetDefault() @@ -48,6 +50,7 @@ class actionDialog(wx.Dialog): elif self.reportSpam.GetValue() == True: return "report" elif self.block.GetValue() == True: return "block" elif self.unblock.GetValue() == True: return "unblock" + elif self.ignore_client.GetValue() == True: return "ignore_client" def setup_default(self, default): if default == "follow": @@ -63,4 +66,12 @@ class actionDialog(wx.Dialog): elif default == "block": self.block.SetValue(True) elif default == "unblock": - self.unblock.SetValue(True) \ No newline at end of file + self.unblock.SetValue(True) + elif default == "ignore_client": + self.ignore_client.SetValue(True) + + def get_response(self): + return self.ShowModal() + + def get_user(self): + return self.cb.GetValue() \ No newline at end of file