diff --git a/app/assets/javascripts/comments.js.coffee b/app/assets/javascripts/comments.js.coffee index 377fa4d1a..8a9ebe0b1 100644 --- a/app/assets/javascripts/comments.js.coffee +++ b/app/assets/javascripts/comments.js.coffee @@ -1,8 +1,11 @@ App.Comments = - add_response: (parent_id, response_html) -> + add_comment: (parent_id, response_html) -> $(response_html).insertAfter($("#js-comment-form-#{parent_id}")) + add_reply: (parent_id, response_html) -> + $("##{parent_id} .comment-children:first").prepend($(response_html)) + display_error: (field_with_errors, error_html) -> $(error_html).insertAfter($("#{field_with_errors}")) diff --git a/app/assets/javascripts/moderator_comment.js.coffee b/app/assets/javascripts/moderator_comment.js.coffee new file mode 100644 index 000000000..7cc680169 --- /dev/null +++ b/app/assets/javascripts/moderator_comment.js.coffee @@ -0,0 +1,7 @@ +App.ModeratorComments = + + add_class_faded: (id) -> + $("##{id} .comment-body:first").addClass("faded") + + hide_moderator_actions: (id) -> + $("##{id} #moderator-comment-actions:first").hide() \ No newline at end of file diff --git a/app/assets/javascripts/moderator_debates.js.coffee b/app/assets/javascripts/moderator_debates.js.coffee new file mode 100644 index 000000000..802504ec2 --- /dev/null +++ b/app/assets/javascripts/moderator_debates.js.coffee @@ -0,0 +1,8 @@ +App.ModeratorDebates = + + add_class_faded: (id) -> + $("##{id}").addClass("faded") + $("#comments").addClass("faded") + + hide_moderator_actions: (id) -> + $("##{id} #moderator-debate-actions:first").hide() \ No newline at end of file diff --git a/app/assets/stylesheets/debates.scss b/app/assets/stylesheets/debates.scss index f242e8757..afc99b75a 100644 --- a/app/assets/stylesheets/debates.scss +++ b/app/assets/stylesheets/debates.scss @@ -571,4 +571,9 @@ } } } + +} + +.faded { + opacity: 0.4; } diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index f4322efe7..f011be7d9 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -1,4 +1,5 @@ class Admin::BaseController < ApplicationController + layout 'admin' before_action :authenticate_user! skip_authorization_check diff --git a/app/controllers/admin/comments_controller.rb b/app/controllers/admin/comments_controller.rb new file mode 100644 index 000000000..4c385b5d4 --- /dev/null +++ b/app/controllers/admin/comments_controller.rb @@ -0,0 +1,13 @@ +class Admin::CommentsController < Admin::BaseController + + def index + @comments = Comment.only_hidden + end + + def restore + @comment = Comment.with_hidden.find(params[:id]) + @comment.restore + redirect_to admin_comments_path, notice: t('admin.comments.restore.success') + end + +end \ No newline at end of file diff --git a/app/controllers/admin/debates_controller.rb b/app/controllers/admin/debates_controller.rb new file mode 100644 index 000000000..a37744f71 --- /dev/null +++ b/app/controllers/admin/debates_controller.rb @@ -0,0 +1,16 @@ +class Admin::DebatesController < Admin::BaseController + + def index + @debates = Debate.only_hidden + end + + def show + @debate = Debate.with_hidden.find(params[:id]) + end + + def restore + @debate = Debate.with_hidden.find(params[:id]) + @debate.restore + redirect_to admin_debates_path, notice: t('admin.debates.restore.success') + end +end \ No newline at end of file diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 71de112a9..a10d80da9 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -2,6 +2,7 @@ class CommentsController < ApplicationController before_action :authenticate_user! before_action :build_comment, only: :create before_action :parent, only: :create + load_and_authorize_resource respond_to :html, :js @@ -50,4 +51,5 @@ class CommentsController < ApplicationController def email_on_comment_reply? reply? && parent.author.email_on_comment_reply? end + end diff --git a/app/controllers/debates_controller.rb b/app/controllers/debates_controller.rb index 0816245c7..eeb82825a 100644 --- a/app/controllers/debates_controller.rb +++ b/app/controllers/debates_controller.rb @@ -1,6 +1,8 @@ class DebatesController < ApplicationController before_action :authenticate_user!, except: [:index, :show] + load_and_authorize_resource + respond_to :html, :js def index @debates = Debate.search(params) @@ -9,6 +11,7 @@ class DebatesController < ApplicationController def show set_debate_votes(@debate) + @comments = @debate.root_comments.with_hidden.recent end def new @@ -46,7 +49,6 @@ class DebatesController < ApplicationController set_debate_votes(@debate) end - private def debate_params diff --git a/app/controllers/moderation/comments_controller.rb b/app/controllers/moderation/comments_controller.rb new file mode 100644 index 000000000..c250fc460 --- /dev/null +++ b/app/controllers/moderation/comments_controller.rb @@ -0,0 +1,8 @@ +class Moderation::CommentsController < Moderation::BaseController + + def hide + @comment = Comment.find(params[:id]) + @comment.hide + end + +end \ No newline at end of file diff --git a/app/controllers/moderation/debates_controller.rb b/app/controllers/moderation/debates_controller.rb new file mode 100644 index 000000000..cb5599092 --- /dev/null +++ b/app/controllers/moderation/debates_controller.rb @@ -0,0 +1,7 @@ +class Moderation::DebatesController < Moderation::BaseController + + def hide + @debate = Debate.find(params[:id]) + @debate.hide + end +end \ No newline at end of file diff --git a/app/helpers/abilities_helper.rb b/app/helpers/abilities_helper.rb new file mode 100644 index 000000000..462af0479 --- /dev/null +++ b/app/helpers/abilities_helper.rb @@ -0,0 +1,7 @@ +module AbilitiesHelper + + def moderator? + current_user.try(:moderator?) + end + +end \ No newline at end of file diff --git a/app/models/ability.rb b/app/models/ability.rb index c1fc24ae3..62947b52c 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -15,10 +15,13 @@ class Ability can [:create, :vote], Comment - if user.moderator? or user.administrator? + if user.moderator? + can [:hide], Comment + can [:hide], Debate elsif user.administrator? - + can [:restore], Comment + can [:restore], Debate end end end diff --git a/app/models/comment.rb b/app/models/comment.rb index b8182b04f..f8a43c222 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,5 +1,8 @@ class Comment < ActiveRecord::Base + include ActsAsParanoidAliases acts_as_nested_set scope: [:commentable_id, :commentable_type], counter_cache: :children_count + + acts_as_paranoid column: :hidden_at acts_as_votable validates :body, presence: true diff --git a/app/models/debate.rb b/app/models/debate.rb index b0d022c51..e029ffdd4 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -1,5 +1,6 @@ require 'numeric' class Debate < ActiveRecord::Base + include ActsAsParanoidAliases default_scope { order('created_at DESC') } apply_simple_captcha @@ -8,6 +9,7 @@ class Debate < ActiveRecord::Base acts_as_votable acts_as_commentable acts_as_taggable + acts_as_paranoid column: :hidden_at belongs_to :author, class_name: 'User', foreign_key: 'author_id' diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 79540a5d0..8ea2b27af 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -1,3 +1,5 @@ -
- <%= link_to t('admin.tags.index.title'), admin_tags_path %> -
+ diff --git a/app/views/admin/comments/index.html.erb b/app/views/admin/comments/index.html.erb new file mode 100644 index 000000000..1555fda0c --- /dev/null +++ b/app/views/admin/comments/index.html.erb @@ -0,0 +1,14 @@ +
+

