4511-add-group-to-watcher.patch

Yuichi HARADA, 2020-01-31 03:18

Download (24.2 KB)

View differences:

app/controllers/watchers_controller.rb
42 42
    else
43 43
      user_ids << params[:user_id]
44 44
    end
45
    users = User.active.visible.where(:id => user_ids.flatten.compact.uniq)
45
    user_ids = user_ids.flatten.compact.uniq
46
    users = User.active.visible.where(:id => user_ids).to_a
47
    users += Group.givable.active.visible.where(:id => user_ids).to_a
46 48
    users.each do |user|
47 49
      @watchables.each do |watchable|
48 50
        Watcher.create(:watchable => watchable, :user => user)
......
59 61
    if params[:watcher]
60 62
      user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
61 63
      @users = User.active.visible.where(:id => user_ids).to_a
64
      @users += Group.givable.active.visible.where(:id => user_ids).to_a
62 65
    end
63 66
    if @users.blank?
64 67
      head 200
......
66 69
  end
67 70

  
68 71
  def destroy
69
    user = User.find(params[:user_id])
72
    user = Principal.find(params[:user_id])
70 73
    @watchables.each do |watchable|
71 74
      watchable.set_watcher(user, false)
72 75
    end
......
126 129
      scope = User.all.limit(100)
127 130
    end
128 131
    users = scope.active.visible.sorted.like(params[:q]).to_a
132
    users += Group.givable.active.visible.sorted.like(params[:q]).to_a
129 133
    if @watchables && @watchables.size == 1
130 134
      users -= @watchables.first.watcher_users
131 135
    end
app/helpers/avatars_helper.rb
51 51
        gravatar(email.to_s.downcase, options) rescue nil
52 52
      elsif user.is_a?(AnonymousUser)
53 53
        anonymous_avatar(options)
54
      elsif user.is_a?(Group)
55
        group_avatar(options)
54 56
      else
55 57
        nil
56 58
      end
......
72 74
  def anonymous_avatar(options={})
73 75
    image_tag 'anonymous.png', GravatarHelper::DEFAULT_OPTIONS.except(:default, :rating, :ssl).merge(options)
74 76
  end
77

  
78
  def group_avatar(options={})
79
    image_tag 'group.png', GravatarHelper::DEFAULT_OPTIONS.except(:default, :rating, :ssl).merge(options)
80
  end
75 81
end
app/helpers/issues_helper.rb
365 365
  # on the new issue form
366 366
  def users_for_new_issue_watchers(issue)
367 367
    users = issue.watcher_users.select{|u| u.status == User::STATUS_ACTIVE}
368
    if issue.project.users.count <= 20
369
      users = (users + issue.project.users.sort).uniq
368
    if issue.project.users.count + Group.givable.count <= 20
369
      users = (users + issue.project.users.sort + Group.givable.sort).uniq
370 370
    end
371 371
    users
372 372
  end
app/helpers/watchers_helper.rb
47 47
  def watchers_list(object)
48 48
    remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
49 49
    content = ''.html_safe
50
    lis = object.watcher_users.preload(:email_address).collect do |user|
50
    lis = object.watcher_users.collect do |user|
51 51
      s = ''.html_safe
52 52
      s << avatar(user, :size => "16").to_s
53 53
      s << link_to_user(user, :class => 'user')
app/models/group.rb
115 115
    return if self.id.nil?
116 116

  
117 117
    Issue.where(['assigned_to_id = ?', id]).update_all('assigned_to_id = NULL')
118
    Watcher.where('user_id = ?', id).delete_all
118 119
  end
119 120
end
120 121

  
app/models/query.rb
600 600

  
601 601
  def watcher_values
602 602
    watcher_values = [["<< #{l(:label_me)} >>", "me"]]
603
    watcher_values += users.sort_by(&:status).collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")] } if User.current.allowed_to?(:view_issue_watchers, self.project)
603
    watcher_values += principals.sort_by(&:status).collect{|s| [s.name, s.id.to_s, l("status_#{User::LABEL_BY_STATUS[s.status]}")] } if User.current.allowed_to?(:view_issue_watchers, self.project)
