Class: InviteRedeemer

Inherits:
Object
  • Object
show all
Defined in:
app/models/invite_redeemer.rb

Overview

NOTE: There are a lot of complicated rules and conditions for our invite system, and the code is spread out through a lot of places. Tread lightly and read carefully when modifying this code. You may also want to look at:

  • InvitesController

  • SessionController

  • Invite model

  • User model

Invites that are scoped to a specific email (email IS NOT NULL on the Invite model) have different rules to invites that are considered an “invite link”, (email IS NULL) on the Invite model.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(invite:, email: nil, username: nil, name: nil, password: nil, user_custom_fields: nil, ip_address: nil, session: nil, email_token: nil, redeeming_user: nil) ⇒ InviteRedeemer

Returns a new instance of InviteRedeemer.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'app/models/invite_redeemer.rb', line 28

def initialize(
  invite:,
  email: nil,
  username: nil,
  name: nil,
  password: nil,
  user_custom_fields: nil,
  ip_address: nil,
  session: nil,
  email_token: nil,
  redeeming_user: nil
)
  @invite = invite
  @username = username
  @name = name
  @password = password
  @user_custom_fields = user_custom_fields
  @ip_address = ip_address
  @session = session
  @email_token = email_token
  @redeeming_user = redeeming_user

  ensure_email_is_present!(email)
end

Instance Attribute Details

#emailObject (readonly)

Returns the value of attribute email.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def email
  @email
end

#email_tokenObject (readonly)

Returns the value of attribute email_token.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def email_token
  @email_token
end

#inviteObject (readonly)

Returns the value of attribute invite.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def invite
  @invite
end

#ip_addressObject (readonly)

Returns the value of attribute ip_address.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def ip_address
  @ip_address
end

#nameObject (readonly)

Returns the value of attribute name.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def name
  @name
end

#passwordObject (readonly)

Returns the value of attribute password.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def password
  @password
end

#redeeming_userObject (readonly)

Returns the value of attribute redeeming_user.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def redeeming_user
  @redeeming_user
end

#sessionObject (readonly)

Returns the value of attribute session.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def session
  @session
end

#user_custom_fieldsObject (readonly)

Returns the value of attribute user_custom_fields.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def user_custom_fields
  @user_custom_fields
end

#usernameObject (readonly)

Returns the value of attribute username.



17
18
19
# File 'app/models/invite_redeemer.rb', line 17

def username
  @username
end

Class Method Details

.create_user_from_invite(email:, invite:, username: nil, name: nil, password: nil, user_custom_fields: nil, ip_address: nil, session: nil, email_token: nil) ⇒ Object

This will never be called if there is a redeeming_user being passed in to InviteRedeemer – see invited_user below.



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
155
156
157
158
159
160
161
162
163
164
# File 'app/models/invite_redeemer.rb', line 85

def self.create_user_from_invite(
  email:,
  invite:,
  username: nil,
  name: nil,
  password: nil,
  user_custom_fields: nil,
  ip_address: nil,
  session: nil,
  email_token: nil
)
  if username && UsernameValidator.new(username).valid_format? &&
       User.username_available?(username, email)
    available_username = username
  else
    available_username = UserNameSuggester.suggest(email)
  end

  user = User.where(staged: true).with_email(email.strip.downcase).first
  user.unstage! if user
  user ||= User.new

  user.attributes = {
    email: email,
    username: available_username,
    name: name || available_username,
    active: false,
    trust_level: SiteSetting.default_invitee_trust_level,
    ip_address: ip_address,
    registration_ip_address: ip_address,
  }

  if (!SiteSetting.must_approve_users && SiteSetting.invite_only) ||
       (SiteSetting.must_approve_users? && EmailValidator.can_auto_approve_user?(user.email))
    ReviewableUser.set_approved_fields!(user, Discourse.system_user)
  end

  user_fields = UserField.all
  if user_custom_fields.present? && user_fields.present?
    field_params = user_custom_fields || {}
    fields = user.custom_fields

    user_fields.each do |f|
      field_val = field_params[f.id.to_s]
      fields["#{User::USER_FIELD_PREFIX}#{f.id}"] = field_val[
        0...UserField.max_length
      ] unless field_val.blank?
    end
    user.custom_fields = fields
  end

  user.moderator = true if invite.moderator? && invite.invited_by.staff?

  if password
    user.password = password
    user.password_required!
  end

  authenticator = UserAuthenticator.new(user, session, require_password: false)

  if !authenticator.has_authenticator? && !SiteSetting.enable_local_logins
    raise ActiveRecord::RecordNotSaved.new(I18n.t("login.incorrect_username_email_or_password"))
  end

  authenticator.start

  if authenticator.email_valid? && !authenticator.authenticated?
    raise ActiveRecord::RecordNotSaved.new(I18n.t("login.incorrect_username_email_or_password"))
  end

  user.save!
  authenticator.finish

  if invite.emailed_status != Invite.emailed_status_types[:not_required] &&
       email == invite.email && invite.email_token.present? && email_token == invite.email_token
    user.activate
  end

  User.find(user.id)
end

Instance Method Details

#ensure_email_is_present!(email) ⇒ Object

The email must be present in some form since many of the methods for processing + redemption rely on it. If it’s still nil after these checks then we have hit an edge case and should not proceed!



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'app/models/invite_redeemer.rb', line 65

def ensure_email_is_present!(email)
  if email.blank?
    Rails.logger.warn(
      "email param was blank in InviteRedeemer for invite ID #{@invite.id}. The `redeeming_user` was #{@redeeming_user.present? ? "(ID: #{@redeeming_user.id})" : "not"} present.",
    )
  end

  if email.blank? && @invite.is_email_invite?
    @email = @invite.email
  elsif @redeeming_user.present?
    @email = @redeeming_user.email
  else
    @email = email
  end

  raise Discourse::InvalidParameters if @email.blank?
end

#redeemObject



53
54
55
56
57
58
59
60
# File 'app/models/invite_redeemer.rb', line 53

def redeem
  Invite.transaction do
    if can_redeem_invite? && mark_invite_redeemed
      process_invitation
      invited_user
    end
  end
end