Commit 379c7653ce0811cd24764d036cb839bb76c61c5e

Authored by Leandro Santos
2 parents d555951e f5aeac9a

fix conflit with task_taggable branch

app/controllers/my_profile/tasks_controller.rb
1 1 class TasksController < MyProfileController
2 2  
3   - protect [:perform_task, :view_tasks], :profile, :only => [:index]
4   - protect :perform_task, :profile, :except => [:index]
  3 + protect [:perform_task, :view_tasks], :profile, :only => [:index, :save_tags, :search_tags]
  4 + protect :perform_task, :profile, :except => [:index, :save_tags, :search_tags]
5 5  
6 6 def index
7 7 @filter_type = params[:filter_type].presence
8 8 @filter_text = params[:filter_text].presence
9 9 @filter_responsible = params[:filter_responsible]
  10 + @filter_tags = params[:filter_tags]
  11 +
10 12 @task_types = Task.pending_types_for(profile)
  13 + @task_tags = [OpenStruct.new(:name => _('All'), :id => nil) ] + Task.all_tags
11 14  
12 15 @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc')
13 16 @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present?
  17 + @tasks = @tasks.tagged_with(@filter_tags, any: true) if @filter_tags.present?
14 18 @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
15 19  
16 20 @failed = params ? params[:failed] : {}
... ... @@ -112,4 +116,36 @@ class TasksController &lt; MyProfileController
112 116 render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} }
113 117 end
114 118  
  119 + def save_tags
  120 +
  121 + if request.post? && params[:tag_list]
  122 + result = {
  123 + success: false,
  124 + message: _('Error to save tags. Please, contact the system admin')
  125 + }
  126 +
  127 + ActsAsTaggableOn.remove_unused_tags = true
  128 +
  129 + task = profile.tasks.find_by_id params[:task_id]
  130 + save = user.tag(task, with: params[:tag_list], on: :tags)
  131 +
  132 + if save
  133 + result[:success] = true
  134 + end
  135 + end
  136 +
  137 + render json: result
  138 + end
  139 +
  140 + #FIXME make this test
  141 + # Should not search for article tasks
  142 + # Should not search for other profile tags
  143 + # Should search only task tags
  144 + # Should check the permissions
  145 + def search_tags
  146 + arg = params[:term].downcase
  147 + result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
  148 + render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json'
  149 + end
  150 +
115 151 end
... ...
app/models/person.rb
... ... @@ -16,6 +16,8 @@ class Person &lt; Profile
16 16 acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)}
17 17 acts_as_accessor
18 18  
  19 + acts_as_tagger
  20 +
19 21 scope :members_of, lambda { |resources|
20 22 resources = [resources] if !resources.kind_of?(Array)
21 23 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ')
... ...
app/views/tasks/_task.html.erb
... ... @@ -64,7 +64,7 @@
64 64  
65 65 <div class="formfieldline">
66 66 <div class="formfield tag-list-fields">
67   - <%= labelled_text_field(_('Tags'),"tasks[#{task.id}][task][tag_list]", task.tag_list.to_s, :size => 36, :class => 'tag-list') %>
  67 + <%= 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}'}") %>
68 68 </div>
69 69 </div>
70 70  
... ...
app/views/tasks/index.html.erb
... ... @@ -35,6 +35,11 @@
35 35 </p>
36 36 <% end %>
37 37 <p>
  38 + <%= labelled_select(_('Tags')+': ', :filter_tags, :id, :name, @filter_tags, @task_tags, {:id => 'filter-add-tag'}) %>
  39 + <%= text_field_tag( :filter_tags, @filter_tags, :size => 36, :class => 'filter-tags' ) %>
  40 + </p>
  41 +
  42 + <p>
38 43 <%= submit_button(:search, _('Search')) %>
39 44 </p>
40 45 <% end %>
... ... @@ -94,3 +99,55 @@
94 99  
95 100  
96 101 <%= javascript_include_tag 'tasks' %>
  102 +
  103 +<script type="text/javascript">
  104 +
  105 + jQuery('.filter-tags').inputosaurus({
  106 + hideInput: true
  107 + });
  108 +
  109 + $('#filter-add-tag').change(function(){
  110 +
  111 + if($(this).val() != ''){
  112 + jQuery('.filter-tags').inputosaurus('addTags',$(this).children(':selected').text());
  113 + }
  114 + });
  115 +
  116 + jQuery('.tag-list').inputosaurus({
  117 + autoCompleteSource: <%= "'/myprofile/#{profile.identifier}/tasks/search_tags'," %>
  118 + activateFinalResult: true,
  119 + submitTags: {
  120 + url: <%= "'/myprofile/#{profile.identifier}/tasks/save_tags'" %>,
  121 + beforeSend: function(){
  122 + this.element.parents('.task_box')
  123 + .prev('.fg-state-error')
  124 + .remove();
  125 + },
  126 + success: function(response){
  127 +
  128 + this.element.parents('.task_box')
  129 + .prev('.fg-state-error')
  130 + .remove();
  131 +
  132 + if(!response.success){
  133 +
  134 + var errorIcon = $('<span/>',{
  135 + 'class':'ui-icon ui-icon-alert',
  136 + style:'float: left; margin-right: .3em;'
  137 + });
  138 +
  139 + var content = $('<p/>',{
  140 + html:'<strong>'+response.message+'</strong>'
  141 + }).prepend(errorIcon);
  142 +
  143 + var div = $('<div/>',{
  144 + 'class':'alert fg-state-error ui-state-error'
  145 + }).append(content);
  146 +
  147 + this.element.parents('.task_box').before(div);
  148 + }
  149 +
  150 + }
  151 + }
  152 + })
  153 +</script>
