Commit fd453c35b35357625cc759ccb6375d65346501c9

Authored by Ábner Silva de Oliveira
1 parent e6cd995b

moderação das propostas.

controllers/myprofile/proposals_discussion_plugin_evaluate_tasks_controller.rb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +class ProposalsDiscussionPluginEvaluateTasksController < MyProfileController
  2 +
  3 + protect :view_tasks, :profile, :only => [:flag_approve_proposal, :flag_reject_proposal]
  4 +
  5 + def flag_approve_proposal
  6 + if request.post? && params[:task_id]
  7 + result = {
  8 + success: false,
  9 + message: _('Error flagging proposal. Please, contact the system admin')
  10 + }
  11 +
  12 + task = Task.to(profile).find_by_id params[:task_id]
  13 + save = task.flag_accept_proposal(current_person)
  14 +
  15 + if save
  16 + result = {:success => true }
  17 + end
  18 + end
  19 +
  20 + render json: result
  21 + end
  22 +
  23 + def flag_reject_proposal
  24 + if request.post? && params[:task_id]
  25 + result = {
  26 + success: false,
  27 + message: _('Error flagging proposal. Please, contact the system admin')
  28 + }
  29 +
  30 + task = Task.to(profile).find_by_id params[:task_id]
  31 + save = task.flag_reject_proposal(current_person)
  32 +
  33 + if save
  34 + result = {:success => true }
  35 + end
  36 + end
  37 +
  38 + render json: result
  39 + end
  40 +
  41 +end
... ...
controllers/myprofile/proposals_discussion_plugin_tasks_controller.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +class ProposalsDiscussionPluginTasksController < TasksController
  2 +
  3 + def index
  4 + @email_templates = profile.email_templates.find_all_by_template_type(:task_rejection)
  5 +
  6 + @filter_type = params[:filter_type].presence
  7 + @filter_text = params[:filter_text].presence
  8 + @filter_responsible = params[:filter_responsible]
  9 + @filter_tags = params[:filter_tags]
  10 +
  11 + @view_only = !current_person.has_permission?(:perform_task, profile)
  12 +
  13 + @task_tags = [OpenStruct.new(:name => _('All'), :id => nil) ] + Task.all_tags
  14 + @task_types = Task.pending_types_for(profile)
  15 +
  16 + if @view_only
  17 + @tasks = Task.pending_all(profile, false, false).order_by('created_at', 'asc')
  18 + @tasks = @tasks.where(:responsible_id => current_person.id)
  19 + else
  20 +
  21 + @tasks = ProposalsDiscussionPlugin::ProposalTask.pending_evaluated(profile, @filter_type, @filter_text).order_by('created_at', 'asc')
  22 + @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present?
  23 + @tasks = @tasks.tagged_with(@filter_tags, any: true) if @filter_tags.present?
  24 + end
  25 +
  26 + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
  27 +
  28 + @failed = params ? params[:failed] : {}
  29 +
  30 + @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization?
  31 +
  32 +
  33 + end
  34 +
  35 +end
... ...
db/migrate/20150618100000_create_proposal_evaluation_table.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +class CreateProposalEvaluationTable < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :proposals_discussion_plugin_proposal_evaluations do |t|
  4 + t.integer "proposal_task_id"
  5 + t.integer "evaluator_id"
  6 + t.integer "flagged_status"
  7 + t.timestamps
  8 + end
  9 + add_index(
  10 + :proposals_discussion_plugin_proposal_evaluations,
  11 + [:proposal_task_id],
  12 + name: 'index_proposals_discussion_plugin_proposal_task_id'
  13 + )
  14 + add_index(
  15 + :proposals_discussion_plugin_proposal_evaluations,
  16 + [:evaluator_id],
  17 + name: 'index_proposals_discussion_plugin_proposal_evaluator_id'
  18 + )
  19 + end
  20 + def self.down
  21 + drop_table :proposals_discussion_plugin_proposal_evaluations
  22 + end
  23 +end
... ...
lib/proposals_discussion_plugin/proposal_evaluation.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class ProposalsDiscussionPlugin::ProposalEvaluation < Noosfero::Plugin::ActiveRecord
  2 + belongs_to :proposal_task
  3 + belongs_to :evaluated_by, :class_name => 'Person', :foreign_key => :evaluator_id
  4 +
  5 + attr_accessor :flagged_status
  6 +
  7 +end
