# Check the arguments are sane
raise OSM::APIBadUserInput, "No id was given" unless params[:id]
raise OSM::APIBadUserInput, "No text was given" if params[:text].blank?
- raise OSM::APIRateLimitExceeded if current_user.changeset_comments.where("created_at >= ?", Time.now.utc - 1.hour).count >= current_user.max_changeset_comments_per_hour
+ raise OSM::APIRateLimitExceeded if rate_limit_exceeded?
# Extract the arguments
id = params[:id].to_i
format.json
end
end
+
+ private
+
+ ##
+ # Check if the current user has exceed the rate limit for comments
+ def rate_limit_exceeded?
+ recent_comments = current_user.changeset_comments.where("created_at >= ?", Time.now.utc - 1.hour).count
+
+ recent_comments >= current_user.max_changeset_comments_per_hour
+ end
end
end
raise OSM::APINotFoundError if current_user.nil? || current_user != u
end
- changesets.where(:user_id => u.id)
+ changesets.where(:user => u)
end
end
end
# Find the comments we want to return
- @comments = NoteComment.where(:note_id => notes).order("created_at DESC").limit(result_limit).preload(:note)
+ @comments = NoteComment.where(:note => notes).order("created_at DESC").limit(result_limit).preload(:note)
# Render the result
respond_to do |format|
if @params[:display_name]
changesets = if user.data_public? || user == current_user
- changesets.where(:user_id => user.id)
+ changesets.where(:user => user)
else
changesets.where("false")
end
elsif @params[:bbox]
changesets = conditions_bbox(changesets, BoundingBox.from_bbox_params(params))
elsif @params[:friends] && current_user
- changesets = changesets.where(:user_id => current_user.friends.identifiable)
+ changesets = changesets.where(:user => current_user.friends.identifiable)
elsif @params[:nearby] && current_user
- changesets = changesets.where(:user_id => current_user.nearby)
+ changesets = changesets.where(:user => current_user.nearby)
end
changesets = changesets.where("changesets.id <= ?", @params[:max_id]) if @params[:max_id]
elsif params[:friends]
if current_user
@title = t ".title_friends"
- entries = DiaryEntry.where(:user_id => current_user.friends)
+ entries = DiaryEntry.where(:user => current_user.friends)
else
require_user
return
elsif params[:nearby]
if current_user
@title = t ".title_nearby"
- entries = DiaryEntry.where(:user_id => current_user.nearby)
+ entries = DiaryEntry.where(:user => current_user.nearby)
else
require_user
return
if params[:search_by_user].present?
@find_user = User.find_by(:display_name => params[:search_by_user])
if @find_user
- @issues = @issues.where(:reported_user_id => @find_user.id)
+ @issues = @issues.where(:reported_user => @find_user)
else
@issues = @issues.none
flash.now[:warning] = t(".user_not_found")
# Destroy the message.
def destroy
- @message = Message.where("to_user_id = ? OR from_user_id = ?", current_user.id, current_user.id).find(params[:id])
+ @message = Message.where(:recipient => current_user).or(Message.where(:sender => current_user.id)).find(params[:id])
@message.from_user_visible = false if @message.sender == current_user
@message.to_user_visible = false if @message.recipient == current_user
if @message.save && !request.xhr?
# Set the message as being read or unread.
def mark
- @message = Message.where("to_user_id = ? OR from_user_id = ?", current_user.id, current_user.id).find(params[:message_id])
+ @message = Message.where(:recipient => current_user).or(Message.where(:sender => current_user)).find(params[:message_id])
if params[:mark] == "unread"
message_read = false
notice = t ".as_unread"
if current_user == @user && @role == "administrator"
flash[:error] = t("user_role.filter.not_revoke_admin_current_user")
else
- UserRole.where(:user_id => @user.id, :role => @role).delete_all
+ UserRole.where(:user => @user, :role => @role).delete_all
end
redirect_to user_path(@user)
end
save!
tags = self.tags
- ChangesetTag.where(:changeset_id => id).delete_all
+ ChangesetTag.where(:changeset => id).delete_all
tags.each do |k, v|
tag = ChangesetTag.new
first = true
# If there are any existing points for this trace then delete them
- Tracepoint.where(:gpx_id => id).delete_all
+ Tracepoint.where(:trace => id).delete_all
gpx.points.each_slice(1_000) do |points|
# Gather the trace points together for a bulk import
end
if gpx.actual_points.positive?
- max_lat = Tracepoint.where(:gpx_id => id).maximum(:latitude)
- min_lat = Tracepoint.where(:gpx_id => id).minimum(:latitude)
- max_lon = Tracepoint.where(:gpx_id => id).maximum(:longitude)
- min_lon = Tracepoint.where(:gpx_id => id).minimum(:longitude)
+ max_lat = Tracepoint.where(:trace => id).maximum(:latitude)
+ min_lat = Tracepoint.where(:trace => id).minimum(:latitude)
+ max_lon = Tracepoint.where(:trace => id).maximum(:longitude)
+ min_lon = Tracepoint.where(:trace => id).minimum(:longitude)
max_lat = max_lat.to_f / 10000000
min_lat = min_lat.to_f / 10000000
def max_changeset_comments_per_hour
if moderator?
- 36000
+ Settings.moderator_changeset_comments_per_hour
else
previous_comments = changeset_comments.limit(200).count
active_reports = issues.with_status(:open).sum(:reports_count)
max_comments = previous_comments / 200.0 * Settings.max_changeset_comments_per_hour
- max_comments = max_comments.floor.clamp(Settings.min_changeset_comments_per_hour, Settings.max_changeset_comments_per_hour)
+ max_comments = max_comments.floor.clamp(Settings.initial_changeset_comments_per_hour, Settings.max_changeset_comments_per_hour)
max_comments /= 2**active_reports
- max_comments.floor.clamp(1, Settings.max_changeset_comments_per_hour)
+ max_comments.floor.clamp(Settings.min_changeset_comments_per_hour, Settings.max_changeset_comments_per_hour)
end
end
openid_options = { :name => "openid", :store => openid_store }
google_options = { :name => "google", :scope => "email", :access_type => "online" }
-facebook_options = { :name => "facebook", :scope => "email", :client_options => { :site => "https://graph.facebook.com/v4.0", :authorize_url => "https://www.facebook.com/v4.0/dialog/oauth" } }
+facebook_options = { :name => "facebook", :scope => "email", :client_options => { :site => "https://graph.facebook.com/v17.0", :authorize_url => "https://www.facebook.com/v17.0/dialog/oauth" } }
microsoft_options = { :name => "microsoft", :scope => "openid User.Read" }
github_options = { :name => "github", :scope => "user:email" }
wikipedia_options = { :name => "wikipedia", :client_options => { :site => "https://meta.wikimedia.org" } }
# Rate limit for friending
max_friends_per_hour: 60
# Rate limit for changeset comments
-min_changeset_comments_per_hour: 6
+min_changeset_comments_per_hour: 1
+initial_changeset_comments_per_hour: 6
max_changeset_comments_per_hour: 60
+moderator_changeset_comments_per_hour: 36000
# Domain for handling message replies
#messages_domain: "messages.openstreetmap.org"
# MaxMind GeoIPv2 database
trace_file_storage: "test"
trace_image_storage: "test"
trace_icon_storage: "test"
+# Lower some rate limits for testing
+max_changeset_comments_per_hour: 30
+moderator_changeset_comments_per_hour: 60
end
##
- # create comment rate limit
- def test_create_comment_rate_limit
+ # create comment rate limit for new users
+ def test_create_comment_new_user_rate_limit
changeset = create(:changeset, :closed)
user = create(:user)
auth_header = basic_authorization_header user.email, "test"
- assert_difference "ChangesetComment.count", Settings.min_changeset_comments_per_hour do
- 1.upto(Settings.min_changeset_comments_per_hour) do |count|
+ assert_difference "ChangesetComment.count", Settings.initial_changeset_comments_per_hour do
+ 1.upto(Settings.initial_changeset_comments_per_hour) do |count|
+ post changeset_comment_path(:id => changeset, :text => "Comment #{count}"), :headers => auth_header
+ assert_response :success
+ end
+ end
+
+ assert_no_difference "ChangesetComment.count" do
+ post changeset_comment_path(:id => changeset, :text => "One comment too many"), :headers => auth_header
+ assert_response :too_many_requests
+ end
+ end
+
+ ##
+ # create comment rate limit for experienced users
+ def test_create_comment_experienced_user_rate_limit
+ changeset = create(:changeset, :closed)
+ user = create(:user)
+ create_list(:changeset_comment, 200, :author_id => user.id, :created_at => Time.now.utc - 1.day)
+
+ auth_header = basic_authorization_header user.email, "test"
+
+ assert_difference "ChangesetComment.count", Settings.max_changeset_comments_per_hour do
+ 1.upto(Settings.max_changeset_comments_per_hour) do |count|
+ post changeset_comment_path(:id => changeset, :text => "Comment #{count}"), :headers => auth_header
+ assert_response :success
+ end
+ end
+
+ assert_no_difference "ChangesetComment.count" do
+ post changeset_comment_path(:id => changeset, :text => "One comment too many"), :headers => auth_header
+ assert_response :too_many_requests
+ end
+ end
+
+ ##
+ # create comment rate limit for reported users
+ def test_create_comment_reported_user_rate_limit
+ changeset = create(:changeset, :closed)
+ user = create(:user)
+ create(:issue_with_reports, :reportable => user, :reported_user => user)
+
+ auth_header = basic_authorization_header user.email, "test"
+
+ assert_difference "ChangesetComment.count", Settings.initial_changeset_comments_per_hour / 2 do
+ 1.upto(Settings.initial_changeset_comments_per_hour / 2) do |count|
+ post changeset_comment_path(:id => changeset, :text => "Comment #{count}"), :headers => auth_header
+ assert_response :success
+ end
+ end
+
+ assert_no_difference "ChangesetComment.count" do
+ post changeset_comment_path(:id => changeset, :text => "One comment too many"), :headers => auth_header
+ assert_response :too_many_requests
+ end
+ end
+
+ ##
+ # create comment rate limit for moderator users
+ def test_create_comment_moderator_user_rate_limit
+ changeset = create(:changeset, :closed)
+ user = create(:moderator_user)
+
+ auth_header = basic_authorization_header user.email, "test"
+
+ assert_difference "ChangesetComment.count", Settings.moderator_changeset_comments_per_hour do
+ 1.upto(Settings.moderator_changeset_comments_per_hour) do |count|
post changeset_comment_path(:id => changeset, :text => "Comment #{count}"), :headers => auth_header
assert_response :success
end
assert_response :success
assert_template :new
- assert_nil UserPreference.where(:user_id => user.id, :k => "diary.default_language").first
+ assert_nil UserPreference.where(:user => user, :k => "diary.default_language").first
end
def test_create
# checks if user was subscribed
assert_equal 1, entry.subscribers.length
- assert_equal "en", UserPreference.where(:user_id => user.id, :k => "diary.default_language").first.v
+ assert_equal "en", UserPreference.where(:user => user, :k => "diary.default_language").first.v
end
def test_create_german
# checks if user was subscribed
assert_equal 1, entry.subscribers.length
- assert_equal "de", UserPreference.where(:user_id => user.id, :k => "diary.default_language").first.v
+ assert_equal "de", UserPreference.where(:user => user, :k => "diary.default_language").first.v
end
def test_new_spammy
# Default to assigning to an administrator
assigned_role { "administrator" }
+
+ # Optionally create some reports for this issue
+ factory :issue_with_reports do
+ transient do
+ reports_count { 1 }
+ end
+
+ after(:create) do |issue, evaluator|
+ create_list(:report, evaluator.reports_count, :issue => issue)
+ end
+ end
end
end
def test_import_creates_tracepoints
trace = create(:trace, :fixture => "a")
- assert_equal 0, Tracepoint.where(:gpx_id => trace.id).count
+ assert_equal 0, Tracepoint.where(:trace => trace).count
trace.import
trace.reload
- assert_equal 1, Tracepoint.where(:gpx_id => trace.id).count
+ assert_equal 1, Tracepoint.where(:trace => trace).count
# Check that the tile has been set prior to the bulk import
# i.e. that the callbacks have been run correctly
- assert_equal 3221331576, Tracepoint.where(:gpx_id => trace.id).first.tile
+ assert_equal 3221331576, Tracepoint.where(:trace => trace).first.tile
end
def test_import_creates_icon