... ...
public/javascripts/inputosaurus.js
1 1 /**
2   - * Inputosaurus Text
  2 + * Inputosaurus Text
3 3 *
4 4 * Must be instantiated on an <input> element
5 5 * Allows multiple input items. Each item is represented with a removable tag that appears to be inside the input area.
... ... @@ -30,7 +30,7 @@
30 30 //
31 31 // 'change' - triggered whenever a tag is added or removed (should be similar to binding the the change event of the instantiated input
32 32 // 'keyup' - keyup event on the newly created input
33   -
  33 +
34 34 // while typing, the user can separate values using these delimiters
35 35 // the value tags are created on the fly when an inputDelimiter is detected
36 36 inputDelimiters : [',', ';'],
... ... @@ -56,12 +56,18 @@
56 56 // manipulate and return the input value after parseInput() parsing
57 57 // the array of tag names is passed and expected to be returned as an array after manipulation
58 58 parseHook : null,
59   -
  59 +
60 60 // define a placeholder to display when the input is empty
61 61 placeholder: null,
62   -
  62 +
63 63 // when you check for duplicates it check for the case
64   - caseSensitiveDuplicates: false
  64 + caseSensitiveDuplicates: false,
  65 +
  66 + //Hide input to inform tags. This is cool when you create tags from another way
  67 + hideInput: false,
  68 +
  69 + //Ajax options to send tags
  70 + submitTags: null
65 71 },
66 72  
67 73 _create: function() {
... ... @@ -69,7 +75,7 @@
69 75 els = {},
70 76 o = widget.options,
71 77 placeholder = o.placeholder || this.element.attr('placeholder') || null;
72   -
  78 +
73 79 this._chosenValues = [];
74 80  
75 81 // Create the elements
... ... @@ -77,11 +83,11 @@
77 83 els.input = $('<input type="text" />');
78 84 els.inputCont = $('<li class="inputosaurus-input inputosaurus-required"></li>');
79 85 els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required">');
80   -
  86 +
81 87 // define starting placeholder
82   - if (placeholder) {
  88 + if (placeholder) {
83 89 o.placeholder = placeholder;
84   - els.input.attr('placeholder', o.placeholder);
  90 + els.input.attr('placeholder', o.placeholder);
85 91 if (o.width) {
86 92 els.input.css('min-width', o.width - 50);
87 93 }
... ... @@ -90,11 +96,11 @@
90 96 o.wrapperElement && o.wrapperElement.append(els.ul);
91 97 this.element.replaceWith(o.wrapperElement || els.ul);
92 98 els.origInputCont.append(this.element).hide();
93   -
  99 +
94 100 els.inputCont.append(els.input);
95 101 els.ul.append(els.inputCont);
96 102 els.ul.append(els.origInputCont);
97   -
  103 +
98 104 o.width && els.ul.css('width', o.width);
99 105  
100 106 this.elements = els;
... ... @@ -130,8 +136,8 @@
130 136 var auto = $(this).data('ui-autocomplete') || $(this).data('autocomplete');
131 137 var menu = auto.menu,
132 138 $menuItems;
133   -
134   -
  139 +
  140 +
135 141 // zIndex will force the element on top of anything (like a dialog it's in)
136 142 menu.element.zIndex && menu.element.zIndex($(this).zIndex() + 1);
137 143 menu.element.width(widget.elements.ul.outerWidth());
... ... @@ -201,6 +207,31 @@
201 207 widget._resetPlaceholder();
202 208 },
203 209  
  210 + addTags: function(list){
  211 +
  212 + if(arguments.length == 1){
  213 + list = [list];
  214 + }
  215 +
  216 + if(arguments[1]){
  217 + list = Array.prototype.slice.call(arguments);
  218 + }
  219 +
  220 + if(!$.isArray(list)){
  221 + var msg = 'Tag list needs be an Array';
  222 +
  223 + if(console){
  224 + console.error(msg);
  225 +
  226 + return false;
  227 + }else{
  228 + throw new Error(msg);
  229 + }
  230 +
  231 + }
  232 + this._setChosen(list);
  233 + },
  234 +
204 235 _inputFocus : function(ev) {
205 236 var widget = ev.data.widget || this;
206 237  
... ... @@ -241,7 +272,7 @@
241 272  
242 273 widget.elements.input.width(txtWidth < maxWidth ? txtWidth : maxWidth);
243 274 },
244   -
  275 +
245 276 // resets placeholder on representative input
246 277 _resetPlaceholder: function () {
247 278 var placeholder = this.options.placeholder,
... ... @@ -266,7 +297,7 @@
266 297 ev.preventDefault();
267 298 lastTag.find('a').focus();
268 299 }
269   -
  300 +
270 301 },
271 302  
272 303 _editTag : function(ev) {
... ... @@ -285,6 +316,7 @@
285 316 v.key === tagKey && (tagName = v.value);
286 317 });
287 318  
  319 + widget.beforeEditValue = widget.element.val();
288 320 widget.elements.input.val(tagName);
289 321  
290 322 widget._removeTag(ev);
... ... @@ -295,7 +327,7 @@
295 327 var widget = ev.data.widget;
296 328 switch(ev.which){
297 329  
298   - case $.ui.keyCode.BACKSPACE:
  330 + case $.ui.keyCode.BACKSPACE:
299 331 ev && ev.preventDefault();
300 332 ev && ev.stopPropagation();
301 333 $(ev.currentTarget).trigger('click');
... ... @@ -395,6 +427,10 @@
395 427 }
396 428 });
397 429 self._setValue(self._buildValue());
  430 +
  431 + if(this.options.hideInput){
  432 + this.elements.input.parent().hide();
  433 + }
398 434 },
399 435  
400 436 _buildValue : function() {
... ... @@ -409,11 +445,18 @@
409 445 },
410 446  
411 447 _setValue : function(value) {
412   - var val = this.element.val();
  448 +
  449 + if(arguments[1] && (arguments[1].type == 'dblclick' && value == '')){
  450 + return false;
  451 + }
  452 + var val = this.element.val().replace(/,\s*/g,',');
