This commit is contained in:
Anton Khorev 2025-03-12 00:33:30 +03:00 committed by GitHub
commit 77e01983a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 219 additions and 175 deletions

View file

@ -3,7 +3,7 @@
class ApiAbility
include CanCan::Ability
def initialize(user, scopes)
def initialize(user, scopes) # rubocop:disable Metrics/CyclomaticComplexity
can :read, [:version, :capability, :permission, :map]
if Settings.status != "database_offline"
@ -34,7 +34,8 @@ class ApiAbility
can :read, :active_user_blocks_list if scopes.include?("read_prefs")
if user.terms_agreed?
can [:create, :update, :upload, :close, :subscribe, :unsubscribe], Changeset if scopes.include?("write_map")
can [:create, :update, :upload, :close], Changeset if scopes.include?("write_map")
can [:create, :destroy], :changeset_subscription if scopes.include?("write_map")
can :create, ChangesetComment if scopes.include?("write_changeset_comments")
can [:create, :update, :destroy], [Node, Way, Relation] if scopes.include?("write_map")
end

View file

@ -0,0 +1,55 @@
module Api
class ChangesetSubscriptionsController < ApiController
before_action :check_api_writable
before_action :authorize
authorize_resource :class => :changeset_subscription
before_action :require_public_data
before_action :set_request_formats
##
# Adds a subscriber to the changeset
def create
# Check the arguments are sane
raise OSM::APIBadUserInput, "No id was given" unless params[:changeset_id]
# Extract the arguments
changeset_id = params[:changeset_id].to_i
# Find the changeset and check it is valid
@changeset = Changeset.find(changeset_id)
raise OSM::APIChangesetAlreadySubscribedError, @changeset if @changeset.subscribed?(current_user)
# Add the subscriber
@changeset.subscribe(current_user)
respond_to do |format|
format.xml
format.json
end
end
##
# Removes a subscriber from the changeset
def destroy
# Check the arguments are sane
raise OSM::APIBadUserInput, "No id was given" unless params[:changeset_id]
# Extract the arguments
changeset_id = params[:changeset_id].to_i
# Find the changeset and check it is valid
@changeset = Changeset.find(changeset_id)
raise OSM::APIChangesetNotSubscribedError, @changeset unless @changeset.subscribed?(current_user)
# Remove the subscriber
@changeset.unsubscribe(current_user)
respond_to do |format|
format.xml
format.json
end
end
end
end

View file

@ -4,13 +4,13 @@ module Api
class ChangesetsController < ApiController
include QueryMethods
before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe]
before_action :check_api_writable, :only => [:create, :update, :upload]
before_action :setup_user_auth, :only => [:show]
before_action :authorize, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
before_action :authorize, :only => [:create, :update, :upload, :close]
authorize_resource
before_action :require_public_data, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
before_action :require_public_data, :only => [:create, :update, :upload, :close]
before_action :set_request_formats, :except => [:create, :close, :upload]
skip_around_action :api_call_timeout, :only => [:upload]
@ -152,58 +152,6 @@ module Api
end
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.subscribed?(current_user)
# Add the subscriber
changeset.subscribe(current_user)
# Return a copy of the updated changeset
@changeset = changeset
render "show"
respond_to do |format|
format.xml
format.json
end
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.subscribed?(current_user)
# Remove the subscriber
changeset.unsubscribe(current_user)
# Return a copy of the updated changeset
@changeset = changeset
render "show"
respond_to do |format|
format.xml
format.json
end
end
private
#------------------------------------------------------------

View file

@ -0,0 +1,5 @@
json.partial! "api/root_attributes"
json.changeset do
json.partial! @changeset
end

View file

@ -0,0 +1,5 @@
xml.instruct! :xml, :version => "1.0"
xml.osm(OSM::API.new.xml_root_attributes) do |osm|
osm << render(@changeset)
end

View file

@ -0,0 +1,5 @@
json.partial! "api/root_attributes"
json.changeset do
json.partial! @changeset
end

View file

@ -0,0 +1,5 @@
xml.instruct! :xml, :version => "1.0"
xml.osm(OSM::API.new.xml_root_attributes) do |osm|
osm << render(@changeset)
end

View file

@ -23,14 +23,14 @@
<%= tag.button t(".unsubscribe"),
:class => "btn btn-sm btn-primary",
:name => "unsubscribe",
:data => { :method => "POST",
:url => api_changeset_unsubscribe_url(@changeset) } %>
:data => { :method => "DELETE",
:url => api_changeset_subscription_path(@changeset) } %>
<% else %>
<%= tag.button t(".subscribe"),
:class => "btn btn-sm btn-primary",
:name => "subscribe",
:data => { :method => "POST",
:url => api_changeset_subscribe_url(@changeset) } %>
:url => api_changeset_subscription_path(@changeset) } %>
<% end %>
</div>
<% end %>

