Revision 1298:4f746d8966dd .svn/pristine/2b

View differences:

.svn/pristine/2b/2b0a9f999f6063790f2925cfcbf5bec32cb0108e.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2011  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../../test_helper', __FILE__)
19

  
20
class ApiTest::IssuesTest < ActionController::IntegrationTest
21
  fixtures :projects,
22
    :users,
23
    :roles,
24
    :members,
25
    :member_roles,
26
    :issues,
27
    :issue_statuses,
28
    :versions,
29
    :trackers,
30
    :projects_trackers,
31
    :issue_categories,
32
    :enabled_modules,
33
    :enumerations,
34
    :attachments,
35
    :workflows,
36
    :custom_fields,
37
    :custom_values,
38
    :custom_fields_projects,
39
    :custom_fields_trackers,
40
    :time_entries,
41
    :journals,
42
    :journal_details,
43
    :queries,
44
    :attachments
45

  
46
  def setup
47
    Setting.rest_api_enabled = '1'
48
  end
49

  
50
  context "/issues" do
51
    # Use a private project to make sure auth is really working and not just
52
    # only showing public issues.
53
    should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
54

  
55
    should "contain metadata" do
56
      get '/issues.xml'
57

  
58
      assert_tag :tag => 'issues',
59
        :attributes => {
60
          :type => 'array',
61
          :total_count => assigns(:issue_count),
62
          :limit => 25,
63
          :offset => 0
64
        }
65
    end
66

  
67
    context "with offset and limit" do
68
      should "use the params" do
69
        get '/issues.xml?offset=2&limit=3'
70

  
71
        assert_equal 3, assigns(:limit)
72
        assert_equal 2, assigns(:offset)
73
        assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
74
      end
75
    end
76

  
77
    context "with nometa param" do
78
      should "not contain metadata" do
79
        get '/issues.xml?nometa=1'
80

  
81
        assert_tag :tag => 'issues',
82
          :attributes => {
83
            :type => 'array',
84
            :total_count => nil,
85
            :limit => nil,
86
            :offset => nil
87
          }
88
      end
89
    end
90

  
91
    context "with nometa header" do
92
      should "not contain metadata" do
93
        get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
94

  
95
        assert_tag :tag => 'issues',
96
          :attributes => {
97
            :type => 'array',
98
            :total_count => nil,
99
            :limit => nil,
100
            :offset => nil
101
          }
102
      end
103
    end
104

  
105
    context "with relations" do
106
      should "display relations" do
107
        get '/issues.xml?include=relations'
108

  
109
        assert_response :success
110
        assert_equal 'application/xml', @response.content_type
111
        assert_tag 'relations',
112
          :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
113
          :children => {:count => 1},
114
          :child => {
115
            :tag => 'relation',
116
            :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'}
117
          }
118
        assert_tag 'relations',
119
          :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
120
          :children => {:count => 0}
121
      end
122
    end
123

  
124
    context "with invalid query params" do
125
      should "return errors" do
126
        get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
127

  
128
        assert_response :unprocessable_entity
129
        assert_equal 'application/xml', @response.content_type
130
        assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
131
      end
132
    end
133

  
134
    context "with custom field filter" do
135
      should "show only issues with the custom field value" do
136
        get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}}
