Create changeset subscription resource

This commit is contained in:
Anton Khorev 2025-01-22 19:43:57 +03:00
parent 7b19ba580c
commit 84a3a41531
17 changed files with 232 additions and 210 deletions

View file

@ -32,7 +32,7 @@ class Ability
can :read, [:deletion, :account_terms]
if Settings.status != "database_offline"
can [:subscribe, :unsubscribe], Changeset
can [:read, :create, :destroy], :changeset_subscription
can [:read, :create, :update, :destroy], :oauth2_application
can [:read, :destroy], :oauth2_authorized_application
can [:read, :create, :destroy], :oauth2_authorization

View file

@ -0,0 +1,38 @@
class ChangesetSubscriptionsController < ApplicationController
layout "site"
before_action :authorize_web
before_action :set_locale
before_action :check_database_writable
authorize_resource :class => :changeset_subscription
around_action :web_timeout
def show
@changeset = Changeset.find(params[:changeset_id])
@subscribed = @changeset.subscribed?(current_user)
rescue ActiveRecord::RecordNotFound
render :action => "no_such_entry", :status => :not_found
end
def create
@changeset = Changeset.find(params[:changeset_id])
@changeset.subscribe(current_user) unless @changeset.subscribed?(current_user)
redirect_to changeset_path(@changeset)
rescue ActiveRecord::RecordNotFound
render :action => "no_such_entry", :status => :not_found
end
def destroy
@changeset = Changeset.find(params[:changeset_id])
@changeset.unsubscribe(current_user)
redirect_to changeset_path(@changeset)
rescue ActiveRecord::RecordNotFound
render :action => "no_such_entry", :status => :not_found
end
end

View file

@ -7,9 +7,8 @@ class ChangesetsController < ApplicationController
before_action :authorize_web
before_action :set_locale
before_action -> { check_database_readable(:need_api => true) }, :only => [:index, :feed, :show]
before_action -> { check_database_readable(:need_api => true) }
before_action :require_oauth, :only => :show
before_action :check_database_writable, :only => [:subscribe, :unsubscribe]
authorize_resource
@ -107,34 +106,6 @@ class ChangesetsController < ApplicationController
render :template => "browse/not_found", :status => :not_found, :layout => map_layout
end
##
# subscribe to a changeset
def subscribe
@changeset = Changeset.find(params[:id])
if request.post?
@changeset.subscribe(current_user) unless @changeset.subscribed?(current_user)
redirect_to changeset_path(@changeset)
end
rescue ActiveRecord::RecordNotFound
render :action => "no_such_entry", :status => :not_found
end
##
# unsubscribe from a changeset
def unsubscribe
@changeset = Changeset.find(params[:id])
if request.post?
@changeset.unsubscribe(current_user)
redirect_to changeset_path(@changeset)
end
rescue ActiveRecord::RecordNotFound
render :action => "no_such_entry", :status => :not_found
end
private
#------------------------------------------------------------

View file

@ -177,7 +177,7 @@ class UserMailer < ApplicationMailer
@changeset_comment = comment.changeset.tags["comment"].presence
@time = comment.created_at
@changeset_author = comment.changeset.user.display_name
@unsubscribe_url = unsubscribe_changeset_url(comment.changeset)
@changeset_subscription_url = changeset_subscription_url(comment.changeset)
@author = @commenter
subject = if @owner
@ -193,8 +193,8 @@ class UserMailer < ApplicationMailer
set_list_headers(
"#{comment.changeset.id}.changeset.www.openstreetmap.org",
t(".description", :id => comment.changeset.id),
:subscribe => subscribe_changeset_url(comment.changeset),
:unsubscribe => @unsubscribe_url,
:subscribe => @changeset_subscription_url,
:unsubscribe => @changeset_subscription_url,
:archive => @changeset_url
)

View file

@ -0,0 +1,5 @@
<% content_for :heading do %>
<h1><%= t ".heading", :id => h(params[:changeset_id]) %></h1>
<% end %>
<p><%= t ".body", :id => h(params[:changeset_id]) %></p>

View file