View file

@ -18,8 +18,6 @@ OpenStreetMap::Application.routes.draw do
get "permissions" => "permissions#show"
post "changeset/:id/upload" => "changesets#upload", :as => :changeset_upload, :id => /\d+/
post "changeset/:id/subscribe" => "changesets#subscribe", :as => :api_changeset_subscribe, :id => /\d+/
post "changeset/:id/unsubscribe" => "changesets#unsubscribe", :as => :api_changeset_unsubscribe, :id => /\d+/
put "changeset/:id/close" => "changesets#close", :as => :changeset_close, :id => /\d+/
end
@ -27,9 +25,12 @@ OpenStreetMap::Application.routes.draw do
resources :changesets, :only => [:index, :create]
resources :changesets, :path => "changeset", :id => /\d+/, :only => [:show, :update] do
resource :download, :module => :changesets, :only => :show
resource :subscription, :controller => :changeset_subscriptions, :only => [:create, :destroy]
resources :changeset_comments, :path => "comment", :only => :create
end
put "changeset/create" => "changesets#create", :as => nil
post "changeset/:changeset_id/subscribe" => "changeset_subscriptions#create", :changeset_id => /\d+/, :as => nil
post "changeset/:changeset_id/unsubscribe" => "changeset_subscriptions#destroy", :changeset_id => /\d+/, :as => nil
resources :changeset_comments, :id => /\d+/, :only => :index do
resource :visibility, :module => :changeset_comments, :only => [:create, :destroy]

View file

