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()
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 = '<a href="%s">%s</a>' % (profile_url, appeal)
- content = content.replace(appeal, auto_link)
+ auto_link = '<a href="%s">%s</a>' % (profile_url, to_replace)
+ content = content.replace(to_replace, auto_link)
- return content
\ No newline at end of file
+ return content