604 604
    watcher_values
605 605
  end
606 606

  
......
913 913
        if v.delete("me")
914 914
          if User.current.logged?
915 915
            v.push(User.current.id.to_s)
916
            v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id'
916
            v += User.current.group_ids.map(&:to_s) if %w(assigned_to_id watcher_id).include?(field)
917 917
          else
918 918
            v.push("0")
919 919
          end
app/models/watcher.rb
19 19

  
20 20
class Watcher < ActiveRecord::Base
21 21
  belongs_to :watchable, :polymorphic => true
22
  belongs_to :user
22
  belongs_to :user, :class_name => 'Principal'
23 23

  
24 24
  validates_presence_of :user
25 25
  validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id], :case_sensitive => false
......
54 54
  protected
55 55

  
56 56
  def validate_user
57
    errors.add :user_id, :invalid unless user.nil? || user.active?
57
    errors.add :user_id, :invalid \
58
      unless user.nil? || (user.is_a?(User) && user.active?) || (user.is_a?(Group) && user.givable?)
58 59
  end
59 60

  
60 61
  def self.prune_single_user(user, options={})
lib/plugins/acts_as_watchable/lib/acts_as_watchable.rb
31 31

  
32 32
        # Returns an array of users that are proposed as watchers
33 33
        def addable_watcher_users
34
          users = self.project.users.sort - self.watcher_users
34
          users = (self.project.users.sort + Group.givable.sort) - self.watcher_users
35 35
          if respond_to?(:visible?)
36
            users.reject! {|user| !visible?(user)}
36
            users.reject! {|user| user.is_a?(User) && !visible?(user)}
37 37
          end
38 38
          users
39 39
        end
......
47 47

  
48 48
        # Removes user from the watchers list
49 49
        def remove_watcher(user)
50
          return nil unless user && user.is_a?(User)
50
          return nil unless user && (user.is_a?(User) || user.is_a?(Group))
51 51
          # Rails does not reset the has_many :through association
52 52
          watcher_users.reset
53 53
          watchers.where(:user_id => user.id).delete_all
......
73 73

  
74 74
        def notified_watchers
75 75
          notified = watcher_users.active.to_a
76
          notified = notified.map {|n| n.is_a?(Group) ? n.users : n}.flatten
77
          notified.uniq!
76 78
          notified.reject! {|user| user.mail.blank? || user.mail_notification == 'none'}
77 79
          if respond_to?(:visible?)
78 80
            notified.reject! {|user| !visible?(user)}
test/functional/issues_controller_test.rb
2443 2443

  
2444 2444
  def test_show_should_display_watchers
2445 2445
    @request.session[:user_id] = 2
2446
    Issue.find(1).add_watcher User.find(2)
2446
    issue = Issue.find(1)
2447
    issue.add_watcher User.find(2)
2448
    issue.add_watcher Group.find(10)
2447 2449
    get(:show, :params => {:id => 1})
2448 2450
    assert_select 'div#watchers ul' do
2449
      assert_select 'li' do
2451
      assert_select 'li.user-2' do
2450 2452
        assert_select 'a[href="/users/2"]'
2451 2453
        assert_select 'a[class*=delete]'
2452 2454
      end
2455
      assert_select "li.user-10" do
2456
        assert_select 'a[href="/users/10"]', false
2457
        assert_select 'a[class*=delete]'
2458
      end
2453 2459
    end
2454 2460
  end
2455 2461

  
2456 2462
  def test_show_should_display_watchers_with_gravatars
2457 2463
    @request.session[:user_id] = 2
2458
    Issue.find(1).add_watcher User.find(2)
2464
    issue = Issue.find(1)
2465
    issue.add_watcher User.find(2)
2466
    issue.add_watcher Group.find(10)
2459 2467
    with_settings :gravatar_enabled => '1' do
2460 2468
      get(:show, :params => {:id => 1})
2461 2469
    end
2462 2470
    assert_select 'div#watchers ul' do
2463
      assert_select 'li' do
2464
        assert_select 'img.gravatar'
