+
+ def description
+ RichText.new(read_attribute(:description_format), read_attribute(:description))
+ end
+
+ def languages
+ attribute_present?(:languages) ? read_attribute(:languages).split(/ *, */) : []
+ end
+
+ def languages=(languages)
+ write_attribute(:languages, languages.join(","))
+ end
+
+ def preferred_language
+ languages.find { |l| Language.exists?(:code => l) }
+ end
+
+ def preferred_language_from(array)
+ (languages & array.collect { |i| i.to_s }).first
+ end
+
+ def nearby(radius = NEARBY_RADIUS, num = NEARBY_USERS)
+ if self.home_lon and self.home_lat
+ gc = OSM::GreatCircle.new(self.home_lat, self.home_lon)
+ bounds = gc.bounds(radius)
+ 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)
+ else
+ nearby = []
+ end
+ return nearby
+ end
+
+ def distance(nearby_user)
+ return OSM::GreatCircle.new(self.home_lat, self.home_lon).distance(nearby_user.home_lat, nearby_user.home_lon)
+ end
+
+ def is_friends_with?(new_friend)
+ self.friends.where(:friend_user_id => new_friend.id).exists?
+ end
+
+ ##
+ # returns true if a user is visible
+ def visible?
+ ["pending","active","confirmed"].include? self.status
+ end
+
+ ##
+ # returns true if a user is active
+ def active?
+ ["active","confirmed"].include? self.status
+ end
+
+ ##
+ # returns true if the user has the moderator role, false otherwise
+ def moderator?
+ has_role? 'moderator'
+ end
+
+ ##
+ # returns true if the user has the administrator role, false otherwise
+ def administrator?
+ has_role? 'administrator'
+ end
+
+ ##
+ # returns true if the user has the requested role
+ def has_role?(role)
+ roles.any? { |r| r.role == role }
+ end
+
+ ##
+ # returns the first active block which would require users to view
+ # a message, or nil if there are none.
+ def blocked_on_view
+ blocks.active.detect { |b| b.needs_view? }
+ end
+
+ ##
+ # delete a user - leave the account but purge most personal data
+ def delete
+ self.display_name = "user_#{self.id}"
+ self.description = ""
+ self.home_lat = nil
+ self.home_lon = nil
+ self.image = nil
+ self.email_valid = false
+ self.new_email = nil
+ self.openid_url = nil
+ self.status = "deleted"
+ self.save
+ end
+
+ ##
+ # return a spam score for a user
+ def spam_score
+ changeset_score = self.changesets.size * 50
+ trace_score = self.traces.size * 50
+ diary_entry_score = self.diary_entries.inject(0) { |s,e| s += e.body.spam_score }
+ diary_comment_score = self.diary_comments.inject(0) { |s,c| s += c.body.spam_score }
+
+ score = self.description.spam_score / 4.0
+ score += diary_entry_score / self.diary_entries.length if self.diary_entries.length > 0
+ score += diary_comment_score / self.diary_comments.length if self.diary_comments.length > 0
+ score -= changeset_score
+ score -= trace_score
+
+ return score.to_i
+ end
+
+ ##
+ # perform a spam check on a user
+ def spam_check
+ if status == "active" and spam_score > SPAM_THRESHOLD
+ update_column(:status, "suspended")
+ end
+ end
+
+ ##
+ # return an oauth access token for a specified application
+ def access_token(application_key)
+ return ClientApplication.find_by_key(application_key).access_token_for_user(self)
+ end
+
+private
+
+ def set_defaults
+ self.creation_time = Time.now.getutc unless self.attribute_present?(:creation_time)
+ self.description_format = "markdown" unless self.attribute_present?(:description_format)
+ end
+
+ def encrypt_password
+ if pass_crypt_confirmation
+ self.pass_salt = OSM::make_token(8)
+ self.pass_crypt = OSM::encrypt_password(pass_crypt, pass_salt)
+ self.pass_crypt_confirmation = nil
+ end
+ end