<%= t("admin.comments.index.title") %>

+ + +
diff --git a/app/views/admin/debates/index.html.erb b/app/views/admin/debates/index.html.erb new file mode 100644 index 000000000..ce07205b3 --- /dev/null +++ b/app/views/admin/debates/index.html.erb @@ -0,0 +1,13 @@ +
+

<%= t("admin.debates.index.title") %>

+ + +
\ No newline at end of file diff --git a/app/views/admin/debates/show.html.erb b/app/views/admin/debates/show.html.erb new file mode 100644 index 000000000..aaa22eec9 --- /dev/null +++ b/app/views/admin/debates/show.html.erb @@ -0,0 +1,13 @@ +
+

<%= t("admin.debates.index.title") %>

+ +
+
<%= @debate.title %>
+
<%= @debate.description %>
+ +
+ <%= link_to t('admin.actions.restore'), restore_admin_debate_path(@debate), + method: :put, data: { confirm: t('admin.actions.confirm') } %> +
+
+
\ No newline at end of file diff --git a/app/views/comments/_actions.html.erb b/app/views/comments/_actions.html.erb new file mode 100644 index 000000000..ecc9bc9c0 --- /dev/null +++ b/app/views/comments/_actions.html.erb @@ -0,0 +1,5 @@ + +  |  + <%= link_to t("admin.actions.hide").capitalize, hide_moderation_comment_path(comment), + method: :put, remote: true, data: { confirm: t('admin.actions.confirm') } %> + \ No newline at end of file diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb index af5a41897..1de4bfd7b 100644 --- a/app/views/comments/_comment.html.erb +++ b/app/views/comments/_comment.html.erb @@ -1,30 +1,44 @@
-
+
- <%= avatar_image(comment.user, size: 32, class: 'left') %> + <% if comment.hidden? %> + This comment has been deleted + <% else %> -
- - <%= comment.user.name %> • <%= time_ago_in_words(comment.created_at) %> - -