137

  
138
        expected_ids = Issue.visible.all(
139
            :include => :custom_values,
140
            :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
141

  
142
        assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
143
           ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
144
        end
145
      end
146
    end
147

  
148
    context "with custom field filter (shorthand method)" do
149
      should "show only issues with the custom field value" do
150
        get '/issues.xml', { :cf_1 => 'MySQL' }
151

  
152
        expected_ids = Issue.visible.all(
153
            :include => :custom_values,
154
            :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
155

  
156
        assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
157
          ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
158
        end
159
      end
160
    end
161
  end
162

  
163
  context "/index.json" do
164
    should_allow_api_authentication(:get, "/projects/private-child/issues.json")
165
  end
166

  
167
  context "/index.xml with filter" do
168
    should "show only issues with the status_id" do
169
      get '/issues.xml?status_id=5'
170

  
171
      expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
172

  
173
      assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
174
         ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
175
      end
176
    end
177
  end
178

  
179
  context "/index.json with filter" do
180
    should "show only issues with the status_id" do
181
      get '/issues.json?status_id=5'
182

  
183
      json = ActiveSupport::JSON.decode(response.body)
184
      status_ids_used = json['issues'].collect {|j| j['status']['id'] }
185
      assert_equal 3, status_ids_used.length
186
      assert status_ids_used.all? {|id| id == 5 }
187
    end
188

  
189
  end
190

  
191
  # Issue 6 is on a private project
192
  context "/issues/6.xml" do
193
    should_allow_api_authentication(:get, "/issues/6.xml")
194
  end
195

  
196
  context "/issues/6.json" do
197
    should_allow_api_authentication(:get, "/issues/6.json")
198
  end
199

  
200
  context "GET /issues/:id" do
201
    context "with journals" do
202
      context ".xml" do
203
        should "display journals" do
204
          get '/issues/1.xml?include=journals'
205

  
206
          assert_tag :tag => 'issue',
207
            :child => {
208
              :tag => 'journals',
209
              :attributes => { :type => 'array' },
210
              :child => {
211
                :tag => 'journal',
212
                :attributes => { :id => '1'},
213
                :child => {
214
                  :tag => 'details',
215
                  :attributes => { :type => 'array' },
216
                  :child => {
217
                    :tag => 'detail',
218
                    :attributes => { :name => 'status_id' },
219
                    :child => {
220
                      :tag => 'old_value',
221
                      :content => '1',
222
                      :sibling => {
223
                        :tag => 'new_value',
224
                        :content => '2'
225
                      }
226
                    }
227
                  }
228
                }
229
              }
230
            }
231
        end
232
      end
233
    end
234

  
235
    context "with custom fields" do
236
      context ".xml" do
237
        should "display custom fields" do
238
          get '/issues/3.xml'
239

  
240
          assert_tag :tag => 'issue',
241
            :child => {
242
              :tag => 'custom_fields',
243
              :attributes => { :type => 'array' },
244
              :child => {
245
                :tag => 'custom_field',
246
                :attributes => { :id => '1'},
247
                :child => {
248
                  :tag => 'value',
249
                  :content => 'MySQL'
250
                }
251
              }
252
            }
253

  
254
          assert_nothing_raised do
255
            Hash.from_xml(response.body).to_xml
256
          end
257
        end
258
      end
259
    end
260

  
261
    context "with attachments" do
262
      context ".xml" do
263
        should "display attachments" do
264
          get '/issues/3.xml?include=attachments'
265

  
266
          assert_tag :tag => 'issue',
267
            :child => {
268
              :tag => 'attachments',
269
              :children => {:count => 5},
270
              :child => {
271
                :tag => 'attachment',
272
                :child => {
273
                  :tag => 'filename',
274
                  :content => 'source.rb',
275
                  :sibling => {
276
                    :tag => 'content_url',
277
                    :content => 'http://www.example.com/attachments/download/4/source.rb'
278
                  }
279
                }
280
              }
281
            }
282
        end
283
      end
284
    end
285

  
286
    context "with subtasks" do
287
      setup do
288
        @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
289
        @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
290
        @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
291
      end
292

  
293
      context ".xml" do
294
        should "display children" do
295
          get '/issues/1.xml?include=children'
296

  
297
          assert_tag :tag => 'issue',
298
            :child => {
299
              :tag => 'children',
300
              :children => {:count => 2},
301
              :child => {
302
                :tag => 'issue',
303
                :attributes => {:id => @c1.id.to_s},
304
                :child => {
305
                  :tag => 'subject',
306
                  :content => 'child c1',
307
                  :sibling => {
308
                    :tag => 'children',
309
                    :children => {:count => 1},
310
                    :child => {
311
                      :tag => 'issue',
312
                      :attributes => {:id => @c3.id.to_s}
313
                    }
314
                  }
315
                }
316
              }
317
            }
318
        end
319

  
320
        context ".json" do
321
          should "display children" do
322
            get '/issues/1.json?include=children'
323

  
324
            json = ActiveSupport::JSON.decode(response.body)
325
            assert_equal([
326
              {
327
                'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
328
                'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
329
              },
330
              { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
331
              ],
332
              json['issue']['children'])
333
          end
334
        end
335
      end
336
    end
337
  end
338

  
339
  context "POST /issues.xml" do
340
    should_allow_api_authentication(:post,
341
                                    '/issues.xml',
342
                                    {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
343
                                    {:success_code => :created})
344

  
345
    should "create an issue with the attributes" do
346
      assert_difference('Issue.count') do
347
        post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
348
      end
349

  
350
      issue = Issue.first(:order => 'id DESC')
351
      assert_equal 1, issue.project_id
352
      assert_equal 2, issue.tracker_id
353
      assert_equal 3, issue.status_id
354
      assert_equal 'API test', issue.subject
355

  
356
      assert_response :created
357
      assert_equal 'application/xml', @response.content_type
358
      assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
359
    end
360
  end
361

  
362
  context "POST /issues.xml with failure" do
363
    should "have an errors tag" do
364
      assert_no_difference('Issue.count') do
365
        post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
366
      end
367

  
368
      assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
369
    end
370
  end
371

  
372
  context "POST /issues.json" do
373
    should_allow_api_authentication(:post,
374
                                    '/issues.json',
375
                                    {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
376
                                    {:success_code => :created})
377

  
378
    should "create an issue with the attributes" do
379
      assert_difference('Issue.count') do
380
        post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
381
      end
382

  
383
      issue = Issue.first(:order => 'id DESC')
384
      assert_equal 1, issue.project_id
385
      assert_equal 2, issue.tracker_id
386
      assert_equal 3, issue.status_id
387
      assert_equal 'API test', issue.subject
388
    end
389

  
390
  end
391

  
392
  context "POST /issues.json with failure" do
393
    should "have an errors element" do
394
      assert_no_difference('Issue.count') do
395
        post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
396
      end
397

  
398
      json = ActiveSupport::JSON.decode(response.body)
399
      assert json['errors'].include?(['subject', "can't be blank"])
400
    end
401
  end
402

  
403
  # Issue 6 is on a private project
404
  context "PUT /issues/6.xml" do
405
    setup do
406
      @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
407
      @headers = { :authorization => credentials('jsmith') }
408
    end
409

  
410
    should_allow_api_authentication(:put,
411
                                    '/issues/6.xml',
412
                                    {:issue => {:subject => 'API update', :notes => 'A new note'}},
413
                                    {:success_code => :ok})
414

  
415
    should "not create a new issue" do
416
      assert_no_difference('Issue.count') do
417
        put '/issues/6.xml', @parameters, @headers
418
      end
419
    end
420

  
421
    should "create a new journal" do
422
      assert_difference('Journal.count') do
423
        put '/issues/6.xml', @parameters, @headers
424
      end
425
    end
426

  
427
    should "add the note to the journal" do
428
      put '/issues/6.xml', @parameters, @headers
429

  
430
      journal = Journal.last
431
      assert_equal "A new note", journal.notes
432
    end
433

  
434
    should "update the issue" do
435
      put '/issues/6.xml', @parameters, @headers
436

  
437
      issue = Issue.find(6)
438
      assert_equal "API update", issue.subject
439
    end
440

  
441
  end
442

  
443
  context "PUT /issues/3.xml with custom fields" do
444
    setup do
445
      @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
446
      @headers = { :authorization => credentials('jsmith') }
447
    end
448

  
449
    should "update custom fields" do
450
      assert_no_difference('Issue.count') do
451
        put '/issues/3.xml', @parameters, @headers
452
      end
453

  
454
      issue = Issue.find(3)
455
      assert_equal '150', issue.custom_value_for(2).value
456
      assert_equal 'PostgreSQL', issue.custom_value_for(1).value
457
    end
458
  end
459

  
460
  context "PUT /issues/6.xml with failed update" do
461
    setup do
462
      @parameters = {:issue => {:subject => ''}}
463
      @headers = { :authorization => credentials('jsmith') }
464
    end
465

  
466
    should "not create a new issue" do
467
      assert_no_difference('Issue.count') do
468
        put '/issues/6.xml', @parameters, @headers
469
      end
470
    end
471

  
472
    should "not create a new journal" do
473
      assert_no_difference('Journal.count') do
474
        put '/issues/6.xml', @parameters, @headers
475
      end
476
    end
477

  
478
    should "have an errors tag" do
479
      put '/issues/6.xml', @parameters, @headers
480

  
481
      assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
482
    end
483
  end
484

  
485
  context "PUT /issues/6.json" do
486
    setup do
487
      @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
488
      @headers = { :authorization => credentials('jsmith') }
489
    end
490

  
491
    should_allow_api_authentication(:put,
492
                                    '/issues/6.json',
493
                                    {:issue => {:subject => 'API update', :notes => 'A new note'}},
494
                                    {:success_code => :ok})
495

  
496
    should "not create a new issue" do
497
      assert_no_difference('Issue.count') do
498
        put '/issues/6.json', @parameters, @headers
499
      end
500
    end
501

  
502
    should "create a new journal" do
503
      assert_difference('Journal.count') do
504
        put '/issues/6.json', @parameters, @headers
505
      end
506
    end
507

  
508
    should "add the note to the journal" do
509
      put '/issues/6.json', @parameters, @headers
510

  
511
      journal = Journal.last
512
      assert_equal "A new note", journal.notes
513
    end
514

  
515
    should "update the issue" do
516
      put '/issues/6.json', @parameters, @headers
517

  
518
      issue = Issue.find(6)
519
      assert_equal "API update", issue.subject
520
    end
521

  
522
  end
523

  
524
  context "PUT /issues/6.json with failed update" do
525
    setup do
526
      @parameters = {:issue => {:subject => ''}}
527
      @headers = { :authorization => credentials('jsmith') }
528
    end
529

  
530
    should "not create a new issue" do
531
      assert_no_difference('Issue.count') do
532
        put '/issues/6.json', @parameters, @headers
533
      end
534
    end
535

  
536
    should "not create a new journal" do
537
      assert_no_difference('Journal.count') do
538
        put '/issues/6.json', @parameters, @headers
539
      end
540
    end
541

  
542
    should "have an errors attribute" do
543
      put '/issues/6.json', @parameters, @headers
544

  
545
      json = ActiveSupport::JSON.decode(response.body)
546
      assert json['errors'].include?(['subject', "can't be blank"])
547
    end
548
  end
549

  
550
  context "DELETE /issues/1.xml" do
551
    should_allow_api_authentication(:delete,
552
                                    '/issues/6.xml',
553
                                    {},
554
                                    {:success_code => :ok})
555

  
556
    should "delete the issue" do
557
      assert_difference('Issue.count',-1) do
558
        delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
559
      end
560

  
561
      assert_nil Issue.find_by_id(6)
562
    end
563
  end
564

  
565
  context "DELETE /issues/1.json" do
566
    should_allow_api_authentication(:delete,
567
                                    '/issues/6.json',
568
                                    {},
569
                                    {:success_code => :ok})
570

  
571
    should "delete the issue" do
572
      assert_difference('Issue.count',-1) do
573
        delete '/issues/6.json', {}, :authorization => credentials('jsmith')
574
      end
575

  
576
      assert_nil Issue.find_by_id(6)
577
    end
578
  end
579

  
580
  def credentials(user, password=nil)
581
    ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
582
  end
583
end
.svn/pristine/2b/2b22d90c6bc0187f71e0f86b9bffc12dccfc3f03.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2013  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../test_helper', __FILE__)
19

  
20
class ProjectCopyTest < ActiveSupport::TestCase
21
  fixtures :projects, :trackers, :issue_statuses, :issues,
22
           :journals, :journal_details,
23
           :enumerations, :users, :issue_categories,
24
           :projects_trackers,
25
           :custom_fields,
26
           :custom_fields_projects,
27
           :custom_fields_trackers,
28
           :custom_values,
29
           :roles,
30
           :member_roles,
31
           :members,
32
           :enabled_modules,
33
           :versions,
34
           :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
35
           :groups_users,
36
           :boards, :messages,
37
           :repositories,
38
           :news, :comments,
39
           :documents
40

  
41
  def setup
42
    ProjectCustomField.destroy_all
43
    @source_project = Project.find(2)
44
    @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test')
45
    @project.trackers = @source_project.trackers
46
    @project.enabled_module_names = @source_project.enabled_modules.collect(&:name)
47
  end
48

  
49
  test "#copy should copy issues" do
50
    @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'),
51
                                              :subject => "copy issue status",
52
                                              :tracker_id => 1,
53
                                              :assigned_to_id => 2,
54
                                              :project_id => @source_project.id)
55
    assert @project.valid?
56
    assert @project.issues.empty?
57
    assert @project.copy(@source_project)
58

  
59
    assert_equal @source_project.issues.size, @project.issues.size
60
    @project.issues.each do |issue|
61
      assert issue.valid?
62
      assert ! issue.assigned_to.blank?
63
      assert_equal @project, issue.project
64
    end
65

  
66
    copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"})
67
    assert copied_issue
68
    assert copied_issue.status
69
    assert_equal "Closed", copied_issue.status.name
70
  end
71

  
72
  test "#copy should copy issues custom values" do
73
    field = IssueCustomField.generate!(:is_for_all => true, :trackers => Tracker.all)
74
    issue = Issue.generate!(:project => @source_project, :subject => 'Custom field copy')
75
    issue.custom_field_values = {field.id => 'custom'}
76
    issue.save!
77
    assert_equal 'custom', issue.reload.custom_field_value(field)
78

  
79
    assert @project.copy(@source_project)
80
    copy = @project.issues.find_by_subject('Custom field copy')
81
    assert copy
82
    assert_equal 'custom', copy.reload.custom_field_value(field)
83
  end
84

  
85
  test "#copy should copy issues assigned to a locked version" do
86
    User.current = User.find(1)
87
    assigned_version = Version.generate!(:name => "Assigned Issues")
88
    @source_project.versions << assigned_version
89
    Issue.generate!(:project => @source_project,
90
                    :fixed_version_id => assigned_version.id,
91
                    :subject => "copy issues assigned to a locked version")
92
    assigned_version.update_attribute :status, 'locked'
93

  
94
    assert @project.copy(@source_project)
95
    @project.reload
96
    copied_issue = @project.issues.first(:conditions => {:subject => "copy issues assigned to a locked version"})
97

  
98
    assert copied_issue
99
    assert copied_issue.fixed_version
100
    assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
101
    assert_equal 'locked', copied_issue.fixed_version.status
102
  end
103

  
104
  test "#copy should change the new issues to use the copied version" do
105
    User.current = User.find(1)
106
    assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open')
107
    @source_project.versions << assigned_version
108
    assert_equal 3, @source_project.versions.size
109
    Issue.generate!(:project => @source_project,
110
                    :fixed_version_id => assigned_version.id,
111
                    :subject => "change the new issues to use the copied version")
112

  
113
    assert @project.copy(@source_project)
114
    @project.reload
115
    copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"})
116

  
117
    assert copied_issue
118
    assert copied_issue.fixed_version
119
    assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
120
    assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record
121
  end
122

  
123
  test "#copy should keep target shared versions from other project" do
124
    assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open', :project_id => 1, :sharing => 'system')
125
    issue = Issue.generate!(:project => @source_project,
126
                            :fixed_version => assigned_version,
127
                            :subject => "keep target shared versions")
128

  
129
    assert @project.copy(@source_project)
130
    @project.reload
131
    copied_issue = @project.issues.first(:conditions => {:subject => "keep target shared versions"})
132

  
133
    assert copied_issue
134
    assert_equal assigned_version, copied_issue.fixed_version
135
  end
136

  
137
  test "#copy should copy issue relations" do
138
    Setting.cross_project_issue_relations = '1'
139

  
140
    second_issue = Issue.generate!(:status_id => 5,
141
                                   :subject => "copy issue relation",
142
                                   :tracker_id => 1,
143
                                   :assigned_to_id => 2,
144
                                   :project_id => @source_project.id)
145
    source_relation = IssueRelation.create!(:issue_from => Issue.find(4),
146
                                              :issue_to => second_issue,
147
                                              :relation_type => "relates")
148
    source_relation_cross_project = IssueRelation.create!(:issue_from => Issue.find(1),
149
                                                            :issue_to => second_issue,
150
                                                            :relation_type => "duplicates")
151

  
152
    assert @project.copy(@source_project)
153
    assert_equal @source_project.issues.count, @project.issues.count
154
    copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4
155
    copied_second_issue = @project.issues.find_by_subject("copy issue relation")
156

  
157
    # First issue with a relation on project
158
    assert_equal 1, copied_issue.relations.size, "Relation not copied"
159
    copied_relation = copied_issue.relations.first
160
    assert_equal "relates", copied_relation.relation_type
161
    assert_equal copied_second_issue.id, copied_relation.issue_to_id
162
    assert_not_equal source_relation.id, copied_relation.id
163

  
164
    # Second issue with a cross project relation
165
    assert_equal 2, copied_second_issue.relations.size, "Relation not copied"
166
    copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first
167
    assert_equal "duplicates", copied_relation.relation_type
168
    assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept"
169
    assert_not_equal source_relation_cross_project.id, copied_relation.id
170
  end
171

  
172
  test "#copy should copy issue attachments" do
173
    issue = Issue.generate!(:subject => "copy with attachment", :tracker_id => 1, :project_id => @source_project.id)
174
    Attachment.create!(:container => issue, :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 1)
175
    @source_project.issues << issue
176
    assert @project.copy(@source_project)
177

  
178
    copied_issue = @project.issues.first(:conditions => {:subject => "copy with attachment"})
179
    assert_not_nil copied_issue
180
    assert_equal 1, copied_issue.attachments.count, "Attachment not copied"
181
    assert_equal "testfile.txt", copied_issue.attachments.first.filename
182
  end
183

  
184
  test "#copy should copy memberships" do
185
    assert @project.valid?
186
    assert @project.members.empty?
187
    assert @project.copy(@source_project)
188

  
189
    assert_equal @source_project.memberships.size, @project.memberships.size
190
    @project.memberships.each do |membership|
191
      assert membership
192
      assert_equal @project, membership.project
193
    end
194
  end
195

  
196
  test "#copy should copy memberships with groups and additional roles" do
197
    group = Group.create!(:lastname => "Copy group")
198
    user = User.find(7)
199
    group.users << user
200
    # group role
201
    Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2])
202
    member = Member.find_by_user_id_and_project_id(user.id, @source_project.id)
203
    # additional role
204
    member.role_ids = [1]
205

  
206
    assert @project.copy(@source_project)
207
    member = Member.find_by_user_id_and_project_id(user.id, @project.id)
208
    assert_not_nil member
209
    assert_equal [1, 2], member.role_ids.sort
210
  end
211

  
212
  test "#copy should copy project specific queries" do
213
    assert @project.valid?
214
    assert @project.queries.empty?
215
    assert @project.copy(@source_project)
216

  
217
    assert_equal @source_project.queries.size, @project.queries.size
218
    @project.queries.each do |query|
219
      assert query
220
      assert_equal @project, query.project
221
    end
222
    assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
223
  end
224

  
225
  test "#copy should copy versions" do
226
    @source_project.versions << Version.generate!
227
    @source_project.versions << Version.generate!
228

  
229
    assert @project.versions.empty?
230
    assert @project.copy(@source_project)
231

  
232
    assert_equal @source_project.versions.size, @project.versions.size
233
    @project.versions.each do |version|
234
      assert version
235
      assert_equal @project, version.project
236
    end
237
  end
238

  
239
  test "#copy should copy wiki" do
240
    assert_difference 'Wiki.count' do
241
      assert @project.copy(@source_project)
242
    end
243

  
244
    assert @project.wiki
245
    assert_not_equal @source_project.wiki, @project.wiki
246
    assert_equal "Start page", @project.wiki.start_page
247
  end
248

  
249
  test "#copy should copy wiki without wiki module" do
250
    project = Project.new(:name => 'Copy Test', :identifier => 'copy-test', :enabled_module_names => [])
251
    assert_difference 'Wiki.count' do
252
      assert project.copy(@source_project)
253
    end
254

  
255
    assert project.wiki
256
  end
257

  
258
  test "#copy should copy wiki pages and content with hierarchy" do
259
    assert_difference 'WikiPage.count', @source_project.wiki.pages.size do
260
      assert @project.copy(@source_project)
261
    end
262

  
263
    assert @project.wiki
264
    assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size
265

  
266
    @project.wiki.pages.each do |wiki_page|
267
      assert wiki_page.content
268
      assert !@source_project.wiki.pages.include?(wiki_page)
269
    end
270

  
271
    parent = @project.wiki.find_page('Parent_page')
272
    child1 = @project.wiki.find_page('Child_page_1')
273
    child2 = @project.wiki.find_page('Child_page_2')
274
    assert_equal parent, child1.parent
275
    assert_equal parent, child2.parent
276
  end
277

  
278
  test "#copy should copy issue categories" do
279
    assert @project.copy(@source_project)
280

  
281
    assert_equal 2, @project.issue_categories.size
282
    @project.issue_categories.each do |issue_category|
283
      assert !@source_project.issue_categories.include?(issue_category)
284
    end
285
  end
286

  
287
  test "#copy should copy boards" do
288
    assert @project.copy(@source_project)
289

  
290
    assert_equal 1, @project.boards.size
291
    @project.boards.each do |board|
292
      assert !@source_project.boards.include?(board)
293
    end
294
  end
295

  
296
  test "#copy should change the new issues to use the copied issue categories" do
297
    issue = Issue.find(4)
298
    issue.update_attribute(:category_id, 3)
299

  
300
    assert @project.copy(@source_project)
301

  
302
    @project.issues.each do |issue|
303
      assert issue.category
304
      assert_equal "Stock management", issue.category.name # Same name
305
      assert_not_equal IssueCategory.find(3), issue.category # Different record
306
    end
307
  end
308

  
309
  test "#copy should limit copy with :only option" do
310
    assert @project.members.empty?
311
    assert @project.issue_categories.empty?
312
    assert @source_project.issues.any?
313

  
314
    assert @project.copy(@source_project, :only => ['members', 'issue_categories'])
315

  
316
    assert @project.members.any?
317
    assert @project.issue_categories.any?
318
    assert @project.issues.empty?
319
  end
320

  
321
  test "#copy should copy subtasks" do
322
    source = Project.generate!(:tracker_ids => [1])
323
    issue = Issue.generate_with_descendants!(:project => source)
324
    project = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1])