2471
      assert_select 'li.user-2' do
2472
        assert_select 'img.gravatar[title=?]', 'John Smith'
2465 2473
        assert_select 'a[href="/users/2"]'
2466 2474
        assert_select 'a[class*=delete]'
2467 2475
      end
2476
      assert_select "li.user-10" do
2477
        assert_select 'img.gravatar[title=?]', 'A Team'
2478
        assert_select 'a[href="/users/10"]', false
2479
        assert_select 'a[class*=delete]'
2480
      end
2468 2481
    end
2469 2482
  end
2470 2483

  
......
3995 4008
    ActionMailer::Base.deliveries.clear
3996 4009

  
3997 4010
    with_settings :notified_events => %w(issue_added) do
3998
      assert_difference 'Watcher.count', 2 do
4011
      assert_difference 'Watcher.count', 3 do
3999 4012
        post(
4000 4013
          :create,
4001 4014
          :params => {
......
4005 4018
              :subject => 'This is a new issue with watchers',
4006 4019
              :description => 'This is the description',
4007 4020
              :priority_id => 5,
4008
              :watcher_user_ids => ['2', '3']
4021
              :watcher_user_ids => ['2', '3', '10']
4009 4022
            }
4010 4023
          }
4011 4024
        )
......
4016 4029
    assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
4017 4030

  
4018 4031
    # Watchers added
4019
    assert_equal [2, 3], issue.watcher_user_ids.sort
4032
    assert_equal [2, 3, 10], issue.watcher_user_ids.sort
4020 4033
    assert issue.watched_by?(User.find(3))
4034
    assert issue.watched_by?(Group.find(10))
4021 4035
    # Watchers notified
4022
    mail = ActionMailer::Base.deliveries.last
4023
    assert_not_nil mail
4036
    assert_equal 3, ActionMailer::Base.deliveries.size
4037
    mail = ActionMailer::Base.deliveries[1]
4024 4038
    assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
4039
    mail = ActionMailer::Base.deliveries[2]
4040
    assert [mail.bcc, mail.cc].flatten.include?(User.find(8).mail)
4025 4041
  end
4026 4042

  
4027 4043
  def test_post_create_subissue
......
4740 4756

  
4741 4757
  def test_new_as_copy_should_preserve_watchers
4742 4758
    @request.session[:user_id] = 2
4759
    issue = Issue.find(1)
4743 4760
    user = User.generate!
4744
    Watcher.create!(:watchable => Issue.find(1), :user => user)
4761
    Watcher.create!(:watchable => issue, :user => user)
4762
    Watcher.create!(:watchable => issue, :user => Group.find(10))
4745 4763
    get(
4746 4764
      :new,
4747 4765
      :params => {
......
4749 4767
        :copy_from => 1
4750 4768
      }
4751 4769
    )
4752
    assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 1
4770
    assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 2
4753 4771
    assert_select 'input[type=checkbox][name=?][checked=checked][value=?]', 'issue[watcher_user_ids][]', user.id.to_s
4772
    assert_select 'input[type=checkbox][name=?][checked=checked][value=?]', 'issue[watcher_user_ids][]', '10'
4754 4773
    assert_select 'input[type=hidden][name=?][value=?]', 'issue[watcher_user_ids][]', '', 1
4755 4774
  end
4756 4775

  
......
5174 5193
          :copy_from => copied.id,
5175 5194
          :issue => {
5176 5195
            :subject => 'Copy cleared watchers',
5177
            :watcher_user_ids => ['', '3']
5196
            :watcher_user_ids => ['', '3', '10']
5178 5197
          }
5179 5198
        }
5180 5199
      )
5181 5200
    end
5182 5201
    issue = Issue.order('id DESC').first
5183
    assert_equal [3], issue.watcher_user_ids
5202
    assert_equal [3, 10], issue.watcher_user_ids
5184 5203
  end
5185 5204

  
5186 5205
  def test_create_as_copy_without_watcher_user_ids_should_not_copy_watchers
......
7329 7348
  end
7330 7349

  
7331 7350
  test "issue bulk copy copy watcher" do