... ...
lib/proposals_discussion_plugin/proposal_task.rb
... ... @@ -10,6 +10,16 @@ class ProposalsDiscussionPlugin::ProposalTask &lt; Task
10 10 settings_items :article, :type => Hash, :default => {}
11 11 settings_items :closing_statment, :article_parent_id
12 12  
  13 +
  14 + scope :pending_evaluated, lambda { |profile, filter_type, filter_text|
  15 + self
  16 + .to(profile)
  17 + .without_spam.pending
  18 + .of(filter_type)
  19 + .like('data', filter_text)
  20 + .where(:status => ProposalsDiscussionPlugin::ProposalTask::Status.evaluated_statuses)
  21 + }
  22 +
13 23 before_create do |task|
14 24 if !task.target.nil?
15 25 organization = task.target
... ... @@ -18,8 +28,80 @@ class ProposalsDiscussionPlugin::ProposalTask &lt; Task
18 28 end
19 29 end
20 30  
  31 + def unflagged?
  32 + ! flagged?
  33 + end
  34 +
  35 + def flagged?
  36 + flagged_for_approval? || flagged_for_reproval?
  37 + end
  38 +
  39 + def flagged_for_approval?
  40 + Status::FLAGGED_FOR_APPROVAL.eql?(self.status)
  41 + end
  42 +
  43 + def flagged_for_reproval?
  44 + Status::FLAGGED_FOR_REPROVAL.eql?(self.status)
  45 + end
  46 +
21 47 after_create :schedule_spam_checking
22 48  
  49 + module Status
  50 + FLAGGED_FOR_APPROVAL = 5
  51 + FLAGGED_FOR_REPROVAL = 6
  52 +
  53 + class << self
  54 + def names
  55 + [
  56 + nil,
  57 + N_('Active'), N_('Cancelled'), N_('Finished'),
  58 + N_('Hidden'), N_('Flagged for Approval'), N_('Flagged for Reproval')
  59 + ]
  60 + end
  61 +
  62 + def evaluated_statuses
  63 + [
  64 + FLAGGED_FOR_APPROVAL,
  65 + FLAGGED_FOR_REPROVAL
  66 + ]
  67 + end
  68 + end
  69 + end
  70 +
  71 +
  72 + def flag_accept_proposal(evaluated_by)
  73 + transaction do
  74 + if evaluated_by
  75 + ProposalsDiscussionPlugin::ProposalEvaluation.new do |evaluation|
  76 + evaluation.evaluated_by = evaluated_by
  77 + evaluation.flagged_status = Status::FLAGGED_FOR_APPROVAL
  78 + evaluation.proposal_task = self
  79 + evaluation.save!
  80 + end
  81 + end
  82 + self.status = Status::FLAGGED_FOR_APPROVAL
  83 + self.save!
  84 + return true
  85 + end
  86 + end
  87 +
  88 + def flag_reject_proposal(evaluated_by)
  89 + transaction do
  90 + if evaluated_by
  91 + ProposalsDiscussionPlugin::ProposalEvaluation.new do |evaluation|
  92 + evaluation.evaluated_by = evaluated_by
  93 + evaluation.flagged_status = Status::FLAGGED_FOR_REPROVAL
  94 + evaluation.proposal_task = self
  95 + evaluation.save!
  96 + end
  97 + end
  98 + self.status = Status::FLAGGED_FOR_REPROVAL
  99 + self.save!
  100 + return true
  101 + end
  102 + end
  103 +
  104 +
23 105 def schedule_spam_checking
24 106 self.delay.check_for_spam
25 107 end
... ... @@ -65,7 +147,6 @@ class ProposalsDiscussionPlugin::ProposalTask &lt; Task
65 147 article_abstract
66 148 end
67 149  
68   -
69 150 def information
70 151 {:message => _("%{requestor} wants to send the following proposal. <br/>%{abstract}"), :variables => {:abstract => abstract}}
71 152 end
... ... @@ -90,7 +171,7 @@ class ProposalsDiscussionPlugin::ProposalTask &lt; Task
90 171 # def article_title
91 172 # article ? article.title : _('(The original text was removed)')
92 173 # end
93   -
  174 +
94 175 # def article
95 176 # Article.find_by_id data[:article_id]
96 177 # end
... ...
public/images/approval.png 0 → 100644

414 Bytes

public/images/reproval.png 0 → 100644

381 Bytes