@ -0,0 +1,132 @@
require "test_helper"
module Api
class ChangesetsControllerTest < ActionDispatch::IntegrationTest
##
# test all routes which lead to this controller
def test_routes
assert_routing(
{ :path => "/api/0.6/changeset/1/subscription", :method => :post },
{ :controller => "api/changeset_subscriptions", :action => "create", :changeset_id => "1" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/subscription.json", :method => :post },
{ :controller => "api/changeset_subscriptions", :action => "create", :changeset_id => "1", :format => "json" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/subscription", :method => :delete },
{ :controller => "api/changeset_subscriptions", :action => "destroy", :changeset_id => "1" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/subscription.json", :method => :delete },
{ :controller => "api/changeset_subscriptions", :action => "destroy", :changeset_id => "1", :format => "json" }
)
assert_recognizes(
{ :controller => "api/changeset_subscriptions", :action => "create", :changeset_id => "1" },
{ :path => "/api/0.6/changeset/1/subscribe", :method => :post }
)
assert_recognizes(
{ :controller => "api/changeset_subscriptions", :action => "create", :changeset_id => "1", :format => "json" },
{ :path => "/api/0.6/changeset/1/subscribe.json", :method => :post }
)
assert_recognizes(
{ :controller => "api/changeset_subscriptions", :action => "destroy", :changeset_id => "1" },
{ :path => "/api/0.6/changeset/1/unsubscribe", :method => :post }
)
assert_recognizes(
{ :controller => "api/changeset_subscriptions", :action => "destroy", :changeset_id => "1", :format => "json" },
{ :path => "/api/0.6/changeset/1/unsubscribe.json", :method => :post }
)
end
def test_create_success
auth_header = bearer_authorization_header
changeset = create(:changeset, :closed)
assert_difference "changeset.subscribers.count", 1 do
post api_changeset_subscription_path(changeset), :headers => auth_header
end
assert_response :success
# not closed changeset
changeset = create(:changeset)
assert_difference "changeset.subscribers.count", 1 do
post api_changeset_subscription_path(changeset), :headers => auth_header
end
assert_response :success
end
def test_create_fail
user = create(:user)
# unauthorized
changeset = create(:changeset, :closed)
assert_no_difference "changeset.subscribers.count" do
post api_changeset_subscription_path(changeset)
end
assert_response :unauthorized
auth_header = bearer_authorization_header user
# bad changeset id
assert_no_difference "changeset.subscribers.count" do
post api_changeset_subscription_path(999111), :headers => auth_header
end
assert_response :not_found
# trying to subscribe when already subscribed
changeset = create(:changeset, :closed)
changeset.subscribers.push(user)
assert_no_difference "changeset.subscribers.count" do
post api_changeset_subscription_path(changeset), :headers => auth_header
end
assert_response :conflict
end
def test_destroy_success
user = create(:user)
auth_header = bearer_authorization_header user
changeset = create(:changeset, :closed)
changeset.subscribers.push(user)
assert_difference "changeset.subscribers.count", -1 do
delete api_changeset_subscription_path(changeset), :headers => auth_header
end
assert_response :success
# not closed changeset
changeset = create(:changeset)
changeset.subscribers.push(user)
assert_difference "changeset.subscribers.count", -1 do
delete api_changeset_subscription_path(changeset), :headers => auth_header
end
assert_response :success
end
def test_destroy_fail
# unauthorized
changeset = create(:changeset, :closed)
assert_no_difference "changeset.subscribers.count" do
delete api_changeset_subscription_path(changeset)
end
assert_response :unauthorized
auth_header = bearer_authorization_header
# bad changeset id
assert_no_difference "changeset.subscribers.count" do
delete api_changeset_subscription_path(999111), :headers => auth_header
end
assert_response :not_found
# trying to unsubscribe when not subscribed
changeset = create(:changeset, :closed)
assert_no_difference "changeset.subscribers.count" do
delete api_changeset_subscription_path(changeset), :headers => auth_header
end
assert_response :not_found
end
end
end

View file

@ -33,22 +33,6 @@ module Api
{ :path => "/api/0.6/changeset/1/upload", :method => :post },
{ :controller => "api/changesets", :action => "upload", :id => "1" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/subscribe", :method => :post },
{ :controller => "api/changesets", :action => "subscribe", :id => "1" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/subscribe.json", :method => :post },
{ :controller => "api/changesets", :action => "subscribe", :id => "1", :format => "json" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/unsubscribe", :method => :post },
{ :controller => "api/changesets", :action => "unsubscribe", :id => "1" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/unsubscribe.json", :method => :post },
{ :controller => "api/changesets", :action => "unsubscribe", :id => "1", :format => "json" }
)
assert_routing(
{ :path => "/api/0.6/changeset/1/close", :method => :put },
{ :controller => "api/changesets", :action => "close", :id => "1" }
@ -2503,103 +2487,6 @@ module Api
"element limit.")
end
##
# test subscribe success
def test_subscribe_success
auth_header = bearer_authorization_header
changeset = create(:changeset, :closed)
assert_difference "changeset.subscribers.count", 1 do
post api_changeset_subscribe_path(changeset), :headers => auth_header
end
assert_response :success
# not closed changeset
changeset = create(:changeset)
assert_difference "changeset.subscribers.count", 1 do
post api_changeset_subscribe_path(changeset), :headers => auth_header
end
assert_response :success
end
##
# test subscribe fail
def test_subscribe_fail
user = create(:user)
# unauthorized
changeset = create(:changeset, :closed)
assert_no_difference "changeset.subscribers.count" do
post api_changeset_subscribe_path(changeset)
end
assert_response :unauthorized
auth_header = bearer_authorization_header user
# bad changeset id
assert_no_difference "changeset.subscribers.count" do
post api_changeset_subscribe_path(999111), :headers => auth_header
end
assert_response :not_found
# trying to subscribe when already subscribed
changeset = create(:changeset, :closed)
changeset.subscribers.push(user)
assert_no_difference "changeset.subscribers.count" do
post api_changeset_subscribe_path(changeset), :headers => auth_header
end
assert_response :conflict
end
##
# test unsubscribe success
def test_unsubscribe_success
user = create(:user)
auth_header = bearer_authorization_header user
changeset = create(:changeset, :closed)
changeset.subscribers.push(user)
assert_difference "changeset.subscribers.count", -1 do
post api_changeset_unsubscribe_path(changeset), :headers => auth_header
end
assert_response :success
# not closed changeset
changeset = create(:changeset)
changeset.subscribers.push(user)
assert_difference "changeset.subscribers.count", -1 do
post api_changeset_unsubscribe_path(changeset), :headers => auth_header
end
assert_response :success
end
##
# test unsubscribe fail
def test_unsubscribe_fail
# unauthorized
changeset = create(:changeset, :closed)
assert_no_difference "changeset.subscribers.count" do
post api_changeset_unsubscribe_path(changeset)
end
assert_response :unauthorized
auth_header = bearer_authorization_header
# bad changeset id
assert_no_difference "changeset.subscribers.count" do
post api_changeset_unsubscribe_path(999111), :headers => auth_header
end
assert_response :not_found
# trying to unsubscribe when not subscribed
changeset = create(:changeset, :closed)
assert_no_difference "changeset.subscribers.count" do
post api_changeset_unsubscribe_path(changeset), :headers => auth_header
end
assert_response :not_found
end
private
##