325

  
326
    assert_difference 'Project.count' do
327
      assert_difference 'Issue.count', 1+issue.descendants.count do
328
        assert project.copy(source.reload)
329
      end
330
    end
331
    copy = Issue.where(:parent_id => nil).order("id DESC").first
332
    assert_equal project, copy.project
333
    assert_equal issue.descendants.count, copy.descendants.count
334
    child_copy = copy.children.detect {|c| c.subject == 'Child1'}
335
    assert child_copy.descendants.any?
336
  end
337
end
.svn/pristine/2b/2b52b333ebdd9a328bfca27bab6d9bb1f5c45425.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2013  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
class ActivitiesController < ApplicationController
19
  menu_item :activity
20
  before_filter :find_optional_project
21
  accept_rss_auth :index
22

  
23
  def index
24
    @days = Setting.activity_days_default.to_i
25

  
26
    if params[:from]
27
      begin; @date_to = params[:from].to_date + 1; rescue; end
28
    end
29

  
30
    @date_to ||= Date.today + 1
31
    @date_from = @date_to - @days
32
    @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
33
    @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id]))
34

  
35
    @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project,
36
                                                             :with_subprojects => @with_subprojects,
37
                                                             :author => @author)
38
    @activity.scope_select {|t| !params["show_#{t}"].nil?}