public/style.css
... ... @@ -319,3 +319,33 @@ form .proposals-discussion-plugin .body textarea {
319 319 #content .article-body.article-body-proposals-discussion-plugin_proposal .discussion {
320 320 color: gray;
321 321 }
  322 +
  323 +.evaluation_bar {
  324 + width: 400px;
  325 +}
  326 +
  327 +.evaluation_button {
  328 + cursor: pointer;
  329 +}
  330 +
  331 +.evaluation_button img {
  332 + float:left;
  333 + width: 32px;
  334 + height:32px;
  335 + margin-left: 30px;
  336 +}
  337 +
  338 +.evaluation_button span {
  339 + margin-left: 8px;
  340 + font-size: 24px;
  341 + width: auto;
  342 + float:left;
  343 +}
  344 +
  345 +.evaluation_button.approval span {
  346 + color: green;
  347 +}
  348 +
  349 +.evaluation_button.reproval span {
  350 + color: red;
  351 +}
... ...
views/proposals_discussion_plugin_tasks/_task_accept_details.html.erb 0 → 100644
views/proposals_discussion_plugin_tasks/_task_reject_details.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<% if @email_templates.present? %>
  2 + <div class="template-selection">
  3 + <%= labelled_form_field(_('Select a rejection email template:'), select_tag("tasks[#{task.id}][task][email_template_id]", options_from_collection_for_select(@email_templates, :id, :name), :include_blank => true, 'data-url' => url_for(:controller => 'email_templates', :action => 'show_parsed'))) %>
  4 + </div>
  5 +<% end %>