<%= comment.body %>

+ <%= avatar_image(comment.user, size: 32, class: 'left') %> - - <%= render 'comments/votes', comment: comment %> - +
+ + <%= comment.user.name %> • <%= time_ago_in_words(comment.created_at) %> + +

<%= comment.body %>

-

- <%= t("debates.comment.responses", count: comment.children_count) %> - <% if user_signed_in? %> -  |  - <%= render 'comments/form', {parent: comment, toggeable: true} %> - <% end %> -

-
+ + <%= render 'comments/votes', comment: comment %> + -
- <%= render comment.children.reorder('id DESC, lft') %> -
+

+ <%= t("debates.comment.responses", count: comment.children_count) %> + + <% if user_signed_in? %> +  |  + <%= link_to(comment_link_text(comment), "", + class: "js-add-comment-link", data: {'id': dom_id(comment)}) %> + + <% if moderator? %> + <%= render 'comments/actions', comment: comment %> + <% end %> + + <%= render 'comments/form', {parent: comment, toggeable: true} %> + <% end %> +

+
+ + <% end %> + +
+ <%= render comment.children.with_deleted.reorder('id DESC, lft') %> +
-
+
\ No newline at end of file diff --git a/app/views/comments/_form.html.erb b/app/views/comments/_form.html.erb index da2b3bb61..d7fcb5cdd 100644 --- a/app/views/comments/_form.html.erb +++ b/app/views/comments/_form.html.erb @@ -1,5 +1,3 @@ -<%= link_to(comment_link_text(parent), "", class: "js-add-comment-link", data: {'id': dom_id(parent)}) if toggeable %> -
> <%= form_for [@debate, Comment.new], remote: true do |f| %> <%= f.text_area :body %> diff --git a/app/views/comments/create.js.erb b/app/views/comments/create.js.erb index f2b078195..ed3e9c8f9 100644 --- a/app/views/comments/create.js.erb +++ b/app/views/comments/create.js.erb @@ -1,9 +1,10 @@ -var parent_id = '<%= dom_id(@parent) %>'; +var parent_id = "<%= dom_id(@parent) %>"; +var comment_html = "<%= j(render @comment) %>" <% if @parent.is_a?(Debate) -%> App.Comments.reset_form(parent_id); + App.Comments.add_comment(parent_id, comment_html); <% else -%> App.Comments.reset_and_hide_form(parent_id); + App.Comments.add_reply(parent_id, comment_html); <% end -%> - -App.Comments.add_response(parent_id, "<%= j(render @comment) %>"); diff --git a/app/views/debates/_actions.html.erb b/app/views/debates/_actions.html.erb new file mode 100644 index 000000000..3300a7b1d --- /dev/null +++ b/app/views/debates/_actions.html.erb @@ -0,0 +1,2 @@ +<%= link_to t("admin.actions.hide").capitalize, hide_moderation_debate_path(debate), + method: :put, remote: true, data: { confirm: t('admin.actions.confirm') } %> diff --git a/app/views/debates/show.html.erb b/app/views/debates/show.html.erb index 7396a72a2..29ce06b2b 100644 --- a/app/views/debates/show.html.erb +++ b/app/views/debates/show.html.erb @@ -1,5 +1,5 @@
-
+
 <%= link_to t("debates.show.back_link"), debates_path, class: 'left back' %> @@ -21,12 +21,19 @@  •  <%= l @debate.created_at.to_date %>  •  -  <%= link_to t("debates.show.comments", count: @debate.comment_threads.count), "#comments" %> +   + <%= link_to t("debates.show.comments", count: @debate.comment_threads.count), "#comments" %>
