From 97d088726443a6b1c682cf629b5662c54bfbb291 Mon Sep 17 00:00:00 2001 From: hernani Date: Fri, 4 Feb 2011 17:47:40 +0000 Subject: [PATCH] fixes OSQA 555 and OSQA 294 git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@741 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- forum/models/node.py | 4 +- forum/models/question.py | 26 +++------ forum/utils/userlinking.py | 112 ++++++++++++++++++++++++++----------- 3 files changed, 91 insertions(+), 51 deletions(-) diff --git a/forum/models/node.py b/forum/models/node.py index 43d12b3..ebe9139 100644 --- a/forum/models/node.py +++ b/forum/models/node.py @@ -6,7 +6,6 @@ import markdown from django.utils.translation import ugettext as _ from django.utils.safestring import mark_safe from django.utils.html import strip_tags -from forum.utils.userlinking import auto_user_link from forum.utils.html import sanitize_html from utils import PickledObjectField @@ -338,6 +337,9 @@ class Node(BaseModel, NodeContent): def activate_revision(self, user, revision, extensions=['urlize']): self.title = revision.title self.tagnames = revision.tagnames + + from forum.utils.userlinking import auto_user_link + self.body = auto_user_link(self, self._as_markdown(revision.body, *extensions)) self.active_revision = revision diff --git a/forum/models/question.py b/forum/models/question.py index 010647c..bef5bb5 100644 --- a/forum/models/question.py +++ b/forum/models/question.py @@ -63,29 +63,21 @@ class Question(Node): return [Question.objects.get(id=r['id']) for r in related_list] def get_active_users(self): - active_users = [] + active_users = set() - active_users.append(self.author) + active_users.add(self.author) for answer in self.answers: - active_users.append(answer.author) - - for child in self.children.all(): - active_users.append(child.author) - for grandchild in child.children.all(): - active_users.append(grandchild.author) - - # Remove duplicates - unique_active_users = [] - for user in active_users: - if user not in unique_active_users: - unique_active_users.append(user) - active_users = unique_active_users - del unique_active_users + active_users.add(answer.author) + + for comment in answer.comments: + active_users.add(comment.author) + + for comment in self.comments: + active_users.add(comment.author) return active_users - def question_viewed(instance, **kwargs): instance.extra_count += 1 instance.save() diff --git a/forum/utils/userlinking.py b/forum/utils/userlinking.py index fd7a66d..39f8bbb 100644 --- a/forum/utils/userlinking.py +++ b/forum/utils/userlinking.py @@ -1,44 +1,90 @@ import re -from forum.models.user import User +from forum.models import User, Question, Answer, Comment + +def find_best_match_in_name(content, uname, fullname, start_index): + end_index = start_index + len(fullname) + + while end_index > start_index: + if content[start_index : end_index].lower() == fullname.lower(): + return content[start_index : end_index] + + while len(fullname) and fullname[-1] != ' ': + fullname = fullname[:-1] + + fullname = fullname.rstrip() + end_index = start_index + len(fullname) + + return uname + +APPEAL_PATTERN = re.compile(r'@\w+') def auto_user_link(node, content): - patern = r'@\w+' - appeals = re.findall(patern, content) + + # We should find the root of the node tree (question) the current node belongs to. + if isinstance(node, Question): + question = node + elif isinstance(node, Answer): + question = node.question + elif isinstance(node, Comment): + if node.question: + question = node.question + elif node.answer: + question = node.answer.question + + # Now we've got the root question. Let's get the list of active users. + active_users = question.get_active_users() + + appeals = APPEAL_PATTERN.finditer(content) + + replacements = [] for appeal in appeals: # Try to find the profile URL - username = appeal[1:] - profile_url = None - - try: - user = User.objects.get(username__iexact=username) - profile_url = user.get_absolute_url() - except User.DoesNotExist: - """If we don't find the user from the first time, the interesting part - begins. We look through all the authors (looking through question, - comments, answers, and if it matches some of the -- we link him.""" - - # We should find the root of the node tree (question) the current node belongs to. - if node.node_type == "question": - question = node - elif node.node_type == "answer": - question = node.question - elif node.node_type == "comment": - if not node.question: - question = node - else: - question = node.question + username = appeal.group(0)[1:] + + matches = [] + + for user in active_users: + if user.username.lower().startswith(username.lower()): + matches.append(user) + + if len(matches) == 1: + replacements.append( + (find_best_match_in_name(content, username, matches[0].username, appeal.start(0) + 1), matches[0]) + ) + elif len(matches) == 0: + matches = User.objects.filter(username__istartswith=username) - # Now we've got the root question. Let's get the list of active users. - active_users = question.get_active_users() + if (len(matches) == 0): + continue + + best_user_match = None + final_match = "" + + for user in matches: + user_match = find_best_match_in_name(content, username, user.username, appeal.start(0) + 1) - for active_user in active_users: - if active_user.username.lower().startswith(username.lower()): - profile_url = active_user.get_absolute_url() + if (len(user_match) < len(final_match)): + continue + + if (len(user_match) == len(final_match)): + if not (user.username.lower() == user_match.lower()): + continue + + if (best_user_match and (best_user_match.username == final_match)): + continue + + best_user_match = user + final_match = user_match + + replacements.append((final_match, best_user_match)) + + for replacement in replacements: + to_replace = "@" + replacement[0] + profile_url = replacement[1].get_absolute_url() - if (profile_url is not None) and (appeal is not None): - auto_link = '%s' % (profile_url, appeal) - content = content.replace(appeal, auto_link) + auto_link = '%s' % (profile_url, to_replace) + content = content.replace(to_replace, auto_link) - return content \ No newline at end of file + return content -- 2.45.1