... ...
views/tasks/_task.html.erb 0 → 100644
... ... @@ -0,0 +1,105 @@
  1 +<div class="task_box" id="task-<%= task.id %>">
  2 +
  3 + <%= render :partial => 'task_icon', :locals => {:task => task} %>
  4 +
  5 + <% if !@view_only && profile.organization? && @responsible_candidates.present? %>
  6 + <div class="task_responsible">
  7 + <span class="label"><%= _('Assign to:') %></span>
  8 + <span>
  9 + <% change_responsible_url = url_for :action => :change_responsible, :controller => :tasks %>
  10 + <%= select_tag "tasks[#{task.id}][responsible]", options_from_collection_for_select(@responsible_candidates, :id, :name, task.responsible.present? ? task.responsible.id : nil), :include_blank => true, :onchange => "change_task_responsible(this);", 'data-old-responsible' => task.responsible.present? ? task.responsible.id : nil, 'data-task' => task.id, 'data-url' => change_responsible_url %>
  11 + </span>
  12 + </div>
  13 + <% end %>
  14 +
  15 + <% if @view_only && task.responsible.present? %>
  16 + <div class="task_responsible">
  17 + <span class="label"><%= _('Assigned to:') %></span>
  18 + <span class="value"><%= task.responsible.name %></span>
  19 + </div>
  20 + <% end %>
  21 +
  22 + <div class="task_decisions">
  23 + <% unless @view_only %>
  24 + <%=
  25 + labelled_radio_button(_("Accept"), "tasks[#{task.id}][decision]", 'finish', task.flagged_for_approval? || task.default_decision == 'accept',
  26 + :id => "decision-finish-#{task.id}",
  27 + :class => 'task_accept_radio',
  28 + :disabled => task.accept_disabled?,
  29 + :task_id => "#{task.id}") +
  30 + labelled_radio_button(_("Reject"), "tasks[#{task.id}][decision]", 'cancel', task.flagged_for_reproval? || task.default_decision == 'reject',
  31 + :id => "decision-cancel-#{task.id}",
  32 + :class => 'task_reject_radio',
  33 + :disabled => task.reject_disabled?,
  34 + :task_id => "#{task.id}") +
  35 + labelled_radio_button(_("Skip"), "tasks[#{task.id}][decision]", 'skip', task.default_decision == 'skip' && task.unflagged?,
  36 + :id => "decision-skip-#{task.id}",
  37 + :class => 'task_skip_radio',
  38 + :disabled => task.skip_disabled?,
  39 + :task_id => "#{task.id}")
  40 + %>
  41 + <% end %>
  42 + </div><!-- class="task_decisions" -->
  43 +
  44 + <div class="task_date"><%= show_time(task.created_at) %></div>
  45 +
  46 + <%= render :partial => 'task_title', :locals => {:task => task} %>
  47 +
  48 + <div class="task_information">
  49 + <%= task_information(task) %>
  50 + </div>
  51 +
  52 +
  53 + <%= fields_for "tasks[#{task.id}][task]", task do |f| %>
  54 + <% if task.accept_details and !@view_only %>
  55 + <div id="on-accept-information-<%=task.id%>" style="display: none">
  56 + <%= render :partial => partial_for_class(task.class, nil, :accept_details), :locals => {:task => task, :f => f} %>
  57 + </div>
  58 + <% end %>
  59 +
  60 + <% if task.reject_details and !@view_only %>
  61 + <div id="on-reject-information-<%=task.id%>" style="display: none">
  62 + <%= render :partial => partial_for_class(task.class, nil, :reject_details), :locals => {:task => task, :f => f} %>
  63 + </div>
  64 + <% end %>
  65 +
  66 + <% if @view_only %>
  67 + <div class="evaluation_bar" style="float:right">
  68 + <div class="evaluation_button approval"
  69 + data-url='<%="/myprofile/#{profile.identifier}/plugin/proposals_discussion/evaluate_tasks/flag_approve_proposal"%>'
  70 + data-task-id="<%= task.id %>"
  71 + data-status-id="<%= ProposalsDiscussionPlugin::ProposalTask::Status::FLAGGED_FOR_APPROVAL %>">
  72 + <img class="" src="/plugins/proposals_discussion/images/approval.png">
  73 + <span>Aprovar</span>
  74 + </div>
  75 + <div class="evaluation_button reproval"
  76 + data-url='<%="/myprofile/#{profile.identifier}/plugin/proposals_discussion/evaluate_tasks/flag_reject_proposal"%>'
  77 + data-task-id="<%= task.id %>" data-status-id="<%= ProposalsDiscussionPlugin::ProposalTask::Status::FLAGGED_FOR_REPROVAL %>">
  78 + <img class="" src="/plugins/proposals_discussion/images/reproval.png">
  79 + <span>Reprovar</span>
  80 + </div>
  81 + </div>
  82 + <% end %>
  83 + <%#= select_tag "tasks[#{task.id}][setting][evaluation_flag]",
  84 + options_for_select(
  85 + [_('FLAGGED_FOR_APPROVAL'),_('FLAGGED_FOR_REPROVAL')],(task.flagged_status.present? ? task.flagged_status : nil)
  86 + ),
  87 + {
  88 + :include_blank => true,
  89 + :onchange => "change_flagged_status(this);",
  90 + 'data-old-responsible' => task.flagged_status.present? ? task.flagged_status.id : nil,
  91 + 'data-task' => task.id, 'data-url' => 'change_flagged_status_url'
  92 + } %>
  93 +
  94 +
  95 + <div class="formfieldline">
  96 + <div class="formfield tag-list-fields">
  97 + <%= labelled_text_field(_('Tags'),"tasks[#{task.id}][task][tag_list]", task.tags_from(nil).to_s, :size => 36, :class => 'tag-list','data-submit-values'=>"{'task_id':'#{task.id}'}") %>
  98 + </div>
  99 + </div>
  100 +
  101 +
  102 +
  103 + <% end %>
  104 +
  105 +</div><!-- class="task_box" -->
