diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 1c97069b0..a9e44d249 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -33,6 +33,7 @@ //= require moderator_comment //= require moderator_debates //= require moderator_proposals +//= require moderator_proposal_notifications //= require prevent_double_submission //= require gettext //= require annotator diff --git a/app/assets/javascripts/moderator_proposal_notifications.js.coffee b/app/assets/javascripts/moderator_proposal_notifications.js.coffee new file mode 100644 index 000000000..b2e8fbf44 --- /dev/null +++ b/app/assets/javascripts/moderator_proposal_notifications.js.coffee @@ -0,0 +1,7 @@ +App.ModeratorProposalNotifications = + + add_class_faded: (id) -> + $("##{id}").addClass("faded") + + hide_moderator_actions: (id) -> + $("##{id} .js-moderator-proposal-notifications-actions:first").hide() diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index 94ef4a7a9..3914f0fa7 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -1963,7 +1963,8 @@ table { } } -.comment-body { +.comment-body, +.notification-body { img { margin-right: $line-height / 2; diff --git a/app/controllers/admin/proposal_notifications_controller.rb b/app/controllers/admin/proposal_notifications_controller.rb new file mode 100644 index 000000000..625e670fa --- /dev/null +++ b/app/controllers/admin/proposal_notifications_controller.rb @@ -0,0 +1,30 @@ +class Admin::ProposalNotificationsController < Admin::BaseController + + has_filters %w{without_confirmed_hide all with_confirmed_hide}, only: :index + + before_action :load_proposal, only: [:confirm_hide, :restore] + + def index + @proposal_notifications = ProposalNotification.only_hidden.send(@current_filter).order(hidden_at: :desc) + .page(params[:page]) + end + + def confirm_hide + @proposal_notification.confirm_hide + redirect_to request.query_parameters.merge(action: :index) + end + + def restore + @proposal_notification.restore + @proposal_notification.ignore_flag + Activity.log(current_user, :restore, @proposal_notification) + redirect_to request.query_parameters.merge(action: :index) + end + + private + + def load_proposal + @proposal_notification = ProposalNotification.with_hidden.find(params[:id]) + end + +end diff --git a/app/controllers/concerns/moderate_actions.rb b/app/controllers/concerns/moderate_actions.rb index 05aa0e97f..98e67bc2b 100644 --- a/app/controllers/concerns/moderate_actions.rb +++ b/app/controllers/concerns/moderate_actions.rb @@ -57,4 +57,4 @@ module ModerateActions :author_id end -end \ No newline at end of file +end diff --git a/app/controllers/concerns/polymorphic.rb b/app/controllers/concerns/polymorphic.rb index 6ac4b5c1c..8fd4ab312 100644 --- a/app/controllers/concerns/polymorphic.rb +++ b/app/controllers/concerns/polymorphic.rb @@ -26,4 +26,4 @@ module Polymorphic send("#{resource_name}_params") end -end \ No newline at end of file +end diff --git a/app/controllers/moderation/proposal_notifications_controller.rb b/app/controllers/moderation/proposal_notifications_controller.rb new file mode 100644 index 000000000..64a2cae5a --- /dev/null +++ b/app/controllers/moderation/proposal_notifications_controller.rb @@ -0,0 +1,24 @@ +class Moderation::ProposalNotificationsController < Moderation::BaseController + include ModerateActions + + has_filters %w{pending_review all ignored}, only: :index + has_orders %w{created_at moderated}, only: :index + + before_action :load_resources, only: [:index, :moderate] + + load_and_authorize_resource + + def hide + ProposalNotification.find(params[:id]).update(moderated: true) + end + + private + + def resource_name + 'proposal_notification' + end + + def resource_model + ProposalNotification + end +end diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 7e679a05d..f43bc8ad9 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -24,6 +24,7 @@ class ProposalsController < ApplicationController def show super @notifications = @proposal.notifications + @notifications = @proposal.notifications.not_moderated @related_contents = Kaminari.paginate_array(@proposal.relationed_contents).page(params[:page]).per(5) redirect_to proposal_path(@proposal), status: :moved_permanently if request.path != proposal_path(@proposal) diff --git a/app/models/abilities/moderation.rb b/app/models/abilities/moderation.rb index f0f823de1..801e752ed 100644 --- a/app/models/abilities/moderation.rb +++ b/app/models/abilities/moderation.rb @@ -52,6 +52,17 @@ module Abilities can :block, User cannot :block, User, id: user.id + + can :hide, ProposalNotification, hidden_at: nil + cannot :hide, ProposalNotification, author_id: user.id + + can :ignore_flag, ProposalNotification, ignored_at: nil, hidden_at: nil + cannot :ignore_flag, ProposalNotification, author_id: user.id + + can :moderate, ProposalNotification + cannot :moderate, ProposalNotification, author_id: user.id + + can :index, ProposalNotification end end end diff --git a/app/models/proposal_notification.rb b/app/models/proposal_notification.rb index 590f19208..f0a6850f7 100644 --- a/app/models/proposal_notification.rb +++ b/app/models/proposal_notification.rb @@ -10,7 +10,19 @@ class ProposalNotification < ActiveRecord::Base validates :proposal, presence: true validate :minimum_interval - scope :public_for_api, -> { where(proposal_id: Proposal.public_for_api.pluck(:id)) } + scope :public_for_api, -> { where(proposal_id: Proposal.public_for_api.pluck(:id)) } + scope :sort_by_created_at, -> { reorder(created_at: :desc) } + scope :sort_by_moderated, -> { reorder(moderated: :desc) } + + scope :moderated, -> { where(moderated: true) } + scope :not_moderated, -> { where(moderated: false) } + scope :pending_review, -> { moderated.where(ignored_at: nil) } + scope :ignored, -> { moderated.where.not(ignored_at: nil) } + + acts_as_paranoid column: :hidden_at + include ActsAsParanoidAliases + + after_create :set_author def minimum_interval return true if proposal.try(:notifications).blank? @@ -25,4 +37,22 @@ class ProposalNotification < ActiveRecord::Base proposal end + def ignore_flag + update(ignored_at: Time.current) + end + + def ignored? + ignored_at.present? + end + + def after_restore + update(moderated: false) + end + + private + + def set_author + self.update(author_id: self.proposal.author_id) if self.proposal + end + end diff --git a/app/models/user.rb b/app/models/user.rb index aaec3e411..47e7f8c2c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -182,12 +182,14 @@ class User < ActiveRecord::Base debates_ids = Debate.where(author_id: id).pluck(:id) comments_ids = Comment.where(user_id: id).pluck(:id) proposal_ids = Proposal.where(author_id: id).pluck(:id) + proposal_notification_ids = ProposalNotification.where(author_id: id).pluck(:id) hide Debate.hide_all debates_ids Comment.hide_all comments_ids Proposal.hide_all proposal_ids + ProposalNotification.hide_all proposal_notification_ids end def erase(erase_reason = nil) diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 748c88e3e..7e6b94047 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -149,6 +149,10 @@ <%= link_to t("admin.menu.hidden_comments"), admin_comments_path %> +
<%= t("admin.shared.moderated_content") %>
+ +<%= render 'shared/filter_subnav', i18n_namespace: "admin.proposal_notifications.index" %> + +<% if @proposal_notifications.any? %> +| <%= t("admin.shared.title") %> | +<%= t("admin.shared.description") %> | +<%= t("admin.shared.actions") %> | + + + <% @proposal_notifications.each do |proposal_notification| %> +
|---|---|---|
| + <%= proposal_notification.title %> + | +
+
+ <%= proposal_notification.body %>
+
+ |
+ + <%= link_to t("admin.actions.restore"), + restore_admin_proposal_notification_path(proposal_notification, request.query_parameters), + method: :put, + data: { confirm: t("admin.actions.confirm") }, + class: "button hollow warning" %> + <% unless proposal_notification.confirmed_hide? %> + <%= link_to t("admin.actions.confirm_hide"), + confirm_hide_admin_proposal_notification_path(proposal_notification, request.query_parameters), + method: :put, + class: "button" %> + <% end %> + | +
+ <%= t('shared.check') %>: + <%= link_to t('shared.check_all'), '#', data: {check_all: "proposal_notification_ids[]"} %> + | + <%= link_to t('shared.check_none'), '#', data: {check_none: "proposal_notification_ids[]"} %> +
+ +| + <%= t("moderation.proposal_notifications.index.headers.proposal_notification") %> + | ++ <%= t("moderation.proposal_notifications.index.headers.moderate") %> + | +
|---|---|
|
+ <%= link_to proposal_notification.title, proposal_notification, target: "_blank" %>
+ + <%= l proposal_notification.updated_at.to_date %> + +
+ <%= proposal_notification.body %>
+
+ |
+ + <%= check_box_tag "proposal_notification_ids[]", proposal_notification.id, nil, id: "#{dom_id(proposal_notification)}_check" %> + | +
<%= notification.created_at.to_date %>
-<%= notification.body %>
+<%= notification.created_at.to_date %>
+ <%= simple_format text_with_links(notification.body), {}, sanitize: false %> + + + <%= render 'proposal_notifications/actions', notification: notification %> + +