@ -0,0 +1,12 @@
<% content_for :heading do %>
<h1><%= @subscribed ? t(".unsubscribe.heading") : t(".subscribe.heading") %></h1>
<% end %>
<%= render :partial => "heading", :object => @changeset, :as => "changeset" %>
<%= bootstrap_form_tag :method => (@subscribed ? :delete : :post) do |f| %>
<% if params[:referer] -%>
<%= f.hidden_field :referer, :value => params[:referer] %>
<% end -%>
<%= f.primary @subscribed ? t(".unsubscribe.button") : t(".subscribe.button") %>
<% end %>

View file

@ -1,5 +0,0 @@
<% content_for :heading do %>
<h1><%= t ".heading", :id => h(params[:id]) %></h1>
<% end %>
<p><%= t ".body", :id => h(params[:id]) %></p>

View file

@ -1,12 +0,0 @@
<% content_for :heading do %>
<h1><%= t ".heading" %></h1>
<% end %>
<%= render :partial => "heading", :object => @changeset, :as => "changeset" %>
<%= bootstrap_form_tag do |f| %>
<% if params[:referer] -%>
<%= f.hidden_field :referer, :value => params[:referer] %>
<% end -%>
<%= f.primary t(".button") %>
<% end %>

View file

@ -1,12 +0,0 @@
<% content_for :heading do %>
<h1><%= t ".heading" %></h1>
<% end %>
<%= render :partial => "heading", :object => @changeset, :as => "changeset" %>
<%= bootstrap_form_tag do |f| %>
<% if params[:referer] -%>
<%= f.hidden_field :referer, :value => params[:referer] %>
<% end -%>
<%= f.primary t(".button") %>
<% end %>

View file

@ -24,6 +24,6 @@
<% content_for :footer do %>
<p>
<%= t ".unsubscribe_html", :url => link_to(@unsubscribe_url, @unsubscribe_url) %>
<%= t ".unsubscribe_html", :url => link_to(@changeset_subscription_url, @changeset_subscription_url) %>
</p>
<% end %>

View file

@ -17,4 +17,4 @@
<%= t '.details', :url => @changeset_url %>
<%= t '.unsubscribe', :url => @unsubscribe_url %>
<%= t '.unsubscribe', :url => @changeset_subscription_url %>

View file

@ -484,18 +484,6 @@ en:
created: "Created"
closed: "Closed"
belongs_to: "Author"
subscribe:
heading: Subscribe to the following changeset discussion?
button: Subscribe to discussion
unsubscribe:
heading: Unsubscribe from the following changeset discussion?
button: Unsubscribe from discussion
heading:
title: "Changeset %{id}"
created_by_html: "Created by %{link_user} on %{created}."
no_such_entry:
heading: "No entry with the id: %{id}"
body: "Sorry, there is no changeset with the id %{id}. Please check your spelling, or maybe the link you clicked is wrong."
show:
title: "Changeset: %{id}"
created: "Created: %{when}"
@ -527,6 +515,20 @@ en:
sorry: "Sorry, changeset #%{id} could not be found."
timeout:
sorry: "Sorry, the list of changesets you requested took too long to retrieve."
changeset_subscriptions:
show:
subscribe:
heading: Subscribe to the following changeset discussion?
button: Subscribe to discussion
unsubscribe:
heading: Unsubscribe from the following changeset discussion?
button: Unsubscribe from discussion
heading:
title: "Changeset %{id}"
created_by_html: "Created by %{link_user} on %{created}."
no_such_entry:
heading: "No entry with the id: %{id}"
body: "Sorry, there is no changeset with the id %{id}. Please check your spelling, or maybe the link you clicked is wrong."
dashboards:
contact:
km away: "%{count}km away"

View file

@ -124,14 +124,16 @@ OpenStreetMap::Application.routes.draw do
get "/relation/:id" => "relations#show", :id => /\d+/, :as => :relation
get "/relation/:id/history" => "old_relations#index", :id => /\d+/, :as => :relation_history
resources :old_relations, :path => "/relation/:id/history", :id => /\d+/, :version => /\d+/, :param => :version, :only => :show
resources :changesets, :path => "changeset", :id => /\d+/, :only => :show do
match :subscribe, :on => :member, :via => [:get, :post]
match :unsubscribe, :on => :member, :via => [:get, :post]
resources :changesets, :path => "changeset", :id => /\d+/, :only => :show do
resource :subscription, :controller => :changeset_subscriptions, :only => [:show, :create, :destroy]
namespace :changeset_comments, :as => :comments, :path => :comments do
resource :feed, :only => :show, :defaults => { :format => "rss" }
end
end
get "/changeset/:id/subscribe", :id => /\d+/, :to => redirect(:path => "/changeset/%{id}/subscription")
get "/changeset/:id/unsubscribe", :id => /\d+/, :to => redirect(:path => "/changeset/%{id}/subscription")
resources :notes, :path => "note", :id => /\d+/, :only => [:show, :new]
get "/user/:display_name/history" => "changesets#index"

