summaryrefslogtreecommitdiff
path: root/lib/gitlab/user_extractor.rb
blob: f0557f6ad6827e703dcc735ccd8bd2108fa239cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# frozen_string_literal: true

# This class extracts all users found in a piece of text by the username or the
# email address

module Gitlab
  class UserExtractor
    # Not using `Devise.email_regexp` to filter out any chars that an email
    # does not end with and not pinning the email to a start of end of a string.
    EMAIL_REGEXP = /(?<email>([^@\s]+@[^@\s]+(?<!\W)))/
    USERNAME_REGEXP = User.reference_pattern

    def initialize(text)
      # EE passes an Array to `text` in a few places, so we want to support both
      # here.
      @text = Array(text).join(' ')
    end

    def users
      return User.none unless @text.present?
      return User.none if references.empty?

      @users ||= User.from_union(union_relations)
    end

    def usernames
      matches[:usernames]
    end

    def emails
      matches[:emails]
    end

    def references
      @references ||= matches.values.flatten
    end

    def matches
      @matches ||= {
        emails: @text.scan(EMAIL_REGEXP).flatten.uniq,
        usernames: @text.scan(USERNAME_REGEXP).flatten.uniq
      }
    end

    private

    def union_relations
      relations = []

      relations << User.by_any_email(emails) if emails.any?
      relations << User.by_username(usernames) if usernames.any?

      relations
    end
  end
end