Use completely random NeoPass usernames for now

Ahh, I had assumed the `uid` provided by NeoPass would be the user's
Neopets username, but in hindsight that was never gonna work out since
NeoPass doesn't think of things in terms of usernames at all!

For now, we create 100% random NeoPass usernames, of the form
"neopass-shoyru-5812" or similar. This will be an important fallback
anyway, because it's possible to have a NeoPass with *no* Neopets.com
account attached.

But hopefully we'll be able to work with TNT to request the user's main
Neopets account's username somehow, to use that as the default when
possible!
This commit is contained in:
Emi Matchu 2024-04-01 05:57:06 -07:00
parent b03d9b264a
commit 6618651fcb

View file

@ -41,14 +41,13 @@ class AuthUser < AuthRecord
end end
def self.from_omniauth(auth) def self.from_omniauth(auth)
raise MissingAuthInfoError, "Username missing" if auth.uid.blank?
raise MissingAuthInfoError, "Email missing" if auth.info.email.blank? raise MissingAuthInfoError, "Email missing" if auth.info.email.blank?
transaction do transaction do
find_or_create_by!(provider: auth.provider, uid: auth.uid) do |user| find_or_create_by!(provider: auth.provider, uid: auth.uid) do |user|
# Use the Neopets username if possible, or a unique username if not. # TODO: Can we somehow get the Neopets username if one exists, instead
dti_username = build_unique_username_like(auth.uid) # of just using total randomness?
user.name = dti_username user.name = build_unique_username
# Copy the email address from their Neopets account to their DTI # Copy the email address from their Neopets account to their DTI
# account, unless they already have a DTI account with this email, in # account, unless they already have a DTI account with this email, in
@ -60,25 +59,32 @@ class AuthUser < AuthRecord
end end
end end
def self.build_unique_username_like(name) def self.build_unique_username
name_query = sanitize_sql_like(name) + "%" # Start with a base name like "neopass-kougra-".
similar_names = where("name LIKE ?", name_query).pluck(:name) random_species_name = Species.all.pluck(:name).sample
base_name = "neopass-#{random_species_name}"
# Use the given name itself, if we can. # Fetch the list of names that already start with that.
return name unless similar_names.include?(name) name_query = sanitize_sql_like(base_name) + "%"
similar_names = where("name LIKE ?", name_query).pluck(:name).to_set
# If not, try appending "-neopass". # Shuffle the list of four-digit numbers to create 10000 possible names,
return "#{name}-neopass" unless similar_names.include?("#{name}-neopass") # then use the first one that's not already claimed.
potential_names = (0..9999).map { |n| "#{base_name}-#{n}" }.shuffle
name = potential_names.find { |name| !similar_names.include?(name) }
return name unless name.nil?
# After that, try appending "-neopass-1", "-neopass-2", etc, until a # If that failed, try again but with six digits.
# unique name arises. (We don't expect this to happen basically ever, but potential_names = (0..999999).map { |n| "#{base_name}-#{n}" }.shuffle
# it's nice to have a guarantee!) name = potential_names.find { |name| !similar_names.include?(name) }
max = similar_names.size + 1 return name unless name.nil?
candidates = (1..max).map { |n| "#{name}-neopass-#{n}"}
numerical_name = candidates.find { |name| !similar_names.include?(name) }
return numerical_name unless numerical_name.nil?
raise "Failed to build unique username (shouldn't be possible?)" # If *that* failed, then golly gee, we have millions of NeoPass users
# running around using the default username. Good for us, I guess?? If so,
# uhh, let's cross that bridge when we come to it. (At time of writing,
# there are about 60k total registered DTI users at *all*.)
raise "Failed to build unique username (all million+ names starting with " +
"\"#{base_name}\" are taken??)"
end end
class MissingAuthInfoError < ArgumentError;end class MissingAuthInfoError < ArgumentError;end