7332
    Watcher.create!(:watchable => Issue.find(1), :user => User.find(3))
7351
    issue = Issue.find(1)
7352
    Watcher.create!(:watchable => issue, :user => User.find(3))
7353
    Watcher.create!(:watchable => issue, :user => Group.find(10))
7333 7354
    @request.session[:user_id] = 2
7334 7355
    assert_difference 'Issue.count' do
7335 7356
      post(
......
7345 7366
      )
7346 7367
    end
7347 7368
    copy = Issue.order(:id => :desc).first
7348
    assert_equal 1, copy.watchers.count
7369
    assert_equal 2, copy.watchers.count
7370
    assert_equal [3, 10], copy.watcher_user_ids
7349 7371
  end
7350 7372

  
7351 7373
  def test_bulk_copy_should_not_copy_selected_subtasks_twice
test/functional/queries_controller_test.rb
834 834
    assert_equal [["<< me >>", "me"]], json
835 835
  end
836 836

  
837
  def test_watcher_filter_with_permission_should_show_members
837
  def test_watcher_filter_with_permission_should_show_members_and_groups
838 838
    # This user has view_issue_watchers permission
839 839
    @request.session[:user_id] = 1
840 840

  
......
847 847
    assert_equal 'application/json', response.media_type
848 848
    json = ActiveSupport::JSON.decode(response.body)
849 849

  
850
    assert_equal 6, json.count
850
    assert_equal 7, json.count
851 851
    # "me" value should not be grouped
852 852
    assert_include ["<< me >>", "me"], json
853 853
    assert_include ["Dave Lopper", "3", "active"], json
854 854
    assert_include ["Dave2 Lopper2", "5", "locked"], json
855
    assert_include ["A Team", "10", "active"], json
855 856
  end
856 857
end
test/functional/watchers_controller_test.rb
189 189
    assert Issue.find(2).watched_by?(User.find(4))
190 190
  end
191 191

  
192
  def test_create_group_as_html
193
    @request.session[:user_id] = 2
194
    assert_difference('Watcher.count') do
195
      post :create, :params => {
196
        :object_type => 'issue', :object_id => '2',
197
        :watcher => {:user_id => '10'}
198
      }
199
      assert_response :success
200
      assert_include 'Watcher added', response.body
201
    end
202
    assert Issue.find(2).watched_by?(Group.find(10))
203
  end
204

  
192 205
  def test_create
193 206
    @request.session[:user_id] = 2
194 207
    assert_difference('Watcher.count') do
......
205 218

  
206 219
  def test_create_with_mutiple_users
207 220
    @request.session[:user_id] = 2
208
    assert_difference('Watcher.count', 2) do
221
    assert_difference('Watcher.count', 3) do
209 222
      post :create, :params => {
210 223
        :object_type => 'issue', :object_id => '2',
211
        :watcher => {:user_ids => ['4', '7']}
224
        :watcher => {:user_ids => ['4', '7', '10']}
212 225
      }, :xhr => true
213 226
      assert_response :success
214 227
      assert_match /watchers/, response.body
215 228
      assert_match /ajax-modal/, response.body
216 229
    end
217
    assert Issue.find(2).watched_by?(User.find(4))
218
    assert Issue.find(2).watched_by?(User.find(7))
230
    issue = Issue.find(2)
231
    assert issue.watched_by?(User.find(4))
232
    assert issue.watched_by?(User.find(7))
233
    assert issue.watched_by?(Group.find(10))
219 234
  end
220 235

  
221 236
  def test_create_with_mutiple_objects
222 237
    @request.session[:user_id] = 2
223
    assert_difference('Watcher.count', 4) do
238
    assert_difference('Watcher.count', 6) do
224 239
      post :create, :params => {
225 240
        :object_type => 'issue', :object_id => ['1', '2'],
226
        :watcher => {:user_ids => ['4', '7']}
241
        :watcher => {:user_ids => ['4', '7', '10']}
227 242
      }, :xhr => true
228 243
      assert_response :success
229 244
      assert_match /watchers/, response.body
230 245
      assert_match /ajax-modal/, response.body