413 453  
414 454 if(val !== value){
415 455 this.element.val(value);
416 456 this._trigger('change');
  457 + if($.isPlainObject(this.options.submitTags)){
  458 + this._sendTags();
  459 + }
417 460 }
418 461 },
419 462  
... ... @@ -439,7 +482,7 @@
439 482 },
440 483  
441 484 _removeTag : function(ev) {
442   - var $closest = $(ev.currentTarget).closest('li'),
  485 + var $closest = $(ev.currentTarget).closest('li'),
443 486 key = $closest.data('ui-inputosaurus') || $closest.data('inputosaurus'),
444 487 indexFound = false,
445 488 widget = (ev && ev.data.widget) || this;
... ... @@ -453,7 +496,7 @@
453 496  
454 497 indexFound !== false && widget._chosenValues.splice(indexFound, 1);
455 498  
456   - widget._setValue(widget._buildValue());
  499 + widget._setValue(widget._buildValue(),ev);
457 500  
458 501 $(ev.currentTarget).closest('li').remove();
459 502 widget.elements.input.focus();
... ... @@ -477,7 +520,7 @@
477 520 var delim = this.options.outputDelimiter,
478 521 val = this.element.val(),
479 522 values = [];
480   -
  523 +
481 524 values.push(val);
482 525 delim && (values = val.split(delim));
483 526  
... ... @@ -515,9 +558,38 @@
515 558  
516 559 this.elements.ul.replaceWith(this.element);
517 560  
  561 + },
  562 +
  563 + _sendTags: function(){
  564 +
  565 + var requestTags = this.options.submitTags;
  566 + if(this.element.val() != '' && this.beforeEditValue != this.element.val()) {
  567 +
  568 + opts = $.extend({
  569 + url: requestTags.url,
  570 + dataType: 'json',
  571 + data:{},
  572 + type:'POST',
  573 + context:this
  574 + },requestTags);
  575 +
  576 + var extraValues = this.element.data('submit-values');
  577 + if(typeof extraValues == 'string' && /\{*/.test(extraValues)){
  578 + extraValues = $.parseJSON(extraValues.replace(/\'/g,'\"'));
  579 + }
  580 +
  581 + if(!$.isEmptyObject(extraValues)){
  582 + for(v in extraValues){
  583 + opts.data[v] = extraValues[v];
  584 + }
  585 + }
  586 +
  587 + opts.data.tag_list = this.element.val();
  588 +
  589 + $.ajax(opts);
  590 + }
518 591 }
519 592 };
520 593  
521 594 $.widget("ui.inputosaurus", inputosaurustext);
522   -})(jQuery);
523   -
  595 +})($ || jQuery);
... ...
test/functional/tasks_controller_test.rb
... ... @@ -12,14 +12,14 @@ class TasksControllerTest &lt; ActionController::TestCase
12 12 @request = ActionController::TestRequest.new
13 13 @response = ActionController::TestResponse.new
14 14  
15   - self.profile = create_user('testuser').person
16   - @controller.stubs(:profile).returns(profile)
  15 + @person = create_user('testuser').person
  16 + @controller.stubs(:profile).returns(@person)
17 17 login_as 'testuser'
18 18 end
19   - attr_accessor :profile
  19 + attr_accessor :person
20 20  
21 21 def assert_redirected_to(options)
22   - super({ :controller => 'tasks', :profile => profile.identifier }.merge(options))
  22 + super({ :controller => 'tasks', :profile => person.identifier }.merge(options))
23 23 end
24 24  
25 25 should 'list pending tasks' do
... ... @@ -63,8 +63,8 @@ class TasksControllerTest &lt; ActionController::TestCase
63 63  
64 64 should 'list pending tasks without spam' do
65 65 requestor = fast_create(Person)
66   - task_spam = Task.create!(:requestor => requestor, :target => profile, :spam => true)
67   - task_ham = Task.create!(:requestor => requestor, :target => profile, :spam => false)
  66 + task_spam = Task.create!(:requestor => requestor, :target => person, :spam => true)
  67 + task_ham = Task.create!(:requestor => requestor, :target => person, :spam => false)
