X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/15b104f4ff4614aa78c01180b6a9b89dd5a1400f..c3254b7e93a1f276759faf2b825479aa2a006032:/app/models/user.rb?ds=sidebyside diff --git a/app/models/user.rb b/app/models/user.rb index 7a8414ec0..b3325e4eb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -33,6 +33,7 @@ # image_use_gravatar :boolean default(FALSE), not null # image_content_type :string # auth_provider :string +# home_tile :integer # # Indexes # @@ -41,6 +42,7 @@ # users_display_name_lower_idx (lower((display_name)::text)) # users_email_idx (email) UNIQUE # users_email_lower_idx (lower((email)::text)) +# users_home_idx (home_tile) # class User < ActiveRecord::Base @@ -73,6 +75,11 @@ class User < ActiveRecord::Base has_many :roles, :class_name => "UserRole" + has_many :issues, :class_name => "Issue", :foreign_key => :reported_user_id + has_many :issue_comments + + has_many :reports + scope :visible, -> { where(:status => %w[pending active confirmed]) } scope :active, -> { where(:status => %w[active confirmed]) } scope :identifiable, -> { where(:data_public => true) } @@ -81,21 +88,27 @@ class User < ActiveRecord::Base :default_url => "/assets/:class/:attachment/:style.png", :styles => { :large => "100x100>", :small => "50x50>" } + INVALID_CHARS = "/;.,?%#" + validates :display_name, :presence => true, :allow_nil => true, :length => 3..255, :exclusion => %w[new terms save confirm confirm-email go_public reset-password forgot-password suspended] validates :display_name, :if => proc { |u| u.display_name_changed? }, :uniqueness => { :case_sensitive => false } validates :display_name, :if => proc { |u| u.display_name_changed? }, - :format => { :with => %r{\A[^\x00-\x1f\x7f\ufffe\uffff/;.,?%#]*\z} } + :format => { :with => %r{\A[^\x00-\x1f\x7f\ufffe\uffff]*\z} } validates :display_name, :if => proc { |u| u.display_name_changed? }, - :format => { :with => /\A\S/, :message => "has leading whitespace" } + :format => { :with => %r{\A[^#{INVALID_CHARS}]*\z}, + :message => I18n.t("users.account.invalid chars", invalid_chars: INVALID_CHARS) } validates :display_name, :if => proc { |u| u.display_name_changed? }, - :format => { :with => /\S\z/, :message => "has trailing whitespace" } + :format => { :with => /\A\S/, :message => I18n.t("users.account.leading whitespace") } + validates :display_name, :if => proc { |u| u.display_name_changed? }, + :format => { :with => /\S\z/, :message => I18n.t("users.account.trailing whitespace") } validates :email, :presence => true, :confirmation => true validates :email, :if => proc { |u| u.email_changed? }, :uniqueness => { :case_sensitive => false } validates :pass_crypt, :confirmation => true, :length => 8..255 - validates :home_lat, :home_lon, :allow_nil => true, :numericality => true + validates :home_lat, :allow_nil => true, :numericality => true, :inclusion => { :in => -90..90 } + validates :home_lon, :allow_nil => true, :numericality => true, :inclusion => { :in => -180..180 } validates :home_zoom, :allow_nil => true, :numericality => { :only_integer => true } validates :preferred_editor, :inclusion => Editors::ALL_EDITORS, :allow_nil => true validates :image, :attachment_content_type => { :content_type => %r{\Aimage/.*\Z} } @@ -107,7 +120,13 @@ class User < ActiveRecord::Base after_initialize :set_defaults before_save :encrypt_password + before_save :update_tile after_save :spam_check + after_save :reset_preferred_languages + + def to_param + display_name + end def self.authenticate(options) if options[:username] && options[:password] @@ -181,14 +200,24 @@ class User < ActiveRecord::Base end def preferred_languages - @locales ||= Locale.list(languages) + @preferred_languages ||= Locale.list(languages) + end + + def reset_preferred_languages + @preferred_languages = nil end def nearby(radius = NEARBY_RADIUS, num = NEARBY_USERS) if home_lon && home_lat gc = OSM::GreatCircle.new(home_lat, home_lon) + sql_for_area = QuadTile.sql_for_area(gc.bounds(radius), "home_") sql_for_distance = gc.sql_for_distance("home_lat", "home_lon") - nearby = User.where("id != ? AND status IN (\'active\', \'confirmed\') AND data_public = ? AND #{sql_for_distance} <= ?", id, true, radius).order(sql_for_distance).limit(num) + nearby = User.active.identifiable + .where("id != ?", id) + .where(sql_for_area) + .where("#{sql_for_distance} <= ?", radius) + .order(Arel.sql(sql_for_distance)) + .limit(num) else nearby = [] end @@ -261,8 +290,8 @@ class User < ActiveRecord::Base def spam_score changeset_score = changesets.size * 50 trace_score = traces.size * 50 - diary_entry_score = diary_entries.inject(0) { |acc, elem| acc + elem.body.spam_score } - diary_comment_score = diary_comments.inject(0) { |acc, elem| acc + elem.body.spam_score } + diary_entry_score = diary_entries.visible.inject(0) { |acc, elem| acc + elem.body.spam_score } + diary_comment_score = diary_comments.visible.inject(0) { |acc, elem| acc + elem.body.spam_score } score = description.spam_score / 4.0 score += diary_entries.where("created_at > ?", 1.day.ago).count * 10 @@ -277,9 +306,7 @@ class User < ActiveRecord::Base ## # perform a spam check on a user def spam_check - if status == "active" && spam_score > SPAM_THRESHOLD - update(:status => "suspended") - end + update(:status => "suspended") if status == "active" && spam_score > SPAM_THRESHOLD end ## @@ -300,4 +327,8 @@ class User < ActiveRecord::Base self.pass_crypt_confirmation = nil end end + + def update_tile + self.home_tile = QuadTile.tile_for_point(home_lat, home_lon) if home_lat && home_lon + end end