user_reference_filter.rb 3.7 KB
Newer Older
1 2
require 'gitlab/markdown'

R
Robert Speicher 已提交
3 4
module Gitlab
  module Markdown
5
    # HTML filter that replaces user or group references with links.
R
Robert Speicher 已提交
6 7
    #
    # A special `@all` reference is also supported.
8
    class UserReferenceFilter < ReferenceFilter
R
Robert Speicher 已提交
9 10 11 12 13 14 15 16 17 18 19 20
      # Public: Find `@user` user references in text
      #
      #   UserReferenceFilter.references_in(text) do |match, username|
      #     "<a href=...>@#{user}</a>"
      #   end
      #
      # text - String text to search.
      #
      # Yields the String match, and the String user name.
      #
      # Returns a String replaced with the return of the block.
      def self.references_in(text)
21
        text.gsub(User.reference_pattern) do |match|
R
Robert Speicher 已提交
22 23 24 25
          yield match, $~[:user]
        end
      end

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
      def self.referenced_by(node)
        if node.has_attribute?('data-group')
          group = Group.find(node.attr('data-group')) rescue nil
          return unless group

          { user: group.users }
        elsif node.has_attribute?('data-user')
          user = User.find(node.attr('data-user')) rescue nil
          return unless user

          { user: user }
        elsif node.has_attribute?('data-project')
          project = Project.find(node.attr('data-project')) rescue nil
          return unless project

          { user: project.team.members.flatten }
        end
      end

      def self.user_can_reference?(user, node)
        if node.has_attribute?('data-group')
          group = Group.find(node.attr('data-group')) rescue nil
          Ability.abilities.allowed?(user, :read_group, group)
        else
          super
        end
      end

R
Robert Speicher 已提交
54
      def call
55
        replace_text_nodes_matching(User.reference_pattern) do |content|
56
          user_link_filter(content)
R
Robert Speicher 已提交
57 58 59 60 61 62 63 64 65 66 67
        end
      end

      # Replace `@user` user references in text with links to the referenced
      # user's profile page.
      #
      # text - String text to replace references in.
      #
      # Returns a String with `@user` references replaced with links. All links
      # have `gfm` and `gfm-project_member` class names attached for styling.
      def user_link_filter(text)
68 69 70 71 72
        self.class.references_in(text) do |match, username|
          if username == 'all'
            link_to_all
          elsif namespace = Namespace.find_by(path: username)
            link_to_namespace(namespace) || match
R
Robert Speicher 已提交
73 74 75 76 77 78
          else
            match
          end
        end
      end

79 80 81
      private

      def urls
D
Douwe Maan 已提交
82
        Gitlab::Application.routes.url_helpers
R
Robert Speicher 已提交
83 84
      end

85 86
      def link_class
        reference_class(:project_member)
R
Robert Speicher 已提交
87 88
      end

89 90 91 92 93
      def link_to_all
        project = context[:project]

        url = urls.namespace_project_url(project.namespace, project,
                                         only_path: context[:only_path])
94
        data = data_attribute(project: project.id)
95

96
        text = User.reference_prefix + 'all'
97
        %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
R
Robert Speicher 已提交
98 99
      end

100 101 102 103 104 105 106 107 108
      def link_to_namespace(namespace)
        if namespace.is_a?(Group)
          link_to_group(namespace.path, namespace)
        else
          link_to_user(namespace.path, namespace)
        end
      end

      def link_to_group(group, namespace)
109
        url = urls.group_url(group, only_path: context[:only_path])
110
        data = data_attribute(group: namespace.id)
111

112
        text = Group.reference_prefix + group
113
        %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
114 115 116 117
      end

      def link_to_user(user, namespace)
        url = urls.user_url(user, only_path: context[:only_path])
118
        data = data_attribute(user: namespace.owner_id)
119

120
        text = User.reference_prefix + user
121
        %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
R
Robert Speicher 已提交
122 123 124 125
      end
    end
  end
end