68 68  
69 69 get :index
70 70 assert_response :success
... ... @@ -81,15 +81,15 @@ class TasksControllerTest &lt; ActionController::TestCase
81 81 end
82 82  
83 83 should 'display task created_at' do
84   - Task.create!(:requestor => fast_create(Person), :target => profile, :spam => false)
  84 + Task.create!(:requestor => fast_create(Person), :target => person, :spam => false)
85 85 get :index
86 86 assert_select '.task_date'
87 87 end
88 88  
89 89 should 'list processed tasks without spam' do
90 90 requestor = fast_create(Person)
91   - task_spam = create(Task, :status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :spam => true)
92   - task_ham = create(Task, :status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :spam => false)
  91 + task_spam = create(Task, :status => Task::Status::FINISHED, :requestor => requestor, :target => person, :spam => true)
  92 + task_ham = create(Task, :status => Task::Status::FINISHED, :requestor => requestor, :target => person, :spam => false)
93 93  
94 94 get :processed
95 95 assert_response :success
... ... @@ -98,7 +98,7 @@ class TasksControllerTest &lt; ActionController::TestCase
98 98 end
99 99  
100 100 should 'be able to finish a task' do
101   - t = profile.tasks.build; t.save!
  101 + t = person.tasks.build; t.save!
102 102  
103 103 post :close, :tasks => {t.id => {:decision => 'finish', :task => {}}}
104 104 assert_redirected_to :action => 'index'
... ... @@ -108,7 +108,7 @@ class TasksControllerTest &lt; ActionController::TestCase
108 108 end
109 109  
110 110 should 'be able to cancel a task' do
111   - t = profile.tasks.build; t.save!
  111 + t = person.tasks.build; t.save!
112 112  
113 113 post :close, :tasks => {t.id => {:decision => 'cancel', :task => {}}}
114 114 assert_redirected_to :action => 'index'
... ... @@ -118,7 +118,7 @@ class TasksControllerTest &lt; ActionController::TestCase
118 118 end
119 119  
120 120 should 'be able to skip a task' do
121   - t = profile.tasks.build; t.save!
  121 + t = person.tasks.build; t.save!
122 122  
123 123 post :close, :tasks => {t.id => {:decision => 'skip', :task => {}}}
124 124 assert_redirected_to :action => 'index'
... ... @@ -128,9 +128,9 @@ class TasksControllerTest &lt; ActionController::TestCase
128 128 end
129 129  
130 130 should 'be able to apply different decisions to multiples tasks at the same time' do
131   - t1 = profile.tasks.build; t1.save!
132   - t2 = profile.tasks.build; t2.save!
133   - t3 = profile.tasks.build; t3.save!
  131 + t1 = person.tasks.build; t1.save!
  132 + t2 = person.tasks.build; t2.save!
  133 + t3 = person.tasks.build; t3.save!
134 134  
135 135 post :close, :tasks => {t1.id => {:decision => 'finish', :task => {}}, t2.id => {:decision => 'cancel', :task => {}}, t3.id => {:decision => 'skip', :task => {}}}
136 136 assert_redirected_to :action => 'index'
... ... @@ -145,56 +145,60 @@ class TasksControllerTest &lt; ActionController::TestCase
145 145 end
146 146  
147 147 should 'affiliate roles to user after finish add member task' do
148   - t = AddMember.create!(:person => profile, :organization => profile)
149   - count = profile.members.size
  148 + community = fast_create(Community)
  149 + community.add_member(person)
  150 + another_person = fast_create(Person)
  151 + t = AddMember.create!(:person => another_person, :organization => community)
  152 + count = community.members.size
  153 + @controller.stubs(:profile).returns(community)
150 154 post :close, :tasks => {t.id => {:decision => 'finish', :task => {}}}
151   - profile = Profile.find(@profile.id)
152   - assert_equal count + 1, profile.members.size
  155 + community = Profile.find(community.id)
  156 + assert_equal count + 1, community.members.size
153 157 end
154 158  
155 159 should 'display a create ticket form' do
156   - get :new, :profile => profile.identifier
  160 + get :new, :profile => person.identifier
157 161  
158 162 assert_template 'new'
159 163 end
160 164  
161 165 should 'add a hidden field with target_id when informed in the URL' do
162 166 friend = create_user('myfriend').person
163   - profile.add_friend(friend)
  167 + person.add_friend(friend)
164 168  
165   - get :new, :profile => profile.identifier, :target_id => friend.id.to_s
  169 + get :new, :profile => person.identifier, :target_id => friend.id.to_s
166 170  
167 171 assert_tag :tag => 'input', :attributes => { :type => 'hidden', :name => 'ticket[target_id]', :value => friend.id }
168 172 end
169 173  
170 174 should 'select friend from list when not already informed' do
171   - get :new, :profile => profile.identifier
  175 + get :new, :profile => person.identifier
172 176 assert_tag :tag => 'select', :attributes => { :name => 'ticket[target_id]' }
173 177 end
174 178  
175 179 should 'create a ticket' do
176 180 assert_difference 'Ticket.count' do
177   - post :new, :profile => profile.identifier, :ticket => {:name => 'test ticket'}
  181 + post :new, :profile => person.identifier, :ticket => {:name => 'test ticket'}
