diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index dd85045997b905cba1840ba4d61f83b1ba19ce68..f055fc9b25172184954da5f9a3d779285570e77b 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -47,13 +47,18 @@ class TagsController < ApplicationController end end - def edit; end + def edit + check_your_privilege('EditTag', nil, true) + end def update - if @tag.update(tag_params.merge(wiki: helpers.render_markdown(params[:tag][:wiki_markdown]))) + return unless check_your_privilege('EditTag', nil, true) + + wiki_md = params[:tag][:wiki_markdown] + if @tag.update(tag_params.merge(wiki: wiki_md.present? ? helpers.render_markdown(wiki_md) : nil)) redirect_to tag_path(id: @category.id, tag_id: @tag.id) else - render :edit + render :edit, status: 400 end end diff --git a/app/models/tag.rb b/app/models/tag.rb index d9daa475dc5697dac6abafe3cc9daae105ffd7ab..5ee4ccc71fd9772e91b54dfd92bb04d036c13d9a 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -13,7 +13,7 @@ class Tag < ApplicationRecord def self.search(term) where('name LIKE ?', "%#{sanitize_sql_like(term)}%") - .order(sanitize_sql_array(['name LIKE ? DESC, name', "#{sanitize_sql_like(term)}%"])) + .order(Arel.sql(sanitize_sql_array(['name LIKE ? DESC, name', "#{sanitize_sql_like(term)}%"]))) end def all_children diff --git a/test/controllers/tags_controller_test.rb b/test/controllers/tags_controller_test.rb index c2760733773b67fef121a7dc214086dfae8c5ea8..171dce5a02cc160d7c74d0d429a996574596de1a 100644 --- a/test/controllers/tags_controller_test.rb +++ b/test/controllers/tags_controller_test.rb @@ -23,4 +23,123 @@ class TagsControllerTest < ActionController::TestCase assert_equal true, tag['name'].start_with?('dis') end end + + test 'should get category tags list' do + get :category, params: { id: categories(:main).id } + assert_response 200 + assert_not_nil assigns(:tags) + assert_not_nil assigns(:category) + + sign_in users(:standard_user) + get :category, params: { id: categories(:main).id } + assert_response 200 + assert_not_nil assigns(:tags) + assert_not_nil assigns(:category) + end + + test 'should get children list' do + get :children, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 200 + assert_not_nil assigns(:tags) + assert_not_nil assigns(:category) + + sign_in users(:standard_user) + get :children, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 200 + assert_not_nil assigns(:tags) + assert_not_nil assigns(:category) + end + + test 'should get tag page and RSS' do + get :show, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 200 + assert_not_nil assigns(:tag) + assert_not_nil assigns(:category) + assert_not_nil assigns(:posts) + + sign_in users(:standard_user) + get :show, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 200 + assert_not_nil assigns(:tag) + assert_not_nil assigns(:category) + assert_not_nil assigns(:posts) + end + + test 'should get tag RSS feed' do + get :show, params: { id: categories(:main).id, tag_id: tags(:topic).id, format: :rss } + assert_response 200 + assert_not_nil assigns(:tag) + assert_not_nil assigns(:category) + assert_not_nil assigns(:posts) + + sign_in users(:standard_user) + get :show, params: { id: categories(:main).id, tag_id: tags(:topic).id, format: :rss } + assert_response 200 + assert_not_nil assigns(:tag) + assert_not_nil assigns(:category) + assert_not_nil assigns(:posts) + end + + test 'should deny edit to anonymous user' do + get :edit, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 302 + assert_redirected_to new_user_session_path + end + + test 'should deny edit to unprivileged user' do + sign_in users(:standard_user) + get :edit, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 401 + end + + test 'should get edit' do + sign_in users(:deleter) + get :edit, params: { id: categories(:main).id, tag_id: tags(:topic).id } + assert_response 200 + assert_not_nil assigns(:tag) + assert_not_nil assigns(:category) + end + + test 'should deny update to anonymous user' do + patch :update, params: { id: categories(:main).id, tag_id: tags(:topic).id, + tag: { parent_id: tags(:discussion).id, excerpt: 'things' } } + assert_response 302 + assert_redirected_to new_user_session_path + end + + test 'should deny update to unprivileged user' do + sign_in users(:standard_user) + patch :update, params: { id: categories(:main).id, tag_id: tags(:topic).id, + tag: { parent_id: tags(:discussion).id, excerpt: 'things' } } + assert_response 401 + end + + test 'should update tag' do + sign_in users(:deleter) + patch :update, params: { id: categories(:main).id, tag_id: tags(:topic).id, + tag: { parent_id: tags(:discussion).id, excerpt: 'things' } } + assert_response 302 + assert_redirected_to tag_path(id: categories(:main).id, tag_id: tags(:topic).id) + assert_not_nil assigns(:tag) + assert_equal tags(:discussion).id, assigns(:tag).parent_id + assert_equal 'things', assigns(:tag).excerpt + end + + test 'should prevent a tag being its own parent' do + sign_in users(:deleter) + patch :update, params: { id: categories(:main).id, tag_id: tags(:topic).id, + tag: { parent_id: tags(:topic).id, excerpt: 'things' } } + assert_response 400 + assert_not_nil assigns(:tag) + assert_equal ['A tag cannot be its own parent.'], assigns(:tag).errors.full_messages + end + + test 'should prevent hierarchical loops' do + sign_in users(:deleter) + patch :update, params: { id: categories(:main).id, tag_id: tags(:topic).id, + tag: { parent_id: tags(:child).id, excerpt: 'things' } } + assert_response 400 + assert_not_nil assigns(:tag) + assert_equal ["The #{tags(:child).name} tag is already a child of this tag."], assigns(:tag).errors.full_messages + end end diff --git a/test/fixtures/tags.yml b/test/fixtures/tags.yml index d35e8f1c03e2499496f4668a33f426d6933f31c5..de28397edc0b3dff9cb435ab40e5e420264e5770 100644 --- a/test/fixtures/tags.yml +++ b/test/fixtures/tags.yml @@ -27,3 +27,14 @@ status-completed: name: status-completed community: sample tag_set: meta + +topic: + name: topic-tag + community: sample + tag_set: main + +child: + name: child-tag + community: sample + tag_set: main + parent: topic