39
    @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty?
40

  
41
    events = @activity.events(@date_from, @date_to)
42

  
43
    if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, events.size, User.current, current_language])
44
      respond_to do |format|
45
        format.html {
46
          @events_by_day = events.group_by {|event| User.current.time_to_date(event.event_datetime)}
47
          render :layout => false if request.xhr?
48
        }
49
        format.atom {
50
          title = l(:label_activity)
51
          if @author
52
            title = @author.name
53
          elsif @activity.scope.size == 1
54
            title = l("label_#{@activity.scope.first.singularize}_plural")
55
          end
56
          render_feed(events, :title => "#{@project || Setting.app_title}: #{title}")
57
        }
58
      end
59
    end
60

  
61
  rescue ActiveRecord::RecordNotFound
62
    render_404
63
  end
64

  
65
  private
66

  
67
  # TODO: refactor, duplicated in projects_controller
68
  def find_optional_project
69
    return true unless params[:id]
70
    @project = Project.find(params[:id])
71
    authorize
72
  rescue ActiveRecord::RecordNotFound
73
    render_404
74
  end
75
end
.svn/pristine/2b/2b8d3c9c3c263ae7cd6f97cc6dd5f192b92ebd2b.svn-base
1
# The MIT License
2
#
3
# Permission is hereby granted, free of charge, to any person obtaining a copy
4
# of this software and associated documentation files (the "Software"), to deal
5
# in the Software without restriction, including without limitation the rights
6
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
# copies of the Software, and to permit persons to whom the Software is
8
# furnished to do so, subject to the following conditions:
9
#
10
# The above copyright notice and this permission notice shall be included in
11
# all copies or substantial portions of the Software.
12
#
13
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
16
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
# THE SOFTWARE.
20
#
21
# This implements native php methods used by tcpdf, which have had to be
22
# reimplemented within Ruby.
23

  
24
module RFPDF
25

  
26
  # http://uk2.php.net/getimagesize
