changeset 5877:ba5fee3879c8

utils: improve extract_mentioned_users usefulness Previously, extract_mentioned_users performed a regex search, converted to a set to remove duplicates, converted that set back into a list, and sorted the list on username, ignoring case. Every single caller of the function then promptly took the carefully pruned and sorted result and put it back into a set, rendering the entire exercise pointless. In addition, every caller also resolved the usernames to database User objects. In this changeset, extract_mentioned_users is changed to return a set of database User objects directly. A new extract_mentioned_usernames function, which does only username extraction, is kept for the sole purpose of providing a more testable interface (no database needed). Bonus feature: The new extract_mentioned_users will prune non-existent users, as well as the DEFAULT user. This means it is no longer possible to @mention (and send notifications to) the DEFAULT user.
author Søren Løvborg <sorenl@unity3d.com>
date Wed, 06 Apr 2016 14:50:47 +0200
parents ea02c8b2b529
children 1658beb26ff9
files kallithea/lib/utils2.py kallithea/model/comment.py kallithea/model/pull_request.py kallithea/tests/other/test_libs.py
diffstat 4 files changed, 23 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/lib/utils2.py	Tue Apr 19 17:58:21 2016 +0200
+++ b/kallithea/lib/utils2.py	Wed Apr 06 14:50:47 2016 +0200
@@ -572,25 +572,30 @@
                 return
         return datetime.datetime.fromtimestamp(tm)
 
+
 # Must match regexp in kallithea/public/js/base.js MentionsAutoComplete()
 # Check char before @ - it must not look like we are in an email addresses.
 # Matching is greedy so we don't have to look beyond the end.
 MENTIONS_REGEX = re.compile(r'(?:^|(?<=[^a-zA-Z0-9]))@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])')
 
-def extract_mentioned_users(s):
+def extract_mentioned_usernames(text):
     r"""
-    Returns unique usernames from given string s that have @mention
+    Returns list of (possible) usernames @mentioned in given text.
 
-    :param s: string to get mentions
-
-    >>> extract_mentioned_users('@1-2.a_X,@1234 not@not @ddd@not @n @ee @ff @gg, @gg;@hh @n\n@zz,')
+    >>> extract_mentioned_usernames('@1-2.a_X,@1234 not@not @ddd@not @n @ee @ff @gg, @gg;@hh @n\n@zz,')
     ['1-2.a_X', '1234', 'ddd', 'ee', 'ff', 'gg', 'hh', 'zz']
     """
-    usrs = set()
-    for username in MENTIONS_REGEX.findall(s):
-        usrs.add(username)
+    return MENTIONS_REGEX.findall(text)
 
-    return sorted(list(usrs), key=lambda k: k.lower())
+def extract_mentioned_users(text):
+    """ Returns set of actual database Users @mentioned in given text. """
+    from kallithea.model.db import User
+    result = set()
+    for name in extract_mentioned_usernames(text):
+        user = User.get_by_username(name, case_insensitive=True)
+        if user is not None and user.username != User.DEFAULT_USER:
+            result.add(user)
+    return result
 
 
 class AttributeDict(dict):
--- a/kallithea/model/comment.py	Tue Apr 19 17:58:21 2016 +0200
+++ b/kallithea/model/comment.py	Wed Apr 06 14:50:47 2016 +0200
@@ -51,14 +51,6 @@
     def __get_pull_request(self, pull_request):
         return self._get_instance(PullRequest, pull_request)
 
-    def _extract_mentions(self, s):
-        user_objects = []
-        for username in extract_mentioned_users(s):
-            user_obj = User.get_by_username(username, case_insensitive=True)
-            if user_obj:
-                user_objects.append(user_obj)
-        return user_objects
-
     def _get_notification_data(self, repo, comment, user, comment_text,
                                line_no=None, revision=None, pull_request=None,
                                status_change=None, closing_pr=False):
@@ -210,8 +202,7 @@
                 email_kwargs=email_kwargs,
             )
 
-            mention_recipients = set(self._extract_mentions(body)) \
-                                    .difference(recipients)
+            mention_recipients = extract_mentioned_users(body).difference(recipients)
             if mention_recipients:
                 email_kwargs['is_mention'] = True
                 subj = _('[Mention]') + ' ' + subj
--- a/kallithea/model/pull_request.py	Tue Apr 19 17:58:21 2016 +0200
+++ b/kallithea/model/pull_request.py	Wed Apr 06 14:50:47 2016 +0200
@@ -35,7 +35,7 @@
 from kallithea.lib.exceptions import UserInvalidException
 from kallithea.model import BaseModel
 from kallithea.model.db import PullRequest, PullRequestReviewers, Notification, \
-    ChangesetStatus, User
+    ChangesetStatus
 from kallithea.model.notification import NotificationModel
 from kallithea.lib.utils2 import extract_mentioned_users, safe_unicode
 
@@ -109,8 +109,7 @@
             pull_request=new
         )
 
-        mention_recipients = set(User.get_by_username(username, case_insensitive=True)
-                                 for username in extract_mentioned_users(new.description))
+        mention_recipients = extract_mentioned_users(new.description)
         self.__add_reviewers(created_by_user, new, reviewers, mention_recipients)
 
         return new
@@ -163,7 +162,6 @@
                                        email_kwargs=email_kwargs)
 
         if mention_recipients:
-            mention_recipients.discard(None)
             mention_recipients.difference_update(reviewers)
         if mention_recipients:
             email_kwargs['is_mention'] = True
@@ -174,10 +172,8 @@
                                        email_kwargs=email_kwargs)
 
     def mention_from_description(self, user, pr, old_description=''):
-        mention_recipients = set(User.get_by_username(username, case_insensitive=True)
-                                 for username in extract_mentioned_users(pr.description))
-        mention_recipients.difference_update(User.get_by_username(username, case_insensitive=True)
-                                             for username in extract_mentioned_users(old_description))
+        mention_recipients = (extract_mentioned_users(pr.description) -
+                              extract_mentioned_users(old_description))
 
         log.debug("Mentioning %s", mention_recipients)
         self.__add_reviewers(user, pr, [], mention_recipients)
--- a/kallithea/tests/other/test_libs.py	Tue Apr 19 17:58:21 2016 +0200
+++ b/kallithea/tests/other/test_libs.py	Wed Apr 06 14:50:47 2016 +0200
@@ -102,7 +102,7 @@
         self.assertEqual(str2bool(str_bool), expected)
 
     def test_mention_extractor(self):
-        from kallithea.lib.utils2 import extract_mentioned_users
+        from kallithea.lib.utils2 import extract_mentioned_usernames
         sample = (
             "@first hi there @world here's my email username@example.com "
             "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
@@ -111,10 +111,10 @@
             "user.dot  hej ! not-needed maril@example.com"
         )
 
-        s = sorted([
+        expected = set([
             '2one_more22', 'first', 'lukaszb', 'one', 'one_more22', 'UPPER', 'cAmEL', 'john',
-            'marian.user', 'marco-polo', 'marco_polo', 'world'], key=lambda k: k.lower())
-        self.assertEqual(s, extract_mentioned_users(sample))
+            'marian.user', 'marco-polo', 'marco_polo', 'world'])
+        self.assertEqual(expected, set(extract_mentioned_usernames(sample)))
 
     @parameterized.expand([
         (dict(), u'just now'),