178 182 end
179 183 end
180 184  
181 185 should 'create a ticket with profile requestor' do
182   - post :new, :profile => profile.identifier, :ticket => {:name => 'new task'}
183   -
184   - assert_equal profile, assigns(:ticket).requestor
  186 + post :new, :profile => person.identifier, :ticket => {:name => 'new task'}
  187 +
  188 + assert_equal person, assigns(:ticket).requestor
185 189 end
186 190  
187 191 should 'list tasks that this profile created' do
188   - task = Ticket.create!(:name => 'test', :requestor => profile)
189   - get :list_requested, :profile => profile.identifier
  192 + task = Ticket.create!(:name => 'test', :requestor => person)
  193 + get :list_requested, :profile => person.identifier
190 194  
191 195 assert_includes assigns(:tasks), task
192 196 end
193 197  
194 198 should 'list tasks that this profile created without spam' do
195   - task_spam = Ticket.create!(:name => 'test', :requestor => profile, :spam => true)
196   - task_ham = Ticket.create!(:name => 'test', :requestor => profile, :spam => false)
197   - get :list_requested, :profile => profile.identifier
  199 + task_spam = Ticket.create!(:name => 'test', :requestor => person, :spam => true)
  200 + task_ham = Ticket.create!(:name => 'test', :requestor => person, :spam => false)
  201 + get :list_requested, :profile => person.identifier
198 202  
199 203 assert_includes assigns(:tasks), task_ham
200 204 assert_not_includes assigns(:tasks), task_spam
... ... @@ -202,9 +206,9 @@ class TasksControllerTest &lt; ActionController::TestCase
202 206  
203 207 should 'set target of ticket when creating it' do
204 208 f = create_user('friend').person
205   - profile.add_friend f
  209 + person.add_friend f
206 210  
207   - post :new, :profile => profile.identifier, :ticket => {:name => 'test ticket', :target_id => f.id, :target_type => 'Profile'}
  211 + post :new, :profile => person.identifier, :ticket => {:name => 'test ticket', :target_id => f.id, :target_type => 'Profile'}
208 212 assert_response :redirect
209 213  
210 214 assert_equal f, assigns(:ticket).target
... ... @@ -214,9 +218,9 @@ class TasksControllerTest &lt; ActionController::TestCase
214 218 c = fast_create(Community)
215 219 c.update_attributes(:moderated_articles => false)
216 220 @controller.stubs(:profile).returns(c)
217   - c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
218   - article = profile.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
219   - t = ApproveArticle.create!(:name => 'test name', :article => article, :target => c, :requestor => profile)
  221 + c.affiliate(person, Profile::Roles.all_roles(person.environment.id))
  222 + article = person.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
  223 + t = ApproveArticle.create!(:name => 'test name', :article => article, :target => c, :requestor => person)
220 224  
221 225 post :close, :tasks => {t.id => {:decision => 'finish', :task => {:name => 'new_name'}}}
222 226 assert_equal article, c.articles.find_by_name('new_name').reference_article
... ... @@ -227,9 +231,9 @@ class TasksControllerTest &lt; ActionController::TestCase
227 231 c.update_attributes(:moderated_articles => false)
228 232 @controller.stubs(:profile).returns(c)
229 233 folder = create(Folder, :profile => c, :name => 'test folder')
230   - c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
231   - article = profile.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
232   - t = ApproveArticle.create!(:name => 'test name', :article => article, :target => c, :requestor => profile)
  234 + c.affiliate(person, Profile::Roles.all_roles(person.environment.id))
  235 + article = person.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
  236 + t = ApproveArticle.create!(:name => 'test name', :article => article, :target => c, :requestor => person)
233 237  
234 238 post :close, :tasks => {t.id => {:decision => 'finish', :task => {:name => 'new_name', :article_parent_id => folder.id}}}
235 239 assert_equal folder, c.articles.find_by_name('new_name').parent
... ... @@ -240,9 +244,9 @@ class TasksControllerTest &lt; ActionController::TestCase
240 244 c.update_attributes(:moderated_articles => false)
241 245 @controller.stubs(:profile).returns(c)
242 246 folder = create(Article, :profile => c, :name => 'test folder', :type => 'Folder')
243   - c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
244   - article = profile.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
245   - t = ApproveArticle.create!(:article => article, :target => c, :requestor => profile)
  247 + c.affiliate(person, Profile::Roles.all_roles(person.environment.id))
  248 + article = person.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
  249 + t = ApproveArticle.create!(:article => article, :target => c, :requestor => person)
246 250  
247 251 post :close, :tasks => {t.id => {:decision => 'finish', :task => {:name => 'new_name', :article_parent_id => folder.id, :highlighted => true}}}
248 252 assert_equal true, c.articles.find_by_name('new_name').highlighted
... ... @@ -252,9 +256,9 @@ class TasksControllerTest &lt; ActionController::TestCase
252 256 c = fast_create(Community)
253 257 c.update_attributes(:moderated_articles => false)
254 258 @controller.stubs(:profile).returns(c)
255   - c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
256   - article = profile.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
257   - t = ApproveArticle.create!(:article => article, :target => c, :requestor => profile)
  259 + c.affiliate(person, Profile::Roles.all_roles(person.environment.id))
  260 + article = person.articles.create!(:name => 'something interesting', :body => 'ruby on rails')
  261 + t = ApproveArticle.create!(:article => article, :target => c, :requestor => person)
