- Changeset.transaction do
- while p.read == 1
- break if p.node_type == 15 # end element
- next unless p.node_type == 1 # element
-
- case p.name
- when 'create':
- while p.read == 1
- break if p.node_type == 15 # end element
- next unless p.node_type == 1 # element
-
- model = models[p.name]
- next if model.nil?
-
- elem = XML::Node.new p.name
- nd = p.expand; p.next
- osm = model.from_xml_node(nd, true)
- elem['old_id'] = nd['id']
-
- case nd.name
- when 'way':
- fix_way(osm, node_ids)
- raise OSM::APIPreconditionFailedError.new if !osm.preconditions_ok?
- when 'relation':
- fix_rel(osm, ids)
- raise OSM::APIPreconditionFailedError.new if !osm.preconditions_ok?
- end
-
- create_prim ids[nd.name], osm, nd
- elem['new_id'] = osm.id.to_s
- elem['new_version'] = osm.version.to_s
- root << elem
- end
- when 'modify':
- while p.read == 1
- break if p.node_type == 15 # end element
- next unless p.node_type == 1 # element
-
- model = models[p.name]
- next if model.nil?
-
- elem = XML::Node.new p.name
- new_osm = model.from_xml_node(p.expand); p.next
- osm = model.find(new_osm.id)
- osm.update_from new_osm, @user
- elem['old_id'] = elem['new_id'] = osm.id.to_s
- elem['new_version'] = osm.version.to_s
- root << elem
- end
- when 'delete':
- while p.read == 1
- break if p.node_type == 15 # end element
- next unless p.node_type == 1 # element
-
- model = models[p.name]
- next if model.nil?
-
- elem = XML::Node.new p.name
- osm = model.find(p.expand['id']); p.next
- osm.delete_with_history(@user)
- elem['old_id'] = elem['new_id'] = osm.id.to_s
- elem['new_version'] = osm.version.to_s
- root << elem
- end
- end
+ ##
+ # list edits as an atom feed
+ def feed
+ list
+ end
+
+ ##
+ # 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