Commit f34aaed3e0f800585fd808bbdee46089d5f3b21a
Exists in
theme-brasil-digital-from-staging
and in
9 other branches
Merge branch 'tasks_text_filter' into stable
Showing
6 changed files
with
111 additions
and
11 deletions
Show diff stats
app/controllers/my_profile/tasks_controller.rb
| @@ -3,9 +3,10 @@ class TasksController < MyProfileController | @@ -3,9 +3,10 @@ class TasksController < MyProfileController | ||
| 3 | protect 'perform_task', :profile | 3 | protect 'perform_task', :profile |
| 4 | 4 | ||
| 5 | def index | 5 | def index |
| 6 | - @filter = params[:filter_type].blank? ? nil : params[:filter_type] | 6 | + @filter_type = params[:filter_type] = params[:filter_type].blank? ? nil : params[:filter_type] |
| 7 | + @filter_text = params[:filter_text].blank? ? nil : params[:filter_text] | ||
| 7 | @task_types = Task.pending_types_for(profile) | 8 | @task_types = Task.pending_types_for(profile) |
| 8 | - @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) | 9 | + @tasks = Task.pending_all(profile,params).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) |
| 9 | @failed = params ? params[:failed] : {} | 10 | @failed = params ? params[:failed] : {} |
| 10 | end | 11 | end |
| 11 | 12 | ||
| @@ -65,4 +66,12 @@ class TasksController < MyProfileController | @@ -65,4 +66,12 @@ class TasksController < MyProfileController | ||
| 65 | @ticket = Ticket.find(:first, :conditions => ['(requestor_id = ? or target_id = ?) and id = ?', profile.id, profile.id, params[:id]]) | 66 | @ticket = Ticket.find(:first, :conditions => ['(requestor_id = ? or target_id = ?) and id = ?', profile.id, profile.id, params[:id]]) |
| 66 | end | 67 | end |
| 67 | 68 | ||
| 69 | + def search_tasks | ||
| 70 | + | ||
| 71 | + params[:filter_type] = params[:filter_type].blank? ? nil : params[:filter_type] | ||
| 72 | + result = Task.pending_all(profile,params) | ||
| 73 | + | ||
| 74 | + render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} } | ||
| 75 | + end | ||
| 76 | + | ||
| 68 | end | 77 | end |
app/models/task.rb
| @@ -239,6 +239,10 @@ class Task < ActiveRecord::Base | @@ -239,6 +239,10 @@ class Task < ActiveRecord::Base | ||
| 239 | scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] } | 239 | scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] } |
| 240 | scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} } | 240 | scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} } |
| 241 | scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} } | 241 | scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} } |
| 242 | + scope :like, ->(field,value) { where("LOWER(#{field}) LIKE ?", "%#{value.downcase}%") if value} | ||
| 243 | + scope :pending_all, ->(profile, params){ | ||
| 244 | + self.to(profile).without_spam.pending.of(params[:filter_type]).like('data', params[:filter_text]) | ||
| 245 | + } | ||
| 242 | 246 | ||
| 243 | scope :to, lambda { |profile| | 247 | scope :to, lambda { |profile| |
| 244 | environment_condition = nil | 248 | environment_condition = nil |
| @@ -250,6 +254,7 @@ class Task < ActiveRecord::Base | @@ -250,6 +254,7 @@ class Task < ActiveRecord::Base | ||
| 250 | { :conditions => [environment_condition, profile_condition].compact.join(' OR ') } | 254 | { :conditions => [environment_condition, profile_condition].compact.join(' OR ') } |
| 251 | } | 255 | } |
| 252 | 256 | ||
| 257 | + | ||
| 253 | def self.pending_types_for(profile) | 258 | def self.pending_types_for(profile) |
| 254 | Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] } | 259 | Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] } |
| 255 | end | 260 | end |
app/views/tasks/index.html.erb
| @@ -21,11 +21,24 @@ | @@ -21,11 +21,24 @@ | ||
| 21 | </div> | 21 | </div> |
| 22 | <% end %> | 22 | <% end %> |
| 23 | 23 | ||
| 24 | +<%= form_tag '#', :method => 'post' do %> | ||
| 25 | + | ||
| 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-autocomplete',:value => @filter_text}) %> | ||
| 32 | + </p> | ||
| 33 | + <p> | ||
| 34 | + <%= submit_button(:search, _('Search')) %> | ||
| 35 | + </p> | ||
| 36 | + <% end %> | ||
| 37 | +<% end %> | ||
| 24 | <% if @tasks.empty? %> | 38 | <% if @tasks.empty? %> |
| 25 | <p> | 39 | <p> |
| 26 | - <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => 'document.location.href = "?filter_type="+this.value')%> | 40 | + <em><%= _('No pending tasks for %s') % profile.name %></em> |
| 27 | </p> | 41 | </p> |
| 28 | - <em><%= _('No pending tasks for %s') % profile.name %></em> | ||
| 29 | <% else %> | 42 | <% else %> |
| 30 | <%= form_tag :action => 'close' do%> | 43 | <%= form_tag :action => 'close' do%> |
| 31 | <% button_bar do %> | 44 | <% button_bar do %> |
| @@ -38,14 +51,14 @@ | @@ -38,14 +51,14 @@ | ||
| 38 | 51 | ||
| 39 | <ul class='task-list'> | 52 | <ul class='task-list'> |
| 40 | <p> | 53 | <p> |
| 41 | - <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => "document.location.href = '?filter_type='+this.value") %> | ||
| 42 | - </p> | ||
| 43 | - <p> | ||
| 44 | <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %> | 54 | <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %> |
| 45 | </p> | 55 | </p> |
| 46 | - <% @tasks.each do |task| %> | ||
| 47 | - <%= render :partial => 'task', :locals => { :task => task } %> | ||
| 48 | - <% end %> | 56 | + |
| 57 | + <div class="task_boxes"> | ||
| 58 | + <% @tasks.each do |task| %> | ||
| 59 | + <%= render :partial => 'task', :locals => { :task => task } %> | ||
| 60 | + <% end %> | ||
| 61 | + </div> | ||
| 49 | <p> | 62 | <p> |
| 50 | <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %> | 63 | <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %> |
| 51 | </p> | 64 | </p> |
public/javascripts/tasks.js
| @@ -45,5 +45,21 @@ | @@ -45,5 +45,21 @@ | ||
| 45 | $('.task_title').css('margin-right', $('.task_decisions').width()+'px'); | 45 | $('.task_title').css('margin-right', $('.task_decisions').width()+'px'); |
| 46 | $('.task_title').css('margin-left', $('.task_arrow').width()+'px'); | 46 | $('.task_title').css('margin-left', $('.task_arrow').width()+'px'); |
| 47 | 47 | ||
| 48 | + //Autocomplete tasks by type | ||
| 49 | + $('#filter-text-autocomplete').autocomplete({ | ||
| 50 | + source:function(request,response){ | ||
| 51 | + $.ajax({ | ||
| 52 | + url:document.location.pathname+'/search_tasks', | ||
| 53 | + dataType:'json', | ||
| 54 | + data:{ | ||
| 55 | + filter_text:request.term, | ||
| 56 | + filter_type:jQuery('#filter-type').val() | ||
| 57 | + }, | ||
| 58 | + success:response | ||
| 59 | + }) | ||
| 60 | + }, | ||
| 61 | + minLength:2 | ||
| 62 | + }); | ||
| 63 | + | ||
| 48 | })(jQuery) | 64 | })(jQuery) |
| 49 | 65 |
public/stylesheets/application.css
| @@ -6726,6 +6726,10 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img { | @@ -6726,6 +6726,10 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img { | ||
| 6726 | 6726 | ||
| 6727 | /* AutoComplete*/ | 6727 | /* AutoComplete*/ |
| 6728 | .formfield input.ui-autocomplete-loading { background: url('/images/loading-small.gif') right center no-repeat, url("../images/input-bg.gif") no-repeat left top; } | 6728 | .formfield input.ui-autocomplete-loading { background: url('/images/loading-small.gif') right center no-repeat, url("../images/input-bg.gif") no-repeat left top; } |
| 6729 | +.ui-autocomplete-loading{ | ||
| 6730 | + background: url('/images/loading-small.gif') right center no-repeat | ||
| 6731 | +} | ||
| 6732 | + | ||
| 6729 | 6733 | ||
| 6730 | .ui-autocomplete-category { | 6734 | .ui-autocomplete-category { |
| 6731 | font-weight: bold; | 6735 | font-weight: bold; |
test/functional/tasks_controller_test.rb
| @@ -5,7 +5,7 @@ class TasksController; def rescue_action(e) raise e end; end | @@ -5,7 +5,7 @@ class TasksController; def rescue_action(e) raise e end; end | ||
| 5 | 5 | ||
| 6 | class TasksControllerTest < ActionController::TestCase | 6 | class TasksControllerTest < ActionController::TestCase |
| 7 | 7 | ||
| 8 | - noosfero_test :profile => 'testuser' | 8 | + noosfero_test :profile => 'testuser' |
| 9 | 9 | ||
| 10 | def setup | 10 | def setup |
| 11 | @controller = TasksController.new | 11 | @controller = TasksController.new |
| @@ -30,6 +30,37 @@ class TasksControllerTest < ActionController::TestCase | @@ -30,6 +30,37 @@ class TasksControllerTest < ActionController::TestCase | ||
| 30 | assert assigns(:tasks) | 30 | assert assigns(:tasks) |
| 31 | end | 31 | end |
| 32 | 32 | ||
| 33 | + should 'get filtered tasks to autocomplete text field' do | ||
| 34 | + | ||
| 35 | + #Create a admin user and a simple user | ||
| 36 | + profile_admin = create_user('admin_tester').person | ||
| 37 | + Environment.default.add_admin(profile_admin) | ||
| 38 | + user = fast_create(Person,:name => 'FakeUser') | ||
| 39 | + | ||
| 40 | + #Create a task of type 'ModerateUserRegistration' | ||
| 41 | + task_data = { | ||
| 42 | + :target => Environment.default, | ||
| 43 | + :spam => false, | ||
| 44 | + :data => {:user_id => user.id,:name => user.name} | ||
| 45 | + } | ||
| 46 | + ModerateUserRegistration.create!(task_data) | ||
| 47 | + | ||
| 48 | + #Use admin user to your profile with a pending task above | ||
| 49 | + @controller.stubs(:profile).returns(profile_admin) | ||
| 50 | + login_as profile_admin.identifier | ||
| 51 | + | ||
| 52 | + #Perform a http request to 'search_task' action with params | ||
| 53 | + post :search_tasks, :filter_type =>'ModerateUserRegistration', :filter_text => 'Fak' | ||
| 54 | + | ||
| 55 | + assert_response :success | ||
| 56 | + | ||
| 57 | + #Check if json response matches with a 'FakeUser' | ||
| 58 | + json_response = ActiveSupport::JSON.decode(@response.body) | ||
| 59 | + value = json_response[0]['value'] | ||
| 60 | + | ||
| 61 | + assert_equal value, 'FakeUser' | ||
| 62 | + end | ||
| 63 | + | ||
| 33 | should 'list pending tasks without spam' do | 64 | should 'list pending tasks without spam' do |
| 34 | requestor = fast_create(Person) | 65 | requestor = fast_create(Person) |
| 35 | task_spam = Task.create!(:requestor => requestor, :target => profile, :spam => true) | 66 | task_spam = Task.create!(:requestor => requestor, :target => profile, :spam => true) |
| @@ -346,6 +377,28 @@ class TasksControllerTest < ActionController::TestCase | @@ -346,6 +377,28 @@ class TasksControllerTest < ActionController::TestCase | ||
| 346 | assert_includes assigns(:tasks), t3 | 377 | assert_includes assigns(:tasks), t3 |
| 347 | end | 378 | end |
| 348 | 379 | ||
| 380 | + should 'filter tasks by type and data content' do | ||
| 381 | + class CleanHouse < Task; end | ||
| 382 | + class FeedDog < Task; end | ||
| 383 | + Task.stubs(:per_page).returns(3) | ||
| 384 | + requestor = fast_create(Person) | ||
| 385 | + t1 = CleanHouse.create!(:requestor => requestor, :target => profile, :data => {:name => 'Task Test'}) | ||
| 386 | + t2 = CleanHouse.create!(:requestor => requestor, :target => profile) | ||
| 387 | + t3 = FeedDog.create!(:requestor => requestor, :target => profile) | ||
| 388 | + | ||
| 389 | + post :index, :filter_type => t1.type, :filter_text => 'test' | ||
| 390 | + | ||
| 391 | + assert_includes assigns(:tasks), t1 | ||
| 392 | + assert_not_includes assigns(:tasks), t2 | ||
| 393 | + assert_not_includes assigns(:tasks), t3 | ||
| 394 | + | ||
| 395 | + post :index | ||
| 396 | + | ||
| 397 | + assert_includes assigns(:tasks), t1 | ||
| 398 | + assert_includes assigns(:tasks), t2 | ||
| 399 | + assert_includes assigns(:tasks), t3 | ||
| 400 | + end | ||
| 401 | + | ||
| 349 | should 'return tasks ordered accordingly and limited by pages' do | 402 | should 'return tasks ordered accordingly and limited by pages' do |
| 350 | time = Time.now | 403 | time = Time.now |
| 351 | person = fast_create(Person) | 404 | person = fast_create(Person) |