258 262  
259 263 post :close, :tasks => {t.id => {:decision => 'finish', :task => {:name => 'new_name', :article_parent_id => ""}}}
260 264 assert_not_nil c.articles.find_by_name('new_name')
... ... @@ -263,7 +267,7 @@ class TasksControllerTest &lt; ActionController::TestCase
263 267 should 'handle blank names for published articles' do
264 268 c = fast_create(Community)
265 269 @controller.stubs(:profile).returns(c)
266   - c.affiliate(profile, Profile::Roles.all_roles(c.environment))
  270 + c.affiliate(person, Profile::Roles.all_roles(c.environment))
267 271 person = create_user('test_user').person
268 272 p_blog = Blog.create!(:profile => person, :name => 'Blog')
269 273 c_blog1 = Blog.create!(:profile => c, :name => 'Blog')
... ... @@ -282,8 +286,8 @@ class TasksControllerTest &lt; ActionController::TestCase
282 286  
283 287 should 'display error if there is an enterprise with the same identifier and keep the task active' do
284 288 e = Environment.default
285   - e.add_admin(profile)
286   - task = CreateEnterprise.create!(:name => "My Enterprise", :identifier => "my-enterprise", :requestor => profile, :target => e)
  289 + e.add_admin(person)
  290 + task = CreateEnterprise.create!(:name => "My Enterprise", :identifier => "my-enterprise", :requestor => person, :target => e)
287 291 enterprise = fast_create(Enterprise, :name => "My Enterprise", :identifier => "my-enterprise")
288 292  
289 293 assert_nothing_raised do
... ... @@ -299,7 +303,7 @@ class TasksControllerTest &lt; ActionController::TestCase
299 303 should 'render TinyMce Editor when approving suggested article task' do
300 304 Task.destroy_all
301 305 c = fast_create(Community)
302   - c.add_admin profile
  306 + c.add_admin person
303 307 @controller.stubs(:profile).returns(c)
304 308 t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
305 309  
... ... @@ -311,7 +315,7 @@ class TasksControllerTest &lt; ActionController::TestCase
311 315 should 'create TinyMceArticle article after finish approve suggested article task' do
312 316 TinyMceArticle.destroy_all
313 317 c = fast_create(Community)
314   - c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
  318 + c.affiliate(person, Profile::Roles.all_roles(person.environment.id))
315 319 @controller.stubs(:profile).returns(c)
316 320 t = SuggestArticle.create!(:article => {:name => 'test name', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
317 321  
... ... @@ -322,7 +326,7 @@ class TasksControllerTest &lt; ActionController::TestCase
322 326 should "change the article's attributes on suggested article task approval" do
323 327 TinyMceArticle.destroy_all
324 328 c = fast_create(Community)
325   - c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id))
  329 + c.affiliate(person, Profile::Roles.all_roles(person.environment.id))
326 330 @controller.stubs(:profile).returns(c)
327 331 t = SuggestArticle.new
328 332 t.article = {:name => 'test name', :body => 'test body', :source => 'http://test.com', :source_name => 'some source name'}
... ... @@ -342,7 +346,7 @@ class TasksControllerTest &lt; ActionController::TestCase
342 346 should "display name from article suggestion when requestor was not setted" do
343 347 Task.destroy_all
344 348 c = fast_create(Community)
345   - c.add_admin profile
  349 + c.add_admin person
346 350 @controller.stubs(:profile).returns(c)
347 351 t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
348 352  
... ... @@ -353,7 +357,7 @@ class TasksControllerTest &lt; ActionController::TestCase
353 357 should "append hidden tag with type value from article suggestion" do
354 358 Task.destroy_all
355 359 c = fast_create(Community)
356   - c.add_admin profile
  360 + c.add_admin person
357 361 @controller.stubs(:profile).returns(c)
358 362 t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body', :type => 'TextArticle'}, :name => 'some name', :email => 'test@localhost.com', :target => c)
359 363  
... ... @@ -364,7 +368,7 @@ class TasksControllerTest &lt; ActionController::TestCase
364 368 should "display parent_id selection from article suggestion with predefined value" do
365 369 Task.destroy_all
366 370 c = fast_create(Community)
367   - c.add_admin profile
  371 + c.add_admin person
368 372 @controller.stubs(:profile).returns(c)
369 373 parent = fast_create(Folder, :profile_id => c.id)
370 374 t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body', :parent_id => parent.id}, :name => 'some name', :email => 'test@localhost.com', :target => c)
... ... @@ -376,7 +380,7 @@ class TasksControllerTest &lt; ActionController::TestCase
376 380 should "not display name from article suggestion when requestor was setted" do
377 381 Task.destroy_all
378 382 c = fast_create(Community)
379   - c.add_admin profile
  383 + c.add_admin person
