summaryrefslogtreecommitdiff
path: root/app/controllers/invites_controller.rb
blob: 0a9a9e03e94cd031183c4d2fb41333dd62c8a4c1 (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# frozen_string_literal: true

class InvitesController < ApplicationController
  include Gitlab::Utils::StrongMemoize

  prepend_before_action :authenticate_user!, :track_invite_join_click, only: :show
  before_action :member
  before_action :ensure_member_exists
  before_action :invite_details
  skip_before_action :authenticate_user!, only: :decline

  helper_method :member?, :current_user_matches_invite?

  respond_to :html

  feature_category :authentication_and_authorization

  def show
    accept if skip_invitation_prompt?
  end

  def accept
    if member.accept_invite!(current_user)
      redirect_to invite_details[:path], notice: helpers.invite_accepted_notice(member)
    else
      redirect_back_or_default(options: { alert: _("The invitation could not be accepted.") })
    end
  end

  def decline
    if member.decline_invite!
      return render layout: 'signup_onboarding' if !current_user && member.invite_to_unknown_user? && member.created_by

      path =
        if current_user
          dashboard_projects_path
        else
          new_user_session_path
        end

      redirect_to path, notice: _("You have declined the invitation to join %{title} %{name}.") %
        { title: invite_details[:title], name: invite_details[:name] }
    else
      redirect_back_or_default(options: { alert: _("The invitation could not be declined.") })
    end
  end

  private

  def skip_invitation_prompt?
    !member? && current_user_matches_invite?
  end

  def current_user_matches_invite?
    @member.invite_email == current_user.email
  end

  def member?
    strong_memoize(:is_member) do
      @member.source.users.include?(current_user)
    end
  end

  def member
    strong_memoize(:member) do
      @token = params[:id]
      Member.find_by_invite_token(@token)
    end
  end

  def ensure_member_exists
    return if member

    redirect_back_or_default(options: { alert: _("The invitation can not be found with the provided invite token.") })
  end

  def track_invite_join_click
    experiment('members/invite_email', actor: member).track(:join_clicked) if member && Members::InviteEmailExperiment.initial_invite_email?(params[:invite_type])
  end

  def authenticate_user!
    return if current_user

    store_location_for(:user, invite_landing_url) if member

    if user_sign_up?
      set_session_invite_params

      experiment(:invite_signup_page_interaction, actor: member) do |experiment_instance|
        set_originating_member_id if experiment_instance.enabled?

        experiment_instance.use do
          redirect_to new_user_registration_path(invite_email: member.invite_email), notice: _("To accept this invitation, create an account or sign in.")
        end
        experiment_instance.try do
          redirect_to new_users_sign_up_invite_path(invite_email: member.invite_email)
        end

        experiment_instance.track(:view)
      end
    else
      redirect_to new_user_session_path(sign_in_redirect_params), notice: sign_in_notice
    end
  end

  def set_session_invite_params
    session[:invite_email] = member.invite_email

    set_originating_member_id if Members::InviteEmailExperiment.initial_invite_email?(params[:invite_type])
  end

  def set_originating_member_id
    session[:originating_member_id] = member.id
  end

  def sign_in_redirect_params
    member ? { invite_email: member.invite_email } : {}
  end

  def user_sign_up?
    Gitlab::CurrentSettings.allow_signup? && member && !User.find_by_any_email(member.invite_email)
  end

  def sign_in_notice
    if Gitlab::CurrentSettings.allow_signup?
      _("To accept this invitation, sign in or create an account.")
    else
      _("To accept this invitation, sign in.")
    end
  end

  def invite_landing_url
    root_url + invite_details[:path]
  end

  def invite_details
    @invite_details ||= case member.source
                        when Project
                          {
                            name: member.source.full_name,
                            url: project_url(member.source),
                            title: _("project"),
                            path: member.source.activity_path
                          }
                        when Group
                          {
                            name: member.source.name,
                            url: group_url(member.source),
                            title: _("group"),
                            path: member.source.activity_path
                          }
                        end
  end
end