Fixing review comments
authorMatt Amos <zerebubuth@gmail.com>
Wed, 28 Mar 2012 12:21:18 +0000 (13:21 +0100)
committerTom Hughes <tom@compton.nu>
Thu, 5 Apr 2012 12:46:40 +0000 (13:46 +0100)
Added scoping for unredacted items, cleaned up authorization and
railsified old_node_controller.

app/controllers/application_controller.rb
app/controllers/old_node_controller.rb
app/models/old_node.rb
config/routes.rb
lib/redactable.rb
test/functional/old_node_controller_test.rb

index 7ac9e6402bc64236d80aeac26f28e1a36554060e..7043d8206363d7f4978d3afa4a9d7f571e217ac6 100644 (file)
@@ -160,6 +160,18 @@ class ApplicationController < ActionController::Base
     end 
   end 
 
+  ##
+  # to be used as a before_filter *after* authorize. this checks that
+  # the user is a moderator and, if not, returns a forbidden error.
+  #
+  def authorize_moderator(errormessage="Access restricted to moderators") 
+    # check user is a moderator
+    unless @user.moderator?
+      render :text => errormessage, :status => :forbidden
+      return false
+    end 
+  end 
+
   def check_database_readable(need_api = false)
     if STATUS == :database_offline or (need_api and STATUS == :api_offline)
       redirect_to :controller => 'site', :action => 'offline'
index e6170fbda0258aad3c3f4b24bbc171693c58ed0f..1b5ec13a310002e0248f8d7c846495d972d42370 100644 (file)
@@ -2,59 +2,77 @@ class OldNodeController < ApplicationController
   require 'xml/libxml'
 
   skip_before_filter :verify_authenticity_token
+  before_filter :setup_user_auth, :only => [ :history, :version ]
   before_filter :authorize, :only => [ :redact ]
+  before_filter :authorize_moderator, :only => [ :redact ]
   before_filter :require_allow_write_api, :only => [ :redact ]
   before_filter :check_api_readable
   before_filter :check_api_writable, :only => [ :redact ]
+  before_filter :lookup_old_node, :except => [ :history ]
   after_filter :compress_output
   around_filter :api_call_handle_error, :api_call_timeout
 
   def history
-    # TODO - maybe a bit heavyweight to do this on every
-    # call, perhaps try lazy auth.
-    setup_user_auth
-
     node = Node.find(params[:id].to_i)
     
     doc = OSM::API.new.get_xml_doc
     
-    node.old_nodes.each do |old_node|
-      unless old_node.redacted? and (@user.nil? or not @user.moderator?)
-        doc.root << old_node.to_xml_node
-      end
+    visible_nodes = if @user and @user.moderator?
+                      node.old_nodes
+                    else
+                      node.old_nodes.unredacted
+                    end
+
+    visible_nodes.each do |old_node|
+      doc.root << old_node.to_xml_node
     end
     
     render :text => doc.to_s, :content_type => "text/xml"
   end
   
   def version
-    if old_node = OldNode.where(:node_id => params[:id], :version => params[:version]).first
-      # TODO - maybe a bit heavyweight to do this on every
-      # call, perhaps try lazy auth.
-      setup_user_auth
-      
-      if old_node.redacted? and (@user.nil? or not @user.moderator?)
-        render :nothing => true, :status => :forbidden
-      else
+    if @old_node.redacted? and (@user.nil? or not @user.moderator?)
+      render :nothing => true, :status => :forbidden
+    else
 
-        response.last_modified = old_node.timestamp
-        
-        doc = OSM::API.new.get_xml_doc
-        doc.root << old_node.to_xml_node
+      response.last_modified = @old_node.timestamp
+      
+      doc = OSM::API.new.get_xml_doc
+      doc.root << @old_node.to_xml_node
         
-        render :text => doc.to_s, :content_type => "text/xml"
-      end
-    else
-      render :nothing => true, :status => :not_found
+      render :text => doc.to_s, :content_type => "text/xml"
     end
   end
 
   def redact