380 384 @controller.stubs(:profile).returns(c)
381 385 t = SuggestArticle.create!(:article => {:name => 'test name', :abstract => 'test abstract', :body => 'test body'}, :requestor => fast_create(Person), :target => c)
382 386  
... ... @@ -392,7 +396,7 @@ class TasksControllerTest &lt; ActionController::TestCase
392 396  
393 397 should 'close create enterprise if trying to cancel even if there is already an existing identifier' do
394 398 identifier = "common-identifier"
395   - task = CreateEnterprise.create!(:identifier => identifier, :name => identifier, :requestor => profile, :target => profile)
  399 + task = CreateEnterprise.create!(:identifier => identifier, :name => identifier, :requestor => person, :target => person)
396 400 fast_create(Profile, :identifier => identifier)
397 401  
398 402 assert_nothing_raised do
... ... @@ -408,17 +412,17 @@ class TasksControllerTest &lt; ActionController::TestCase
408 412 class FeedDog < Task; end
409 413 Task.stubs(:per_page).returns(3)
410 414 requestor = fast_create(Person)
411   - t1 = CleanHouse.create!(:requestor => requestor, :target => profile)
412   - t2 = CleanHouse.create!(:requestor => requestor, :target => profile)
413   - t3 = FeedDog.create!(:requestor => requestor, :target => profile)
  415 + t1 = CleanHouse.create!(:requestor => requestor, :target => person)
  416 + t2 = CleanHouse.create!(:requestor => requestor, :target => person)
  417 + t3 = FeedDog.create!(:requestor => requestor, :target => person)
414 418  
415   - post :index, :filter_type => t1.type
  419 + get :index, :filter_type => t1.type
416 420  
417 421 assert_includes assigns(:tasks), t1
418 422 assert_includes assigns(:tasks), t2
419 423 assert_not_includes assigns(:tasks), t3
420 424  
421   - post :index
  425 + get :index
422 426  
423 427 assert_includes assigns(:tasks), t1
424 428 assert_includes assigns(:tasks), t2
... ... @@ -430,9 +434,9 @@ class TasksControllerTest &lt; ActionController::TestCase
430 434 class FeedDog < Task; end
431 435 Task.stubs(:per_page).returns(3)
432 436 requestor = fast_create(Person)
433   - t1 = CleanHouse.create!(:requestor => requestor, :target => profile, :data => {:name => 'Task Test'})
434   - t2 = CleanHouse.create!(:requestor => requestor, :target => profile)
435   - t3 = FeedDog.create!(:requestor => requestor, :target => profile)
  437 + t1 = CleanHouse.create!(:requestor => requestor, :target => person, :data => {:name => 'Task Test'})
  438 + t2 = CleanHouse.create!(:requestor => requestor, :target => person)
  439 + t3 = FeedDog.create!(:requestor => requestor, :target => person)
436 440  
437 441 get :index, :filter_type => t1.type, :filter_text => 'test'
438 442  
... ... @@ -447,13 +451,29 @@ class TasksControllerTest &lt; ActionController::TestCase
447 451 assert_includes assigns(:tasks), t3
448 452 end
449 453  
  454 + should 'filter tasks by tags' do
  455 +
  456 + requestor = fast_create(Person)
  457 +
  458 + task_one = Task.create!(:requestor => requestor, :target => person, :data => {:name => 'Task Test'})
  459 + task_two = Task.create!(:requestor => requestor, :target => person, :data => {:name => 'Another Task'})
  460 +
  461 + person.tag(task_one, with: 'noosfero,test', on: :tags)
  462 + person.tag(task_two, with: 'test', on: :tags)
  463 +
  464 + get :index, :filter_tags => 'noosfero'
  465 +
  466 + assert_includes assigns(:tasks), task_one
  467 + assert_not_includes assigns(:tasks), task_two
  468 + end
  469 +
450 470 should 'return tasks ordered accordingly and limited by pages' do
451 471 time = Time.now
452   - person = fast_create(Person)
453   - t1 = create(Task, :status => Task::Status::ACTIVE, :target => profile, :requestor => person, :created_at => time)
454   - t2 = create(Task, :status => Task::Status::ACTIVE, :target => profile, :requestor => person, :created_at => time + 1.second)
455   - t3 = create(Task, :status => Task::Status::ACTIVE, :target => profile, :requestor => person, :created_at => time + 2.seconds)
456   - t4 = create(Task, :status => Task::Status::ACTIVE, :target => profile, :requestor => person, :created_at => time + 3.seconds)
  472 + requestor = fast_create(Person)
  473 + t1 = create(Task, :status => Task::Status::ACTIVE, :target => person, :requestor => requestor, :created_at => time)
  474 + t2 = create(Task, :status => Task::Status::ACTIVE, :target => person, :requestor => requestor, :created_at => time + 1.second)
  475 + t3 = create(Task, :status => Task::Status::ACTIVE, :target => person, :requestor => requestor, :created_at => time + 2.seconds)
  476 + t4 = create(Task, :status => Task::Status::ACTIVE, :target => person, :requestor => requestor, :created_at => time + 3.seconds)
457 477  
458 478 Task.stubs(:per_page).returns(2)
459 479  
... ... @@ -469,9 +489,9 @@ class TasksControllerTest &lt; ActionController::TestCase
469 489 Task.stubs(:per_page).returns(3)
470 490 requestor = fast_create(Person)
471 491 responsible = fast_create(Person)
472   - t1 = Task.create!(:requestor => requestor, :target => profile, :responsible => responsible)
473   - t2 = Task.create!(:requestor => requestor, :target => profile, :responsible => responsible)
474   - t3 = Task.create!(:requestor => requestor, :target => profile)
  492 + t1 = Task.create!(:requestor => requestor, :target => person, :responsible => responsible)
  493 + t2 = Task.create!(:requestor => requestor, :target => person, :responsible => responsible)
  494 + t3 = Task.create!(:requestor => requestor, :target => person)
