+ # Add a comment to a changeset
+ def comment
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+ raise OSM::APIBadUserInput.new("No text was given") if params[:text].blank?
+
+ # Extract the arguments
+ id = params[:id].to_i
+ body = params[:text]
+
+ # Find the changeset and check it is valid
+ changeset = Changeset.find(id)
+ raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open?
+
+ # Add a comment to the changeset
+ comment = changeset.comments.create(:changeset => changeset,
+ :body => body,
+ :author => @user)
+
+ # Notify current subscribers of the new comment
+ changeset.subscribers.visible.each do |user|
+ if @user != user
+ Notifier.changeset_comment_notification(comment, user).deliver_now
+ end
+ end
+
+ # Add the commenter to the subscribers if necessary
+ changeset.subscribers << @user unless changeset.subscribers.exists?(@user.id)
+
+ # Return a copy of the updated changeset
+ render :text => changeset.to_xml.to_s, :content_type => "text/xml"
+ end
+
+ ##
+ # Adds a subscriber to the changeset
+ def subscribe
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+ # Extract the arguments
+ id = params[:id].to_i
+
+ # Find the changeset and check it is valid
+ changeset = Changeset.find(id)
+ raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open?
+ raise OSM::APIChangesetAlreadySubscribedError.new(changeset) if changeset.subscribers.exists?(@user.id)
+
+ # Add the subscriber
+ changeset.subscribers << @user
+
+ # Return a copy of the updated changeset
+ render :text => changeset.to_xml.to_s, :content_type => "text/xml"
+ end
+
+ ##
+ # Removes a subscriber from the changeset
+ def unsubscribe
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+ # Extract the arguments
+ id = params[:id].to_i
+
+ # Find the changeset and check it is valid
+ changeset = Changeset.find(id)
+ raise OSM::APIChangesetNotYetClosedError.new(changeset) if changeset.is_open?
+ raise OSM::APIChangesetNotSubscribedError.new(changeset) unless changeset.subscribers.exists?(@user.id)
+
+ # Remove the subscriber
+ changeset.subscribers.delete(@user)
+
+ # Return a copy of the updated changeset
+ render :text => changeset.to_xml.to_s, :content_type => "text/xml"
+ end
+
+ ##
+ # Sets visible flag on comment to false
+ def hide_comment
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+ # Extract the arguments
+ id = params[:id].to_i
+
+ # Find the changeset
+ comment = ChangesetComment.find(id)
+
+ # Hide the comment
+ comment.update(:visible => false)
+
+ # Return a copy of the updated changeset
+ render :text => comment.changeset.to_xml.to_s, :content_type => "text/xml"
+ end
+
+ ##
+ # Sets visible flag on comment to true
+ def unhide_comment
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput.new("No id was given") unless params[:id]
+
+ # Extract the arguments
+ id = params[:id].to_i
+
+ # Find the changeset
+ comment = ChangesetComment.find(id)
+
+ # Unhide the comment
+ comment.update(:visible => true)
+
+ # Return a copy of the updated changeset
+ render :text => comment.changeset.to_xml.to_s, :content_type => "text/xml"
+ end
+
+ ##
+ # Get a feed of recent changeset comments
+ def comments_feed
+ if params[:id]
+ # Extract the arguments
+ id = params[:id].to_i
+
+ # Find the changeset
+ changeset = Changeset.find(id)
+
+ # Return comments for this changeset only
+ @comments = changeset.comments.includes(:author, :changeset).limit(comments_limit)
+ else
+ # Return comments
+ @comments = ChangesetComment.includes(:author, :changeset).where(:visible => :true).order("created_at DESC").limit(comments_limit).preload(:changeset)
+ end
+
+ # Render the result
+ respond_to do |format|
+ format.rss
+ end
+ rescue OSM::APIBadUserInput
+ render :text => "", :status => :bad_request
+ end
+
+ private
+
+ #------------------------------------------------------------
+ # utility functions below.
+ #------------------------------------------------------------
+
+ ##
+ # if a bounding box was specified do some sanity checks.
+ # restrict changesets to those enclosed by a bounding box
+ # we need to return both the changesets and the bounding box
+ def conditions_bbox(changesets, bbox)
+ if bbox
+ bbox.check_boundaries
+ bbox = bbox.to_scaled
+
+ changesets.where("min_lon < ? and max_lon > ? and min_lat < ? and max_lat > ?",
+ bbox.max_lon.to_i, bbox.min_lon.to_i,
+ bbox.max_lat.to_i, bbox.min_lat.to_i)