diff --git a/app/logical/user_name_validator.rb b/app/logical/user_name_validator.rb new file mode 100644 index 000000000..c86c693db --- /dev/null +++ b/app/logical/user_name_validator.rb @@ -0,0 +1,10 @@ +class UserNameValidator < ActiveModel::EachValidator + def validate_each(rec, attr, value) + name = User.normalize_name(value) + + rec.errors[attr] << "already exists" if User.find_by_name(name).present? + rec.errors[attr] << "must be 2 to 100 characters long" if !name.length.between?(2, 100) + rec.errors[attr] << "cannot have whitespace or colons" if name =~ /[[:space:]]|:/ + rec.errors[attr] << "cannot begin or end with an underscore" if name =~ /\A_|_\z/ + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 73a29581d..6c0ac9129 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -54,10 +54,8 @@ class User < ActiveRecord::Base attr_accessor :password, :old_password attr_accessible :dmail_filter_attributes, :enable_privacy_mode, :enable_post_navigation, :new_post_navigation_layout, :password, :old_password, :password_confirmation, :password_hash, :email, :last_logged_in_at, :last_forum_read_at, :has_mail, :receive_email_notifications, :comment_threshold, :always_resize_images, :favorite_tags, :blacklisted_tags, :name, :ip_addr, :time_zone, :default_image_size, :enable_sequential_post_navigation, :per_page, :hide_deleted_posts, :style_usernames, :enable_auto_complete, :custom_style, :show_deleted_children, :disable_categorized_saved_searches, :disable_tagged_filenames, :enable_recent_searches, :as => [:moderator, :janitor, :gold, :platinum, :member, :anonymous, :default, :builder, :admin] attr_accessible :level, :as => :admin - validates_length_of :name, :within => 2..100, :on => :create - validates_format_of :name, :with => /\A[^\s:]+\Z/, :on => :create, :message => "cannot have whitespace or colons" - validates_format_of :name, :with => /\A[^_].*[^_]\Z/, :on => :create, :message => "cannot begin or end with an underscore" - validates_uniqueness_of :name, :case_sensitive => false + + validates :name, user_name: true, on: :create validates_uniqueness_of :email, :case_sensitive => false, :if => lambda {|rec| rec.email.present? && rec.email_changed? } validates_length_of :password, :minimum => 5, :if => lambda {|rec| rec.new_record? || rec.password.present?} validates_inclusion_of :default_image_size, :in => %w(large original) @@ -153,6 +151,10 @@ class User < ActiveRecord::Base def id_to_pretty_name(user_id) id_to_name(user_id).gsub(/([^_])_+(?=[^_])/, "\\1 \\2") end + + def normalize_name(name) + name.to_s.mb_chars.downcase.strip.tr(" ", "_").to_s + end end def pretty_name diff --git a/app/models/user_name_change_request.rb b/app/models/user_name_change_request.rb index eaf8cd372..b7de494f9 100644 --- a/app/models/user_name_change_request.rb +++ b/app/models/user_name_change_request.rb @@ -3,11 +3,8 @@ class UserNameChangeRequest < ActiveRecord::Base validates_inclusion_of :status, :in => %w(pending approved rejected) belongs_to :user belongs_to :approver, :class_name => "User" - validate :uniqueness_of_desired_name validate :not_limited, :on => :create - validates_length_of :desired_name, :within => 2..100, :on => :create - validates_format_of :desired_name, :with => /\A[^\s:]+\Z/, :on => :create, :message => "cannot have whitespace or colons" - before_validation :normalize_name + validates :desired_name, user_name: true attr_accessible :status, :user_id, :original_name, :desired_name, :change_reason, :rejection_reason, :approver_id def self.pending @@ -40,8 +37,8 @@ class UserNameChangeRequest < ActiveRecord::Base status == "pending" end - def normalize_name - self.desired_name = desired_name.strip.gsub(/ /, "_") + def desired_name=(name) + super(User.normalize_name(name)) end def feedback @@ -71,15 +68,6 @@ class UserNameChangeRequest < ActiveRecord::Base return true end end - - def uniqueness_of_desired_name - if User.find_by_name(desired_name) - errors.add(:desired_name, "already exists") - return false - else - return true - end - end def hidden_attributes if CurrentUser.is_admin? || user == CurrentUser.user diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index ffb505616..523ff75e8 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -187,6 +187,13 @@ class UserTest < ActiveSupport::TestCase assert_equal(Danbooru.config.default_guest_name, User.id_to_name(-1)) end + should "not contain whitespace" do + # U+2007: https://en.wikipedia.org/wiki/Figure_space + user = FactoryGirl.build(:user, :name => "foo\u2007bar") + user.save + assert_equal(["Name cannot have whitespace or colons"], user.errors.full_messages) + end + should "not contain a colon" do user = FactoryGirl.build(:user, :name => "a:b") user.save