231 246
    end
232
    assert Issue.find(1).watched_by?(User.find(4))
233
    assert Issue.find(2).watched_by?(User.find(4))
234
    assert Issue.find(1).watched_by?(User.find(7))
235
    assert Issue.find(2).watched_by?(User.find(7))
247
    issue_1 = Issue.find(1)
248
    issue_2 = Issue.find(2)
249
    user_4 = User.find(4)
250
    user_7 = User.find(7)
251
    group_10 = Group.find(10)
252
    assert issue_1.watched_by?(user_4)
253
    assert issue_2.watched_by?(user_4)
254
    assert issue_1.watched_by?(user_7)
255
    assert issue_2.watched_by?(user_7)
256
    assert issue_1.watched_by?(group_10)
257
    assert issue_2.watched_by?(group_10)
236 258
  end
237 259

  
238 260
  def test_autocomplete_on_watchable_creation
239 261
    @request.session[:user_id] = 2
262
    group = Group.generate!(:name => 'Group Minimum')
240 263
    get :autocomplete_for_user, :params => {:q => 'mi', :project_id => 'ecookbook'}, :xhr => true
241 264
    assert_response :success
242
    assert_select 'input', :count => 4
265
    assert_select 'input', :count => 5
243 266
    assert_select 'input[name=?][value="1"]', 'watcher[user_ids][]'
244 267
    assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
245 268
    assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
246 269
    assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
270
    assert_select %Q!input[name=?][value="#{group.id}"]!, 'watcher[user_ids][]'
247 271
  end
248 272

  
249 273
  def test_search_non_member_on_create
......
342 366
    assert !Issue.find(2).watched_by?(User.find(3))
343 367
  end
344 368

  
369
  def test_destroy_group_as_html
370
    @request.session[:user_id] = 2
371
    issue = Issue.find(2)
372
    group = Group.find(10)
373
    issue.add_watcher(group)
374
    assert issue.watched_by?(group)
375
    assert_difference('Watcher.count', -1) do
376
      delete :destroy, :params => {
377
        :object_type => 'issue', :object_id => '2', :user_id => '10'
378
      }
379
      assert_response :success
380
      assert_include 'Watcher removed', response.body
381
    end
382
    issue.reload
383
    assert !issue.watched_by?(group)
384
  end
385

  
345 386
  def test_destroy
346 387
    @request.session[:user_id] = 2
347 388
    assert_difference('Watcher.count', -1) do
test/helpers/avatars_helper_test.rb
43 43
  end
44 44

  
45 45
  def test_avatar_with_group
46
    assert_nil avatar(Group.first)
46
    assert_match %r{src="/images/group.png(\?\d+)?"}, avatar(Group.first)
47 47
  end
48 48

  
49 49
  def test_avatar_with_invalid_arg_should_return_nil
test/unit/group_test.rb
23 23
  fixtures :projects, :trackers, :issue_statuses, :issues,
24 24
           :enumerations, :users,
25 25
           :projects_trackers,
26
           :roles,
27
           :member_roles,
28
           :members,
29
           :groups_users
26
           :roles, :member_roles, :members,
27
           :groups_users,
28
           :watchers
30 29

  
31 30
  include Redmine::I18n
32 31

  
......
128 127
    assert !User.find(8).member_of?(Project.find(5))
129 128
  end
130 129

  
131
  def test_destroy_should_unassign_issues
130
  def test_destroy_should_unassign_and_unwatch_issues
132 131
    group = Group.find(10)
133 132
    Issue.where(:id => 1).update_all(["assigned_to_id = ?", group.id])
133
    issue = Issue.find(2)
134
    issue.set_watcher(group)
135
    issue.save
136
    issue.reload
137
    assert issue.watcher_user_ids.include?(10)
134 138

  
135 139
    assert group.destroy
136 140
    assert group.destroyed?
137 141

  
138 142
    assert_nil Issue.find(1).assigned_to_id
143
    issue.reload
144
    assert !issue.watcher_user_ids.include?(10)
139 145
  end
140 146

  
141 147
  def test_builtin_groups_should_be_created_if_missing
