summaryrefslogtreecommitdiff
path: root/app/services/members/invite_service.rb
blob: 169500d08f068f23adb9553c90f42738bd37346c (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# frozen_string_literal: true

module Members
  class InviteService < Members::BaseService
    BlankEmailsError = Class.new(StandardError)
    TooManyEmailsError = Class.new(StandardError)

    def initialize(*args)
      super

      @errors = {}
      @emails = params[:email]&.split(',')&.uniq&.flatten
    end

    def execute(source)
      validate_emails!

      @source = source
      emails.each(&method(:process_email))
      result
    rescue BlankEmailsError, TooManyEmailsError => e
      error(e.message)
    end

    private

    attr_reader :source, :errors, :emails

    def validate_emails!
      raise BlankEmailsError, s_('AddMember|Email cannot be blank') if emails.blank?

      if user_limit && emails.size > user_limit
        raise TooManyEmailsError, s_("AddMember|Too many users specified (limit is %{user_limit})") % { user_limit: user_limit }
      end
    end

    def user_limit
      limit = params.fetch(:limit, Members::CreateService::DEFAULT_LIMIT)

      limit < 0 ? nil : limit
    end

    def process_email(email)
      return if existing_member?(email)
      return if existing_invite?(email)
      return if existing_request?(email)

      add_member(email)
    end

    def existing_member?(email)
      existing_member = source.members.with_user_by_email(email).exists?

      if existing_member
        errors[email] = s_("AddMember|Already a member of %{source_name}") % { source_name: source.name }
        return true
      end

      false
    end

    def existing_invite?(email)
      existing_invite = source.members.search_invite_email(email).exists?

      if existing_invite
        errors[email] = s_("AddMember|Member already invited to %{source_name}") % { source_name: source.name }
        return true
      end

      false
    end

    def existing_request?(email)
      existing_request = source.requesters.with_user_by_email(email).exists?

      if existing_request
        errors[email] = s_("AddMember|Member cannot be invited because they already requested to join %{source_name}") % { source_name: source.name }
        return true
      end

      false
    end

    def add_member(email)
      new_member = source.add_user(email, params[:access_level], current_user: current_user, expires_at: params[:expires_at])

      errors[email] = new_member.errors.full_messages.to_sentence if new_member.invalid?
    end

    def result
      if errors.any?
        error(errors)
      else
        success
      end
    end
  end
end