27
  def getimagesize(filename)
28
    image = Magick::ImageList.new(filename)
29
    
30
    out = Hash.new
31
    out[0] = image.columns
32
    out[1] = image.rows
33
    
34
    # These are actually meant to return integer values But I couldn't seem to find anything saying what those values are.
35
    # So for now they return strings. The only place that uses this at the moment is the parsejpeg method, so I've changed that too.
36
    case image.mime_type
37
    when "image/gif"
38
      out[2] = "GIF"
39
    when "image/jpeg"
40
      out[2] = "JPEG"
41
    when "image/png"
42
      out[2] = "PNG"
43
    when " 	image/vnd.wap.wbmp"
44
      out[2] = "WBMP"
45
    when "image/x-xpixmap"
46
      out[2] = "XPM"
47
    end
48
    out[3] = "height=\"#{image.rows}\" width=\"#{image.columns}\""
49
    out['mime'] = image.mime_type
50
    
51
    # This needs work to cover more situations
52
    # I can't see how to just list the number of channels with ImageMagick / rmagick
53
    if image.colorspace.to_s == "CMYKColorspace"
54
        out['channels'] = 4
55
    elsif image.colorspace.to_s == "RGBColorspace"
56
      out['channels'] = 3
57
    end
58

  
59
    out['bits'] = image.channel_depth