test/unit/query_test.rb
421 421
    issues = find_issues_with_query(query)
422 422
    assert issues.any?
423 423
    assert_nil issues.detect {|issue| !issue.is_private?}
424
  ensure
425
    User.current = nil
426 424
  end
427 425

  
428 426
  def test_operator_is_not_on_is_private_field
......
436 434
    issues = find_issues_with_query(query)
437 435
    assert issues.any?
438 436
    assert_nil issues.detect {|issue| issue.is_private?}
439
  ensure
440
    User.current = nil
441 437
  end
442 438

  
443 439
  def test_operator_greater_than
......
950 946
    assert_not_nil result
951 947
    assert !result.empty?
952 948
    assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
953
    User.current = nil
949
  end
950

  
951
  def test_filter_watched_issues_with_groups_also
952
    user = User.find(2)
953
    group = Group.find(10)
954
    group.users << user
955
    Issue.find(3).add_watcher(user)
956
    Issue.find(7).add_watcher(group)
957
    User.current = user
958
    query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
959
    result = find_issues_with_query(query)
960
    assert_not_nil result
961
    assert !result.empty?
962
    assert_equal [3, 7], result.sort_by(&:id).pluck(:id)
954 963
  end
955 964

  
956 965
  def test_filter_unwatched_issues
......
960 969
    assert_not_nil result
961 970
    assert !result.empty?
962 971
    assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
963
    User.current = nil
964 972
  end
965 973

  
966 974
  def test_filter_on_watched_issues_with_view_issue_watchers_permission
......
974 982
    result = find_issues_with_query(query)
975 983
    assert_includes result, Issue.find(1)
976 984
    assert_includes result, Issue.find(3)
977
  ensure
978
    User.current.reload
979
    User.current = nil
980 985
  end
981 986

  
982 987
  def test_filter_on_watched_issues_without_view_issue_watchers_permission
......
990 995
    result = find_issues_with_query(query)
991 996
    assert_includes result, Issue.find(1)
992 997
    assert_not_includes result, Issue.find(3)
993
  ensure
994
    User.current.reload
995
    User.current = nil
996 998
  end
997 999

  
998 1000
  def test_filter_on_custom_field_should_ignore_projects_with_field_disabled
test/unit/watcher_test.rb
40 40
  end
41 41

  
42 42
  def test_watch
43
    group = Group.find(10)
44
    assert @issue.add_watcher(group)
43 45
    assert @issue.add_watcher(@user)
44 46
    @issue.reload
45 47
    assert @issue.watchers.detect {|w| w.user == @user}
48
    assert @issue.watchers.detect {|w| w.user == group}
46 49
  end
47 50

  
48 51
  def test_cant_watch_twice
......
103 106
  def test_addable_watcher_users
104 107
    addable_watcher_users = @issue.addable_watcher_users
105 108
    assert_kind_of Array, addable_watcher_users
106
    assert_kind_of User, addable_watcher_users.first
109
    addable_watcher_users.each do |addable_watcher|
110
      assert_equal true, addable_watcher.is_a?(User) || addable_watcher.is_a?(Group)
111
    end
107 112
  end
108 113

  
109 114
  def test_addable_watcher_users_should_not_include_user_that_cannot_view_the_object
110 115
    issue = Issue.new(:project => Project.find(1), :is_private => true)
111
    assert_nil issue.addable_watcher_users.detect {|user| !issue.visible?(user)}
116
    assert_nil issue.addable_watcher_users.detect {|user| user.is_a?(User) && !issue.visible?(user)}
112 117
  end
113 118

  
114 119
  def test_any_watched_should_return_false_if_no_object_is_watched
......
147 152
  end
148 153

  
149 154
  def test_unwatch
155
    group = Group.find(10)
156
    assert @issue.add_watcher(group)
150 157
    assert @issue.add_watcher(@user)
151 158
    @issue.reload
152 159
    assert_equal 1, @issue.remove_watcher(@user)
160
    assert_equal 1, @issue.remove_watcher(group)
153 161
  end
154 162

  
155 163
  def test_prune_with_user