View file

@ -0,0 +1,150 @@
require "test_helper"
class ChangesetSubscriptionsControllerTest < ActionDispatch::IntegrationTest
##
# test all routes which lead to this controller
def test_routes
assert_routing(
{ :path => "/changeset/1/subscription", :method => :get },
{ :controller => "changeset_subscriptions", :action => "show", :changeset_id => "1" }
)
assert_routing(
{ :path => "/changeset/1/subscription", :method => :post },
{ :controller => "changeset_subscriptions", :action => "create", :changeset_id => "1" }
)
assert_routing(
{ :path => "/changeset/1/subscription", :method => :delete },
{ :controller => "changeset_subscriptions", :action => "destroy", :changeset_id => "1" }
)
get "/changeset/1/subscribe"
assert_redirected_to "/changeset/1/subscription"
get "/changeset/1/unsubscribe"
assert_redirected_to "/changeset/1/subscription"
end
def test_show_as_anonymous
changeset = create(:changeset)
get changeset_subscription_path(changeset)
assert_redirected_to login_path(:referer => changeset_subscription_path(changeset))
end
def test_show_when_not_subscribed
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
session_for(other_user)
get changeset_subscription_path(changeset)
assert_response :success
assert_dom ".content-body" do
assert_dom "a[href='#{changeset_path(changeset)}']", :text => "Changeset #{changeset.id}"
assert_dom "a[href='#{user_path(user)}']", :text => user.display_name
assert_dom "form" do
assert_dom "> @action", changeset_subscription_path(changeset)
assert_dom "input[type=submit]" do
assert_dom "> @value", "Subscribe to discussion"
end
end
end
end
def test_show_when_subscribed
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
changeset.subscribers << other_user
session_for(other_user)
get changeset_subscription_path(changeset)
assert_response :success
assert_dom ".content-body" do
assert_dom "a[href='#{changeset_path(changeset)}']", :text => "Changeset #{changeset.id}"
assert_dom "a[href='#{user_path(user)}']", :text => user.display_name
assert_dom "form" do
assert_dom "> @action", changeset_subscription_path(changeset)
assert_dom "input[type=submit]" do
assert_dom "> @value", "Unsubscribe from discussion"
end
end
end
end
def test_create_success
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
session_for(other_user)
assert_difference "changeset.subscribers.count", 1 do
post changeset_subscription_path(changeset)
end
assert_redirected_to changeset_path(changeset)
assert changeset.reload.subscribed?(other_user)
end
def test_create_fail
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
changeset.subscribers << other_user
# not signed in
assert_no_difference "changeset.subscribers.count" do
post changeset_subscription_path(changeset)
end
assert_response :forbidden
session_for(other_user)
# bad diary id
post changeset_subscription_path(999111)
assert_response :not_found
# trying to subscribe when already subscribed
assert_no_difference "changeset.subscribers.count" do
post changeset_subscription_path(changeset)
end
end
def test_destroy_success
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
changeset.subscribers << other_user
session_for(other_user)
assert_difference "changeset.subscribers.count", -1 do
delete changeset_subscription_path(changeset)
end
assert_redirected_to changeset_path(changeset)
assert_not changeset.reload.subscribed?(other_user)
end
def test_unsubscribe_fail
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
# not signed in
assert_no_difference "changeset.subscribers.count" do
delete changeset_subscription_path(changeset)
end
assert_response :forbidden
session_for(other_user)
# bad diary id
delete changeset_subscription_path(999111)
assert_response :not_found
# trying to unsubscribe when not subscribed
assert_no_difference "changeset.subscribers.count" do
delete changeset_subscription_path(changeset)
end
end
end