60
    File.open( TCPDF.k_path_cache + File::basename(filename), 'w'){|f|
61
      f.binmode
62
      f.print image.to_blob
63
      f.close
64
    }
65
    
66
    out
67
  end
68
  
69
end
.svn/pristine/2b/2b9b5932a0933b4096addb68309527dfbf45da2c.svn-base
1
<% if version.completed? %>
2
  <p><%= format_date(version.effective_date) %></p>
3
<% elsif version.effective_date %>
4
  <p><strong><%= due_date_distance_in_words(version.effective_date) %></strong> (<%= format_date(version.effective_date) %>)</p>
5
<% end %>
6

  
7
<p><%=h version.description %></p>
8
<% if version.custom_field_values.any? %>
9
<ul>
10
  <% version.custom_field_values.each do |custom_value| %>
11
    <% if custom_value.value.present? %>
12
       <li><%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %></li>
13
    <% end %>
14
  <% end %>
15
</ul>
16
<% end %>
17

  
18
<% if version.issues_count > 0 %>
19
    <%= progress_bar([version.closed_percent, version.completed_percent], :width => '40em', :legend => ('%0.0f%' % version.completed_percent)) %>
20
    <p class="progress-info">
21
    	  <%= link_to(l(:label_x_issues, :count => version.issues_count), 
22
              project_issues_path(version.project, :status_id => '*', :fixed_version_id => version, :set_filter => 1)) %>
23
				&nbsp;
24
        (<%= link_to_if(version.closed_issues_count > 0, l(:label_x_closed_issues_abbr, :count => version.closed_issues_count), 
25
               project_issues_path(version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1)) %>
26
        &#8212;
27
        <%= link_to_if(version.open_issues_count > 0, l(:label_x_open_issues_abbr, :count => version.open_issues_count), 
28
              project_issues_path(version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1)) %>)
29
    </p>
30
<% else %>
31
    <p class="progress-info"><%= l(:label_roadmap_no_issues) %></p>
32
<% end %>

Also available in: Unified diff