summaryrefslogtreecommitdiff
path: root/app/services/members/invite_service.rb
blob: 1bf209ab79d9b2b14f5cfd76ed869426d0f82e83 (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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# frozen_string_literal: true

module Members
  class InviteService < Members::CreateService
    extend ::Gitlab::Utils::Override

    def initialize(*args)
      super

      @invites += parsed_emails

      @errors = {}
    end

    private

    alias_method :formatted_errors, :errors

    def parsed_emails
      # can't put this in the initializer since `invites_from_params` is called in super class
      # and needs it
      @parsed_emails ||= (formatted_param(params[:email]) || [])
    end

    def formatted_param(parameter)
      parameter&.split(',')&.uniq&.flatten
    end

    def validate_invitable!
      super

      return if params[:email].blank?

      # we need the below due to add_users hitting Members::CreatorService.parse_users_list and ignoring invalid emails
      # ideally we wouldn't need this, but we can't really change the add_users method
      invalid_emails.each { |email| errors[email] = s_('AddMember|Invite email is invalid') }
    end

    def invalid_emails
      parsed_emails.each_with_object([]) do |email, invalid|
        next if Member.valid_email?(email)

        invalid << email
        @invites.delete(email)
      end
    end

    override :blank_invites_message
    def blank_invites_message
      s_('AddMember|Invites cannot be blank')
    end

    override :add_error_for_member
    def add_error_for_member(member, existing_errors)
      errors[invited_object(member)] = all_member_errors(member, existing_errors).to_sentence
    end

    def invited_object(member)
      return member.invite_email if member.invite_email

      # There is a case where someone was invited by email, but the `user` record exists.
      # The member record returned will not have an invite_email attribute defined since
      # the CreatorService finds `user` record sometimes by email.
      # At that point we lose the info of whether this invite was done by `user` or by email.
      # Here we will give preference to check invites by user_id first.
      # There is also a case where a user could be invited by their email and
      # at the same time via the API in the same request.
      # This would would mean the same user is invited as user_id and email.
      # However, that isn't as likely from the UI at least since the token generator checks
      # for that case and doesn't allow email being used if the user exists as a record already.
      if member.user_id.to_s.in?(invites)
        member.user.username
      else
        member.user.all_emails.detect { |email| email.in?(invites) }
      end
    end
  end
end