View file

@ -32,22 +32,6 @@ class ChangesetsControllerTest < ActionDispatch::IntegrationTest
{ :path => "/history/feed", :method => :get },
{ :controller => "changesets", :action => "feed", :format => :atom }
)
assert_routing(
{ :path => "/changeset/1/subscribe", :method => :get },
{ :controller => "changesets", :action => "subscribe", :id => "1" }
)
assert_routing(
{ :path => "/changeset/1/subscribe", :method => :post },
{ :controller => "changesets", :action => "subscribe", :id => "1" }
)
assert_routing(
{ :path => "/changeset/1/unsubscribe", :method => :get },
{ :controller => "changesets", :action => "unsubscribe", :id => "1" }
)
assert_routing(
{ :path => "/changeset/1/unsubscribe", :method => :post },
{ :controller => "changesets", :action => "unsubscribe", :id => "1" }
)
end
##
@ -432,119 +416,6 @@ class ChangesetsControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to :action => :feed
end
def test_subscribe_page
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
path = subscribe_changeset_path(changeset)
get path
assert_redirected_to login_path(:referer => path)
session_for(other_user)
get path
assert_response :success
assert_dom ".content-body" do
assert_dom "a[href='#{changeset_path(changeset)}']", :text => "Changeset #{changeset.id}"
assert_dom "a[href='#{user_path(user)}']", :text => user.display_name
end
end
def test_subscribe_success
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
session_for(other_user)
assert_difference "changeset.subscribers.count", 1 do
post subscribe_changeset_path(changeset)
end
assert_redirected_to changeset_path(changeset)
assert changeset.reload.subscribed?(other_user)
end
def test_subscribe_fail
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
# not signed in
assert_no_difference "changeset.subscribers.count" do
post subscribe_changeset_path(changeset)
end
assert_response :forbidden
session_for(other_user)
# bad diary id
post subscribe_changeset_path(999111)
assert_response :not_found
# trying to subscribe when already subscribed
post subscribe_changeset_path(changeset)
assert_no_difference "changeset.subscribers.count" do
post subscribe_changeset_path(changeset)
end
end
def test_unsubscribe_page
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
path = unsubscribe_changeset_path(changeset)
get path
assert_redirected_to login_path(:referer => path)
session_for(other_user)
get path
assert_response :success
assert_dom ".content-body" do
assert_dom "a[href='#{changeset_path(changeset)}']", :text => "Changeset #{changeset.id}"
assert_dom "a[href='#{user_path(user)}']", :text => user.display_name
end
end
def test_unsubscribe_success
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
changeset.subscribers.push(other_user)
session_for(other_user)
assert_difference "changeset.subscribers.count", -1 do
post unsubscribe_changeset_path(changeset)
end
assert_redirected_to changeset_path(changeset)
assert_not changeset.reload.subscribed?(other_user)
end
def test_unsubscribe_fail
user = create(:user)
other_user = create(:user)
changeset = create(:changeset, :user => user)
# not signed in
assert_no_difference "changeset.subscribers.count" do
post unsubscribe_changeset_path(changeset)
end
assert_response :forbidden
session_for(other_user)
# bad diary id
post unsubscribe_changeset_path(999111)
assert_response :not_found
# trying to unsubscribe when not subscribed
assert_no_difference "changeset.subscribers.count" do
post unsubscribe_changeset_path(changeset)
end
end
private
##

View file

@ -83,7 +83,7 @@ class UserMailerTest < ActionMailer::TestCase
body = Rails::Dom::Testing.html_document_fragment.parse(email.html_part.body)
url = Rails.application.routes.url_helpers.changeset_url(changeset, :host => Settings.server_url, :protocol => Settings.server_protocol)
unsubscribe_url = Rails.application.routes.url_helpers.unsubscribe_changeset_url(changeset, :host => Settings.server_url, :protocol => Settings.server_protocol)
unsubscribe_url = Rails.application.routes.url_helpers.changeset_subscription_url(changeset, :host => Settings.server_url, :protocol => Settings.server_protocol)
assert_select body, "a[href^='#{url}']"
assert_select body, "a[href='#{unsubscribe_url}']", :count => 1
end