... ...
views/tasks/index.html.erb 0 → 100644
... ... @@ -0,0 +1,134 @@
  1 +<%= stylesheet_link_tag 'tasks' %>
  2 +
  3 +<h1><%= _("%s's pending tasks") % profile.name %></h1>
  4 +<p>
  5 +
  6 +<%
  7 + type_collection = [[nil, _('All')]] + @task_types
  8 +%>
  9 +
  10 +<% if !@failed.blank? %>
  11 + <div id="errorExplanation">
  12 + <% @failed.each do |error, tasks_descriptions|%>
  13 + <h2> <%= error %></h2>
  14 + <p><%=_("This error happened with the following tasks: ")%></p>
  15 + <ul>
  16 + <% tasks_descriptions.each do |description| %>
  17 + <li> <%= description %> </li>
  18 + <% end %>
  19 + </ul>
  20 + <% end %>
  21 + </div>
  22 +<% end %>
  23 +
  24 +<% unless @view_only %>
  25 + <%= form_tag '#', :method => 'get' do %>
  26 + <%= field_set_tag _('Filter'), :class => 'filter_fields' do %>
  27 + <p>
  28 + <%= labelled_select(_('Type of task')+': ', :filter_type, :first, :last, @filter_type, type_collection, {:id => 'filter-type'}) %>
  29 + </p>
  30 + <p>
  31 + <%= labelled_text_field(_("Text filter")+': ', :filter_text, nil, {:id => 'filter-text',:value => @filter_text}) %>
  32 + </p>
  33 + <% if profile.organization? %>
  34 + <p>
  35 + <%= labelled_select(_('Assigned to')+': ', :filter_responsible, :id, :name, @filter_responsible, [OpenStruct.new(:name => _('All'), :id => nil), OpenStruct.new(:name => _('Unassigned'), :id => -1)] + @responsible_candidates, :class => 'filter_responsible') %>
  36 + </p>
  37 + <% end %>
  38 + <p>
  39 + <%= labelled_select(_('Tags')+': ', :filter_tags, :id, :name, @filter_tags, @task_tags, {:id => 'filter-add-tag'}) %>
  40 + <%= text_field_tag( :filter_tags, @filter_tags, :size => 36, :class => 'filter-tags' ) %>
  41 + </p>
  42 +
  43 + <p>
  44 + <%= submit_button(:search, _('Search')) %>
  45 + </p>
  46 + <% end %>
  47 + <% end %>
  48 +<% end %>
  49 +<% if @tasks.empty? %>
  50 + <p>
  51 + <em><%= _('No pending tasks for %s') % profile.name %></em>
  52 + </p>
  53 +<% else %>
  54 + <%= form_tag :action => 'close' do%>
  55 + <% button_bar(:class => 'task-actions') do %>
  56 + <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
  57 + <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
  58 + <%= submit_button :save, _("Apply!") %>
  59 + <%= button(:edit, _('View processed tasks'), :action => 'processed') %>
  60 + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
  61 + <% end unless @view_only %>
  62 +
  63 + <ul class='task-list'>
  64 + <% unless @view_only %>
  65 + <p>
  66 + <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %>
  67 + </p>
  68 + <% end %>
  69 +
  70 + <div class="task_boxes">
  71 + <%= render :partial => 'task', :collection => @tasks %>
  72 + </div>
  73 +
  74 + <% unless @view_only %>
  75 + <p>
  76 + <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %>
  77 + </p>
  78 + <% end %>
  79 + </ul>
  80 +
  81 + <script>
  82 + jQuery('.tag-list').inputosaurus({
  83 + autoCompleteSource: <%= "'/myprofile/#{profile.identifier}/cms/search_tags'," %>
  84 + activateFinalResult : true
  85 + })
  86 + </script>
  87 +
  88 + <%= pagination_links(@tasks)%>
  89 +
  90 + <% button_bar(:class => 'task-actions') do %>
  91 + <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
  92 + <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
  93 + <%= submit_button :save, _("Apply!") %>
  94 + <%= button(:edit, _('View processed tasks'), :action => 'processed') %>
  95 + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
  96 + <% end unless @view_only %>
  97 + <% end %>
  98 +<% end %>
  99 +</p>
  100 +
  101 +
  102 +<%= javascript_include_tag 'tasks' %>
  103 +
  104 +<script type="text/javascript">
  105 + Task.showTags({
  106 + profileIdentifier: <%= "'#{profile.identifier}'" %>
  107 + })
  108 +
  109 + $('div.evaluation_button').on('click', null, function(){
  110 + evaluate_task(this);
  111 + });
  112 +
  113 + function evaluate_task(el) {
  114 + var url = $(el).data('url');
  115 + var task_id = $(el).data('task-id');
  116 + var params = {
  117 + task_id: task_id,
  118 + flagged_status: $(el).data('status-id')
  119 + };
  120 + var taskElement = $('#task-' + task_id);
  121 + jQuery.post(url , params ,
  122 + function(data) {
  123 + if (data.success) {
  124 + $(el).effect("highlight");
  125 + taskElement.fadeOut();
  126 + } else {
  127 + $(el).effect("highlight", {color: 'red'});
  128 + }
  129 + if (data.notice) {
  130 + display_notice(data.notice);
  131 + }
  132 + });
  133 + }
  134 +</script>
... ...
views/tasks/proposals_discussion_plugin/_proposal_task_accept_details.html.erb
... ... @@ -1,4 +0,0 @@
1   -<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article_parent_id]", task.target, task.article_parent_id) %>
2   -
3   -<%= labelled_form_field _('Comment for author'), f.text_field(:closing_statment, :style => 'width: 488px; height: 30px') %>
4   -