diff --git a/controllers/myprofile/proposals_discussion_plugin_evaluate_tasks_controller.rb b/controllers/myprofile/proposals_discussion_plugin_evaluate_tasks_controller.rb new file mode 100644 index 0000000..1c8d394 --- /dev/null +++ b/controllers/myprofile/proposals_discussion_plugin_evaluate_tasks_controller.rb @@ -0,0 +1,41 @@ +class ProposalsDiscussionPluginEvaluateTasksController < MyProfileController + + protect :view_tasks, :profile, :only => [:flag_approve_proposal, :flag_reject_proposal] + + def flag_approve_proposal + if request.post? && params[:task_id] + result = { + success: false, + message: _('Error flagging proposal. Please, contact the system admin') + } + + task = Task.to(profile).find_by_id params[:task_id] + save = task.flag_accept_proposal(current_person) + + if save + result = {:success => true } + end + end + + render json: result + end + + def flag_reject_proposal + if request.post? && params[:task_id] + result = { + success: false, + message: _('Error flagging proposal. Please, contact the system admin') + } + + task = Task.to(profile).find_by_id params[:task_id] + save = task.flag_reject_proposal(current_person) + + if save + result = {:success => true } + end + end + + render json: result + end + +end diff --git a/controllers/myprofile/proposals_discussion_plugin_tasks_controller.rb b/controllers/myprofile/proposals_discussion_plugin_tasks_controller.rb new file mode 100644 index 0000000..0f434eb --- /dev/null +++ b/controllers/myprofile/proposals_discussion_plugin_tasks_controller.rb @@ -0,0 +1,35 @@ +class ProposalsDiscussionPluginTasksController < TasksController + + def index + @email_templates = profile.email_templates.find_all_by_template_type(:task_rejection) + + @filter_type = params[:filter_type].presence + @filter_text = params[:filter_text].presence + @filter_responsible = params[:filter_responsible] + @filter_tags = params[:filter_tags] + + @view_only = !current_person.has_permission?(:perform_task, profile) + + @task_tags = [OpenStruct.new(:name => _('All'), :id => nil) ] + Task.all_tags + @task_types = Task.pending_types_for(profile) + + if @view_only + @tasks = Task.pending_all(profile, false, false).order_by('created_at', 'asc') + @tasks = @tasks.where(:responsible_id => current_person.id) + else + + @tasks = ProposalsDiscussionPlugin::ProposalTask.pending_evaluated(profile, @filter_type, @filter_text).order_by('created_at', 'asc') + @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present? + @tasks = @tasks.tagged_with(@filter_tags, any: true) if @filter_tags.present? + end + + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) + + @failed = params ? params[:failed] : {} + + @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization? + + + end + +end diff --git a/db/migrate/20150618100000_create_proposal_evaluation_table.rb b/db/migrate/20150618100000_create_proposal_evaluation_table.rb new file mode 100644 index 0000000..0e95fdb --- /dev/null +++ b/db/migrate/20150618100000_create_proposal_evaluation_table.rb @@ -0,0 +1,23 @@ +class CreateProposalEvaluationTable < ActiveRecord::Migration + def self.up + create_table :proposals_discussion_plugin_proposal_evaluations do |t| + t.integer "proposal_task_id" + t.integer "evaluator_id" + t.integer "flagged_status" + t.timestamps + end + add_index( + :proposals_discussion_plugin_proposal_evaluations, + [:proposal_task_id], + name: 'index_proposals_discussion_plugin_proposal_task_id' + ) + add_index( + :proposals_discussion_plugin_proposal_evaluations, + [:evaluator_id], + name: 'index_proposals_discussion_plugin_proposal_evaluator_id' + ) + end + def self.down + drop_table :proposals_discussion_plugin_proposal_evaluations + end +end diff --git a/lib/proposals_discussion_plugin/proposal_evaluation.rb b/lib/proposals_discussion_plugin/proposal_evaluation.rb new file mode 100644 index 0000000..cb78e10 --- /dev/null +++ b/lib/proposals_discussion_plugin/proposal_evaluation.rb @@ -0,0 +1,7 @@ +class ProposalsDiscussionPlugin::ProposalEvaluation < Noosfero::Plugin::ActiveRecord + belongs_to :proposal_task + belongs_to :evaluated_by, :class_name => 'Person', :foreign_key => :evaluator_id + + attr_accessor :flagged_status + +end diff --git a/lib/proposals_discussion_plugin/proposal_task.rb b/lib/proposals_discussion_plugin/proposal_task.rb index 3270786..bfbe558 100644 --- a/lib/proposals_discussion_plugin/proposal_task.rb +++ b/lib/proposals_discussion_plugin/proposal_task.rb @@ -10,6 +10,16 @@ class ProposalsDiscussionPlugin::ProposalTask < Task settings_items :article, :type => Hash, :default => {} settings_items :closing_statment, :article_parent_id + + scope :pending_evaluated, lambda { |profile, filter_type, filter_text| + self + .to(profile) + .without_spam.pending + .of(filter_type) + .like('data', filter_text) + .where(:status => ProposalsDiscussionPlugin::ProposalTask::Status.evaluated_statuses) + } + before_create do |task| if !task.target.nil? organization = task.target @@ -18,8 +28,80 @@ class ProposalsDiscussionPlugin::ProposalTask < Task end end + def unflagged? + ! flagged? + end + + def flagged? + flagged_for_approval? || flagged_for_reproval? + end + + def flagged_for_approval? + Status::FLAGGED_FOR_APPROVAL.eql?(self.status) + end + + def flagged_for_reproval? + Status::FLAGGED_FOR_REPROVAL.eql?(self.status) + end + after_create :schedule_spam_checking + module Status + FLAGGED_FOR_APPROVAL = 5 + FLAGGED_FOR_REPROVAL = 6 + + class << self + def names + [ + nil, + N_('Active'), N_('Cancelled'), N_('Finished'), + N_('Hidden'), N_('Flagged for Approval'), N_('Flagged for Reproval') + ] + end + + def evaluated_statuses + [ + FLAGGED_FOR_APPROVAL, + FLAGGED_FOR_REPROVAL + ] + end + end + end + + + def flag_accept_proposal(evaluated_by) + transaction do + if evaluated_by + ProposalsDiscussionPlugin::ProposalEvaluation.new do |evaluation| + evaluation.evaluated_by = evaluated_by + evaluation.flagged_status = Status::FLAGGED_FOR_APPROVAL + evaluation.proposal_task = self + evaluation.save! + end + end + self.status = Status::FLAGGED_FOR_APPROVAL + self.save! + return true + end + end + + def flag_reject_proposal(evaluated_by) + transaction do + if evaluated_by + ProposalsDiscussionPlugin::ProposalEvaluation.new do |evaluation| + evaluation.evaluated_by = evaluated_by + evaluation.flagged_status = Status::FLAGGED_FOR_REPROVAL + evaluation.proposal_task = self + evaluation.save! + end + end + self.status = Status::FLAGGED_FOR_REPROVAL + self.save! + return true + end + end + + def schedule_spam_checking self.delay.check_for_spam end @@ -65,7 +147,6 @@ class ProposalsDiscussionPlugin::ProposalTask < Task article_abstract end - def information {:message => _("%{requestor} wants to send the following proposal.
%{abstract}"), :variables => {:abstract => abstract}} end @@ -90,7 +171,7 @@ class ProposalsDiscussionPlugin::ProposalTask < Task # def article_title # article ? article.title : _('(The original text was removed)') # end - + # def article # Article.find_by_id data[:article_id] # end diff --git a/public/images/approval.png b/public/images/approval.png new file mode 100644 index 0000000..be13a3e Binary files /dev/null and b/public/images/approval.png differ diff --git a/public/images/reproval.png b/public/images/reproval.png new file mode 100644 index 0000000..bab6f37 Binary files /dev/null and b/public/images/reproval.png differ diff --git a/public/style.css b/public/style.css index 9d0e302..642def4 100644 --- a/public/style.css +++ b/public/style.css @@ -319,3 +319,33 @@ form .proposals-discussion-plugin .body textarea { #content .article-body.article-body-proposals-discussion-plugin_proposal .discussion { color: gray; } + +.evaluation_bar { + width: 400px; +} + +.evaluation_button { + cursor: pointer; +} + +.evaluation_button img { + float:left; + width: 32px; + height:32px; + margin-left: 30px; +} + +.evaluation_button span { + margin-left: 8px; + font-size: 24px; + width: auto; + float:left; +} + +.evaluation_button.approval span { + color: green; +} + +.evaluation_button.reproval span { + color: red; +} diff --git a/views/proposals_discussion_plugin_tasks/_task_accept_details.html.erb b/views/proposals_discussion_plugin_tasks/_task_accept_details.html.erb new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/views/proposals_discussion_plugin_tasks/_task_accept_details.html.erb diff --git a/views/proposals_discussion_plugin_tasks/_task_reject_details.html.erb b/views/proposals_discussion_plugin_tasks/_task_reject_details.html.erb new file mode 100644 index 0000000..6a0452c --- /dev/null +++ b/views/proposals_discussion_plugin_tasks/_task_reject_details.html.erb @@ -0,0 +1,5 @@ +<% if @email_templates.present? %> +
+ <%= 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'))) %> +
+<% end %> diff --git a/views/tasks/_task.html.erb b/views/tasks/_task.html.erb new file mode 100644 index 0000000..317049f --- /dev/null +++ b/views/tasks/_task.html.erb @@ -0,0 +1,105 @@ +
+ + <%= render :partial => 'task_icon', :locals => {:task => task} %> + + <% if !@view_only && profile.organization? && @responsible_candidates.present? %> +
+ <%= _('Assign to:') %> + + <% change_responsible_url = url_for :action => :change_responsible, :controller => :tasks %> + <%= 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 %> + +
+ <% end %> + + <% if @view_only && task.responsible.present? %> +
+ <%= _('Assigned to:') %> + <%= task.responsible.name %> +
+ <% end %> + +
+ <% unless @view_only %> + <%= + labelled_radio_button(_("Accept"), "tasks[#{task.id}][decision]", 'finish', task.flagged_for_approval? || task.default_decision == 'accept', + :id => "decision-finish-#{task.id}", + :class => 'task_accept_radio', + :disabled => task.accept_disabled?, + :task_id => "#{task.id}") + + labelled_radio_button(_("Reject"), "tasks[#{task.id}][decision]", 'cancel', task.flagged_for_reproval? || task.default_decision == 'reject', + :id => "decision-cancel-#{task.id}", + :class => 'task_reject_radio', + :disabled => task.reject_disabled?, + :task_id => "#{task.id}") + + labelled_radio_button(_("Skip"), "tasks[#{task.id}][decision]", 'skip', task.default_decision == 'skip' && task.unflagged?, + :id => "decision-skip-#{task.id}", + :class => 'task_skip_radio', + :disabled => task.skip_disabled?, + :task_id => "#{task.id}") + %> + <% end %> +
+ +
<%= show_time(task.created_at) %>
+ + <%= render :partial => 'task_title', :locals => {:task => task} %> + +
+ <%= task_information(task) %> +
+ + + <%= fields_for "tasks[#{task.id}][task]", task do |f| %> + <% if task.accept_details and !@view_only %> + + <% end %> + + <% if task.reject_details and !@view_only %> + + <% end %> + + <% if @view_only %> +
+
+ + Aprovar +
+
+ + Reprovar +
+
+ <% end %> + <%#= select_tag "tasks[#{task.id}][setting][evaluation_flag]", + options_for_select( + [_('FLAGGED_FOR_APPROVAL'),_('FLAGGED_FOR_REPROVAL')],(task.flagged_status.present? ? task.flagged_status : nil) + ), + { + :include_blank => true, + :onchange => "change_flagged_status(this);", + 'data-old-responsible' => task.flagged_status.present? ? task.flagged_status.id : nil, + 'data-task' => task.id, 'data-url' => 'change_flagged_status_url' + } %> + + +
+
+ <%= 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}'}") %> +
+
+ + + + <% end %> + +
diff --git a/views/tasks/index.html.erb b/views/tasks/index.html.erb new file mode 100644 index 0000000..c21fe8e --- /dev/null +++ b/views/tasks/index.html.erb @@ -0,0 +1,134 @@ +<%= stylesheet_link_tag 'tasks' %> + +

<%= _("%s's pending tasks") % profile.name %>

+

+ +<% + type_collection = [[nil, _('All')]] + @task_types +%> + +<% if !@failed.blank? %> +

+ <% @failed.each do |error, tasks_descriptions|%> +

<%= error %>

+

<%=_("This error happened with the following tasks: ")%>

+ + <% end %> +
+<% end %> + +<% unless @view_only %> + <%= form_tag '#', :method => 'get' do %> + <%= field_set_tag _('Filter'), :class => 'filter_fields' do %> +

+ <%= labelled_select(_('Type of task')+': ', :filter_type, :first, :last, @filter_type, type_collection, {:id => 'filter-type'}) %> +

+

+ <%= labelled_text_field(_("Text filter")+': ', :filter_text, nil, {:id => 'filter-text',:value => @filter_text}) %> +

+ <% if profile.organization? %> +

+ <%= 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') %> +

+ <% end %> +

+ <%= labelled_select(_('Tags')+': ', :filter_tags, :id, :name, @filter_tags, @task_tags, {:id => 'filter-add-tag'}) %> + <%= text_field_tag( :filter_tags, @filter_tags, :size => 36, :class => 'filter-tags' ) %> +

+ +

+ <%= submit_button(:search, _('Search')) %> +

+ <% end %> + <% end %> +<% end %> +<% if @tasks.empty? %> +

+ <%= _('No pending tasks for %s') % profile.name %> +

+<% else %> + <%= form_tag :action => 'close' do%> + <% button_bar(:class => 'task-actions') do %> + <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %> + <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %> + <%= submit_button :save, _("Apply!") %> + <%= button(:edit, _('View processed tasks'), :action => 'processed') %> + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> + <% end unless @view_only %> + + + + + + <%= pagination_links(@tasks)%> + + <% button_bar(:class => 'task-actions') do %> + <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %> + <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %> + <%= submit_button :save, _("Apply!") %> + <%= button(:edit, _('View processed tasks'), :action => 'processed') %> + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> + <% end unless @view_only %> + <% end %> +<% end %> +

+ + +<%= javascript_include_tag 'tasks' %> + + diff --git a/views/tasks/proposals_discussion_plugin/_proposal_task_accept_details.html.erb b/views/tasks/proposals_discussion_plugin/_proposal_task_accept_details.html.erb deleted file mode 100644 index f26767f..0000000 --- a/views/tasks/proposals_discussion_plugin/_proposal_task_accept_details.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%= 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) %> - -<%= labelled_form_field _('Comment for author'), f.text_field(:closing_statment, :style => 'width: 488px; height: 30px') %> - -- libgit2 0.21.2