-    if @user && @user.moderator?
-      render :nothing => true
-
+    redaction_id = params['redaction']
+    unless redaction_id.nil?
+      # if a redaction ID was specified, then set this node to
+      # be redacted in that redaction. (TODO: check that the
+      # user doing the redaction owns the redaction object too)
+      redaction = Redaction.find(redaction_id.to_i)
+      @old_node.redact!(redaction)
+      
     else
-      render :nothing => true, :status => :forbidden
+      # if no redaction ID was provided, then this is an unredact
+      # operation.
+      @old_node.redact!(nil)
+    end
+    
+    # just return an empty 200 OK for success
+    render :nothing => true
+  end
+
+  private
+  
+  def lookup_old_node
+    @old_node = OldNode.where(:node_id => params[:id], :version => params[:version]).first
+    if @old_node.nil?
+      # i want to do this
+      #raise OSM::APINotFoundError.new
+      # but i get errors, so i'm getting very fed up and doing this instead
+      render :nothing => true, :status => :not_found
+      return false
     end
   end
 end
index 5643a389bc8ad69fb83f7f886b122e97f4cbe8ff..e20a3b728a9cb62c2d44f63c3b6c782b2023ed32 100644 (file)
@@ -1,11 +1,14 @@
 class OldNode < ActiveRecord::Base
   include GeoRecord
   include ConsistencyValidations
-  include Redactable
 
   self.table_name = "nodes"
   self.primary_keys = "node_id", "version"
 
+  # note this needs to be included after the table name changes, or
+  # the queries generated by Redactable will use the wrong table name.
+  include Redactable
+
   validates_presence_of :changeset_id, :timestamp
   validates_inclusion_of :visible, :in => [ true, false ]
   validates_numericality_of :latitude, :longitude
index 823c00950c1519d64f1cbb4b544b976fb170f46b..46be25c97e5a842eed477e40925685a6b1a9507b 100644 (file)
@@ -16,7 +16,7 @@ OpenStreetMap::Application.routes.draw do
   match 'api/0.6/node/:id/ways' => 'way#ways_for_node', :via => :get, :id => /\d+/
   match 'api/0.6/node/:id/relations' => 'relation#relations_for_node', :via => :get, :id => /\d+/
   match 'api/0.6/node/:id/history' => 'old_node#history', :via => :get, :id => /\d+/
-  match 'api/0.6/node/:id/:version/redact' => 'old_node#redact', :version => /\d+/, :id => /\d+/
+  match 'api/0.6/node/:id/:version/redact' => 'old_node#redact', :via => :post, :version => /\d+/, :id => /\d+/
   match 'api/0.6/node/:id/:version' => 'old_node#version', :via => :get, :id => /\d+/, :version => /\d+/
   match 'api/0.6/node/:id' => 'node#read', :via => :get, :id => /\d+/
   match 'api/0.6/node/:id' => 'node#update', :via => :put, :id => /\d+/
index b994e8563ab31e2934286d054533b0e2a555f712..d8367d7bdf766741aa9b57a244a16c92786e4885 100644 (file)
@@ -1,6 +1,12 @@
 require 'osm'
 
 module Redactable
+  def self.included(base)
+    # this is used to extend activerecord bases, as these aren't
+    # in scope for the module itself.
+    base.scope :unredacted, base.where(:redaction_id => nil)
+  end
+  
   def redacted?
     not self.redaction.nil?
   end
@@ -11,5 +17,6 @@ module Redactable
 
     # make the change
     self.redaction = redaction
+    self.save!
   end
 end
index efef38ad18c19fb9c808f29db202cf12e2ca3b01..ebc38775163b72d16a3e82061197861a72bd15a7 100644 (file)
@@ -193,7 +193,7 @@ class OldNodeControllerTest < ActionController::TestCase
 
     do_redact_node(nodes(:node_with_versions_v4),
                    redactions(:example))
-    assert_response :forbidden, "shouldn't be OK to redact current version as moderator."
+    assert_response :bad_request, "shouldn't be OK to redact current version as moderator."
   end    
 
   ##