+ ##
+ # Add a comment to a changeset
+ def comment
+ # 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?
+
+ # 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, changeset if changeset.is_open?
+
+ # Add a comment to the changeset
+ comment = changeset.comments.create(:changeset => changeset,
+ :body => body,
+ :author => current_user)
+
+ # Notify current subscribers of the new comment
+ changeset.subscribers.visible.each do |user|
+ Notifier.changeset_comment_notification(comment, user).deliver_now if current_user != user
+ end
+
+ # Add the commenter to the subscribers if necessary
+ changeset.subscribers << current_user unless changeset.subscribers.exists?(current_user.id)
+
+ # Return a copy of the updated changeset
+ render :xml => changeset.to_xml.to_s
+ end
+
+ ##
+ # Adds a subscriber to the changeset
+ def subscribe
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput, "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::APIChangesetAlreadySubscribedError, changeset if changeset.subscribers.exists?(current_user.id)
+
+ # Add the subscriber
+ changeset.subscribers << current_user
+
+ # Return a copy of the updated changeset
+ render :xml => changeset.to_xml.to_s
+ end
+
+ ##
+ # Removes a subscriber from the changeset
+ def unsubscribe
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput, "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::APIChangesetNotSubscribedError, changeset unless changeset.subscribers.exists?(current_user.id)
+
+ # Remove the subscriber
+ changeset.subscribers.delete(current_user)
+
+ # Return a copy of the updated changeset
+ render :xml => changeset.to_xml.to_s
+ end
+
+ ##
+ # Sets visible flag on comment to false
+ def hide_comment
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput, "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 :xml => comment.changeset.to_xml.to_s
+ end
+
+ ##
+ # Sets visible flag on comment to true
+ def unhide_comment
+ # Check the arguments are sane
+ raise OSM::APIBadUserInput, "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 :xml => comment.changeset.to_xml.to_s
+ 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
+ head :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, "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, "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 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 current_user.nil? || current_user != u