<%= @debate.description %> <%= render 'shared/tags', debate: @debate %> + + <% if moderator? %> +
+ <%= render 'actions', debate: @debate %> +
+ <% end %>
<% end %> - <%= render @debate.root_comments.recent %> + + <%= render @comments %>
diff --git a/app/views/moderation/comments/hide.js.erb b/app/views/moderation/comments/hide.js.erb new file mode 100644 index 000000000..4583aff53 --- /dev/null +++ b/app/views/moderation/comments/hide.js.erb @@ -0,0 +1,3 @@ +var comment_id = '<%= dom_id(@comment) %>'; +App.ModeratorComments.add_class_faded(comment_id); +App.ModeratorComments.hide_moderator_actions(comment_id); \ No newline at end of file diff --git a/app/views/moderation/debates/hide.js.erb b/app/views/moderation/debates/hide.js.erb new file mode 100644 index 000000000..1502feb08 --- /dev/null +++ b/app/views/moderation/debates/hide.js.erb @@ -0,0 +1,3 @@ +var debate_id = '<%= dom_id(@debate) %>'; +App.ModeratorDebates.add_class_faded(debate_id); +App.ModeratorDebates.hide_moderator_actions(debate_id); \ No newline at end of file diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index a5b469e1b..42c6d375c 100644 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -3,6 +3,14 @@ en: dashboard: index: title: Administration + menu: + debate_topics: Debate topics + hidden_debates: Hidden debates + hidden_comments: Hidden comments + actions: + hide: Hide + restore: Restore + confirm: 'Are you sure?' tags: index: title: 'Debate topics' @@ -11,3 +19,14 @@ en: name: placeholder: 'Write a topic' destroy: Delete Tag + comments: + index: + title: Hidden comments + restore: + success: The comment has been restored + debates: + index: + title: Hidden debates + restore: + success: The debate has been restored + diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index fecb7c5f4..71062c25b 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -3,6 +3,14 @@ es: dashboard: index: title: Administración + menu: + debate_topics: Temas de debate + hidden_debates: Debates ocultos + hidden_comments: Comentarios ocultos + actions: + hide: Ocultar + restore: Permitir + confirm: '¿Estás seguro?' tags: index: title: 'Temas de debate' @@ -11,3 +19,13 @@ es: name: placeholder: 'Escribe el nombre del tema' destroy: Elimina la etiqueta + comments: + index: + title: Comentarios ocultos + restore: + success: El comentario ha sido permitido + debates: + index: + title: Debates ocultos + restore: + success: El debate ha sido permitido diff --git a/config/routes.rb b/config/routes.rb index 5470223e8..27f558e69 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,14 +8,10 @@ Rails.application.routes.draw do root 'welcome#index' resources :debates do - member do - post :vote - end + member { post :vote } resources :comments, only: :create, shallow: true do - member do - post :vote - end + member { post :vote } end end @@ -24,11 +20,27 @@ Rails.application.routes.draw do namespace :admin do root to: "dashboard#index" + resources :debates, only: [:index, :show] do + member { put :restore } + end + + resources :comments, only: :index do + member { put :restore } + end + resources :tags, only: [:index, :create, :update, :destroy] end namespace :moderation do root to: "dashboard#index" + + resources :debates, only: [] do + member { put :hide } + end + + resources :comments, only: [:index] do + member { put :hide } + end end # Example of regular route: diff --git a/db/migrate/20150810201448_add_hidden_at_to_comments.rb b/db/migrate/20150810201448_add_hidden_at_to_comments.rb new file mode 100644 index 000000000..55d652087 --- /dev/null +++ b/db/migrate/20150810201448_add_hidden_at_to_comments.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToComments < ActiveRecord::Migration + def change + add_column :comments, :hidden_at, :datetime + add_index :comments, :hidden_at + end +end diff --git a/db/migrate/20150811145628_add_hidden_at_to_debates.rb b/db/migrate/20150811145628_add_hidden_at_to_debates.rb new file mode 100644 index 000000000..5fbb29532 --- /dev/null +++ b/db/migrate/20150811145628_add_hidden_at_to_debates.rb @@ -0,0 +1,6 @@ +class AddHiddenAtToDebates < ActiveRecord::Migration + def change + add_column :debates, :hidden_at, :datetime + add_index :debates, :hidden_at + end +end diff --git a/db/schema.rb b/db/schema.rb index 4e8e2c286..f35d265f6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,7 +12,6 @@ # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 20150815154430) do - # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -35,9 +34,11 @@ ActiveRecord::Schema.define(version: 20150815154430) do t.datetime "created_at" t.datetime "updated_at" t.integer "children_count", default: 0 + t.datetime "hidden_at" end add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type", using: :btree + add_index "comments", ["hidden_at"], name: "index_comments_on_hidden_at", using: :btree add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree create_table "debates", force: :cascade do |t| @@ -46,8 +47,11 @@ ActiveRecord::Schema.define(version: 20150815154430) do t.integer "author_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "hidden_at" end + add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree + create_table "moderators", force: :cascade do |t| t.integer "user_id" end diff --git a/lib/acts_as_paranoid_aliases.rb b/lib/acts_as_paranoid_aliases.rb new file mode 100644 index 000000000..fac6b685b --- /dev/null +++ b/lib/acts_as_paranoid_aliases.rb @@ -0,0 +1,33 @@ +module ActsAsParanoidAliases + + def self.included(base) + base.extend(ClassMethods) + + def viewable? + not deleted? + end + + def hide + update_attribute(:hidden_at, Time.now) + end + + def hidden? + deleted? + end + end + + module ClassMethods + def with_hidden + with_deleted + end + + def only_hidden + only_deleted + end + end + +end + +module ActsAsParanoid + include ActsAsParanoidAliases +end \ No newline at end of file diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 3954ec600..5486b286e 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -4,6 +4,7 @@ require 'cancan/matchers' describe Ability do subject(:ability) { Ability.new(user) } let(:debate) { Debate.new } + let(:comment) { create(:comment) } describe "Non-logged in user" do let(:user) { nil } @@ -53,6 +54,11 @@ describe Ability do it { should be_able_to(:show, debate) } it { should be_able_to(:vote, debate) } + it { should be_able_to(:hide, comment) } + it { should be_able_to(:hide, debate) } + + it { should_not be_able_to(:restore, comment) } + it { should_not be_able_to(:restore, debate) } end describe "Administrator" do @@ -63,5 +69,7 @@ describe Ability do it { should be_able_to(:show, debate) } it { should be_able_to(:vote, debate) } + it { should be_able_to(:restore, comment) } + it { should be_able_to(:restore, debate) } end end