475 495  
476 496 get :index, :filter_responsible => responsible.id
477 497  
... ... @@ -661,4 +681,50 @@ class TasksControllerTest &lt; ActionController::TestCase
661 681 assert_select ".task_responsible .value"
662 682 end
663 683  
  684 + should 'save task tags' do
  685 + requestor = fast_create(Person)
  686 +
  687 + task_one = Task.create!(:requestor => requestor, :target => person, :data => {:name => 'Task Test'})
  688 + post :save_tags, :task_id => task_one.id, :tag_list => 'test'
  689 +
  690 + assert_includes task_one.tags_from(nil), 'test'
  691 + end
  692 +
  693 + should 'tag attribution in one task not affect another' do
  694 + requestor = fast_create(Person)
  695 +
  696 + task_one = Task.create!(:requestor => requestor, :target => person, :data => {:name => 'Task Test'})
  697 + task_two = Task.create!(:requestor => requestor, :target => person, :data => {:name => 'Another Task'})
  698 +
  699 + post :save_tags, :task_id => task_one.id, :tag_list => 'noosfero,test'
  700 + post :save_tags, :task_id => task_two.id, :tag_list => 'test'
  701 +
  702 + assert_not_includes task_two.tags_from(nil), 'noosfero'
  703 + end
  704 +
  705 + should 'not tag task without permission' do
  706 + Role.delete_all
  707 + requestor = fast_create(Person)
  708 + community = fast_create(Community)
  709 + community.add_member(person)
  710 +
  711 + @controller.stubs(:profile).returns(community)
  712 + task_one = Task.create!(:requestor => requestor, :target => community, :data => {:name => 'Task Test'})
  713 +
  714 + post :save_tags, :task_id => task_one.id, :tag_list => 'test'
  715 +
  716 + assert_not_includes task_one.tags_from(nil), 'test'
  717 + end
  718 +
  719 + should 'not tag task with permission but another user' do
  720 + requestor = fast_create(Person)
  721 + target = fast_create(Person)
  722 +
  723 + task_one = Task.create!(:requestor => requestor, :target => target, :data => {:name => 'Task Test'})
  724 +
  725 + post :save_tags, :task_id => task_one.id, :tag_list => 'test'
  726 +
  727 + assert_not_includes task_one.tags_from(nil), 'test'
  728 + end
  729 +
664 730 end
... ...
test/unit/task_test.rb
... ... @@ -329,7 +329,7 @@ class TaskTest &lt; ActiveSupport::TestCase
329 329 assert_includes Task.to(another_person), t4
330 330 end
331 331  
332   - should 'filter tasks by type with named_scope' do
  332 + should 'filter tasks by type with named scope' do
333 333 class CleanHouse < Task; end
334 334 class FeedDog < Task; end
335 335 requestor = fast_create(Person)
... ... @@ -345,6 +345,25 @@ class TaskTest &lt; ActiveSupport::TestCase
345 345 assert_includes Task.of(nil), t3
346 346 end
347 347  
  348 + should 'filter tasks by tags with named scope' do
  349 +
  350 + requestor = fast_create(Person)
  351 + target = fast_create(Person)
  352 + profile = sample_user
  353 +
  354 + task_one = Task.create!(:requestor => requestor, :target => target, :data => {:name => 'Task Test'})
  355 + task_two = Task.create!(:requestor => requestor, :target => target, :data => {:name => 'Another Task'})
  356 +
  357 + profile.tag(task_one, with: 'noosfero,test', on: :tags)
  358 + profile.tag(task_two, with: 'test', on: :tags)
  359 +
  360 + data = Task.tagged_with('noosfero', any: true)
  361 +
  362 + assert_includes data, task_one
  363 + assert_not_includes data, task_two
  364 +
  365 + end
  366 +
348 367 should 'order tasks by some attribute correctly' do
349 368 Task.destroy_all
350 369 t1 = fast_create(Task, :status => 4, :created_at => Time.now + 1.hour)
... ... @@ -452,6 +471,23 @@ class TaskTest &lt; ActiveSupport::TestCase
452 471 assert_equal person, task.responsible
453 472 end
454 473  
  474 + should 'save tasks tags' do
  475 +
  476 + requestor = fast_create(Person)
  477 + target = fast_create(Person)
  478 + profile = sample_user
  479 +
  480 + task_one = Task.create!(:requestor => requestor, :target => target, :data => {:name => 'Task Test'})
  481 + task_two = Task.create!(:requestor => requestor, :target => target, :data => {:name => 'Another Task'})
  482 +
  483 + profile.tag(task_one, with: 'noosfero,test', on: :tags)
  484 + profile.tag(task_two, with: 'test', on: :tags)
  485 +
  486 + assert_includes task_one.tags_from(nil), 'test'
  487 + assert_not_includes task_two.tags_from(nil), 'noosfero'
  488 +
  489 + end
  490 +
455 491 protected
456 492  
457 493 def sample_user
... ...