+ 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)
+ else
+ changesets
+ end
+ end
+
+ ##
+ # restrict changesets to those by a particular user
+ def conditions_user(changesets, user, name)
+ if user.nil? && name.nil?
+ changesets
+ else
+ # shouldn't provide both name and UID
+ raise OSM::APIBadUserInput.new("provide either the user ID or display name, but not both") if user && name
+
+ # use either the name or the UID to find the user which we're selecting on.
+ u = if name.nil?
+ # user input checking, we don't have any UIDs < 1
+ raise OSM::APIBadUserInput.new("invalid user ID") if user.to_i < 1
+ u = User.find(user.to_i)
+ else
+ u = User.find_by_display_name(name)
+ end
+
+ # make sure we found a user
+ raise OSM::APINotFoundError.new if u.nil?
+
+ # should be able to get changesets of public users only, or
+ # our own changesets regardless of public-ness.
+ unless u.data_public?
+ # get optional user auth stuff so that users can see their own
+ # changesets if they're non-public
+ setup_user_auth
+
+ raise OSM::APINotFoundError if @user.nil? || @user.id != u.id