##// END OF EJS Templates
Fixed: error when serializing back objects with custom fields using ActiveResource (#6403)....
Jean-Philippe Lang -
r4366:0e19aa4362a0
parent child
Show More
@@ -1,107 +1,118
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module CustomFieldsHelper
18 module CustomFieldsHelper
19
19
20 def custom_fields_tabs
20 def custom_fields_tabs
21 tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural},
21 tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural},
22 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time},
22 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time},
23 {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural},
23 {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural},
24 {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural},
24 {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural},
25 {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural},
25 {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural},
26 {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural},
26 {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural},
27 {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName},
27 {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName},
28 {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName},
28 {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName},
29 {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName}
29 {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName}
30 ]
30 ]
31 end
31 end
32
32
33 # Return custom field html tag corresponding to its format
33 # Return custom field html tag corresponding to its format
34 def custom_field_tag(name, custom_value)
34 def custom_field_tag(name, custom_value)
35 custom_field = custom_value.custom_field
35 custom_field = custom_value.custom_field
36 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
36 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
37 field_id = "#{name}_custom_field_values_#{custom_field.id}"
37 field_id = "#{name}_custom_field_values_#{custom_field.id}"
38
38
39 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
39 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
40 case field_format.edit_as
40 case field_format.edit_as
41 when "date"
41 when "date"
42 text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) +
42 text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) +
43 calendar_for(field_id)
43 calendar_for(field_id)
44 when "text"
44 when "text"
45 text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%')
45 text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%')
46 when "bool"
46 when "bool"
47 hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id)
47 hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id)
48 when "list"
48 when "list"
49 blank_option = custom_field.is_required? ?
49 blank_option = custom_field.is_required? ?
50 (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
50 (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
51 '<option></option>'
51 '<option></option>'
52 select_tag(field_name, blank_option + options_for_select(custom_field.possible_values, custom_value.value), :id => field_id)
52 select_tag(field_name, blank_option + options_for_select(custom_field.possible_values, custom_value.value), :id => field_id)
53 else
53 else
54 text_field_tag(field_name, custom_value.value, :id => field_id)
54 text_field_tag(field_name, custom_value.value, :id => field_id)
55 end
55 end
56 end
56 end
57
57
58 # Return custom field label tag
58 # Return custom field label tag
59 def custom_field_label_tag(name, custom_value)
59 def custom_field_label_tag(name, custom_value)
60 content_tag "label", custom_value.custom_field.name +
60 content_tag "label", custom_value.custom_field.name +
61 (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
61 (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
62 :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
62 :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
63 :class => (custom_value.errors.empty? ? nil : "error" )
63 :class => (custom_value.errors.empty? ? nil : "error" )
64 end
64 end
65
65
66 # Return custom field tag with its label tag
66 # Return custom field tag with its label tag
67 def custom_field_tag_with_label(name, custom_value)
67 def custom_field_tag_with_label(name, custom_value)
68 custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
68 custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
69 end
69 end
70
70
71 def custom_field_tag_for_bulk_edit(name, custom_field)
71 def custom_field_tag_for_bulk_edit(name, custom_field)
72 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
72 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
73 field_id = "#{name}_custom_field_values_#{custom_field.id}"
73 field_id = "#{name}_custom_field_values_#{custom_field.id}"
74 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
74 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
75 case field_format.edit_as
75 case field_format.edit_as
76 when "date"
76 when "date"
77 text_field_tag(field_name, '', :id => field_id, :size => 10) +
77 text_field_tag(field_name, '', :id => field_id, :size => 10) +
78 calendar_for(field_id)
78 calendar_for(field_id)
79 when "text"
79 when "text"
80 text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%')
80 text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%')
81 when "bool"
81 when "bool"
82 select_tag(field_name, options_for_select([[l(:label_no_change_option), ''],
82 select_tag(field_name, options_for_select([[l(:label_no_change_option), ''],
83 [l(:general_text_yes), '1'],
83 [l(:general_text_yes), '1'],
84 [l(:general_text_no), '0']]), :id => field_id)
84 [l(:general_text_no), '0']]), :id => field_id)
85 when "list"
85 when "list"
86 select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values), :id => field_id)
86 select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values), :id => field_id)
87 else
87 else
88 text_field_tag(field_name, '', :id => field_id)
88 text_field_tag(field_name, '', :id => field_id)
89 end
89 end
90 end
90 end
91
91
92 # Return a string used to display a custom value
92 # Return a string used to display a custom value
93 def show_value(custom_value)
93 def show_value(custom_value)
94 return "" unless custom_value
94 return "" unless custom_value
95 format_value(custom_value.value, custom_value.custom_field.field_format)
95 format_value(custom_value.value, custom_value.custom_field.field_format)
96 end
96 end
97
97
98 # Return a string used to display a custom value
98 # Return a string used to display a custom value
99 def format_value(value, field_format)
99 def format_value(value, field_format)
100 Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy
100 Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy
101 end
101 end
102
102
103 # Return an array of custom field formats which can be used in select_tag
103 # Return an array of custom field formats which can be used in select_tag
104 def custom_field_formats_for_select
104 def custom_field_formats_for_select
105 Redmine::CustomFieldFormat.as_select
105 Redmine::CustomFieldFormat.as_select
106 end
106 end
107
108 # Renders the custom_values in api views
109 def render_api_custom_values(custom_values, api)
110 api.array :custom_fields do
111 custom_values.each do |custom_value|
112 api.custom_field :id => custom_value.custom_field_id, :name => custom_value.custom_field.name do
113 api.value custom_value.value
114 end
115 end
116 end unless custom_values.empty?
117 end
107 end
118 end
@@ -1,32 +1,28
1 api.array :issues do
1 api.array :issues do
2 @issues.each do |issue|
2 @issues.each do |issue|
3 api.issue do
3 api.issue do
4 api.id issue.id
4 api.id issue.id
5 api.project(:id => issue.project_id, :name => issue.project.name) unless issue.project.nil?
5 api.project(:id => issue.project_id, :name => issue.project.name) unless issue.project.nil?
6 api.tracker(:id => issue.tracker_id, :name => issue.tracker.name) unless issue.tracker.nil?
6 api.tracker(:id => issue.tracker_id, :name => issue.tracker.name) unless issue.tracker.nil?
7 api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil?
7 api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil?
8 api.priority(:id => issue.priority_id, :name => issue.priority.name) unless issue.priority.nil?
8 api.priority(:id => issue.priority_id, :name => issue.priority.name) unless issue.priority.nil?
9 api.author(:id => issue.author_id, :name => issue.author.name) unless issue.author.nil?
9 api.author(:id => issue.author_id, :name => issue.author.name) unless issue.author.nil?
10 api.assigned_to(:id => issue.assigned_to_id, :name => issue.assigned_to.name) unless issue.assigned_to.nil?
10 api.assigned_to(:id => issue.assigned_to_id, :name => issue.assigned_to.name) unless issue.assigned_to.nil?
11 api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil?
11 api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil?
12 api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil?
12 api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil?
13 api.parent(:id => issue.parent_id) unless issue.parent.nil?
13 api.parent(:id => issue.parent_id) unless issue.parent.nil?
14
14
15 api.subject issue.subject
15 api.subject issue.subject
16 api.description issue.description
16 api.description issue.description
17 api.start_date issue.start_date
17 api.start_date issue.start_date
18 api.due_date issue.due_date
18 api.due_date issue.due_date
19 api.done_ratio issue.done_ratio
19 api.done_ratio issue.done_ratio
20 api.estimated_hours issue.estimated_hours
20 api.estimated_hours issue.estimated_hours
21
21
22 api.array :custom_fields do
22 render_api_custom_values issue.custom_field_values, api
23 issue.custom_field_values.each do |custom_value|
24 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
25 end
26 end
27
23
28 api.created_on issue.created_on
24 api.created_on issue.created_on
29 api.updated_on issue.updated_on
25 api.updated_on issue.updated_on
30 end
26 end
31 end
27 end
32 end
28 end
@@ -1,63 +1,59
1 api.issue do
1 api.issue do
2 api.id @issue.id
2 api.id @issue.id
3 api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil?
3 api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil?
4 api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil?
4 api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil?
5 api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil?
5 api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil?
6 api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil?
6 api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil?
7 api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil?
7 api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil?
8 api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil?
8 api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil?
9 api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil?
9 api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil?
10 api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil?
10 api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil?
11 api.parent(:id => @issue.parent_id) unless @issue.parent.nil?
11 api.parent(:id => @issue.parent_id) unless @issue.parent.nil?
12
12
13 api.subject @issue.subject
13 api.subject @issue.subject
14 api.description @issue.description
14 api.description @issue.description
15 api.start_date @issue.start_date
15 api.start_date @issue.start_date
16 api.due_date @issue.due_date
16 api.due_date @issue.due_date
17 api.done_ratio @issue.done_ratio
17 api.done_ratio @issue.done_ratio
18 api.estimated_hours @issue.estimated_hours
18 api.estimated_hours @issue.estimated_hours
19 if User.current.allowed_to?(:view_time_entries, @project)
19 if User.current.allowed_to?(:view_time_entries, @project)
20 api.spent_hours @issue.spent_hours
20 api.spent_hours @issue.spent_hours
21 end
21 end
22
22
23 api.array :custom_fields do
23 render_api_custom_values @issue.custom_field_values, api
24 @issue.custom_field_values.each do |custom_value|
25 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
26 end
27 end unless @issue.custom_field_values.empty?
28
24
29 api.created_on @issue.created_on
25 api.created_on @issue.created_on
30 api.updated_on @issue.updated_on
26 api.updated_on @issue.updated_on
31
27
32 render_api_issue_children(@issue, api)
28 render_api_issue_children(@issue, api)
33
29
34 api.array :relations do
30 api.array :relations do
35 @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation|
31 @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation|
36 api.relation(:id => relation.id, :issue_id => relation.other_issue(@issue).id, :relation_type => relation.relation_type_for(@issue), :delay => relation.delay)
32 api.relation(:id => relation.id, :issue_id => relation.other_issue(@issue).id, :relation_type => relation.relation_type_for(@issue), :delay => relation.delay)
37 end
33 end
38 end
34 end
39
35
40 api.array :changesets do
36 api.array :changesets do
41 @issue.changesets.each do |changeset|
37 @issue.changesets.each do |changeset|
42 api.changeset :revision => changeset.revision do
38 api.changeset :revision => changeset.revision do
43 api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
39 api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
44 api.comments changeset.comments
40 api.comments changeset.comments
45 api.committed_on changeset.committed_on
41 api.committed_on changeset.committed_on
46 end
42 end
47 end
43 end
48 end if User.current.allowed_to?(:view_changesets, @project) && @issue.changesets.any?
44 end if User.current.allowed_to?(:view_changesets, @project) && @issue.changesets.any?
49
45
50 api.array :journals do
46 api.array :journals do
51 @issue.journals.each do |journal|
47 @issue.journals.each do |journal|
52 api.journal :id => journal.id do
48 api.journal :id => journal.id do
53 api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
49 api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
54 api.notes journal.notes
50 api.notes journal.notes
55 api.array :details do
51 api.array :details do
56 journal.details.each do |detail|
52 journal.details.each do |detail|
57 api.detail :property => detail.property, :name => detail.prop_key, :old => detail.old_value, :new => detail.value
53 api.detail :property => detail.property, :name => detail.prop_key, :old => detail.old_value, :new => detail.value
58 end
54 end
59 end
55 end
60 end
56 end
61 end
57 end
62 end unless @issue.journals.empty?
58 end unless @issue.journals.empty?
63 end
59 end
@@ -1,18 +1,16
1 api.array :projects do
1 api.array :projects do
2 @projects.each do |project|
2 @projects.each do |project|
3 api.project do
3 api.project do
4 api.id project.id
4 api.id project.id
5 api.name project.name
5 api.name project.name
6 api.identifier project.identifier
6 api.identifier project.identifier
7 api.description project.description
7 api.description project.description
8 api.parent(:id => project.parent_id, :name => project.parent.name) unless project.parent.nil?
8 api.parent(:id => project.parent_id, :name => project.parent.name) unless project.parent.nil?
9 api.array :custom_fields do
9
10 project.visible_custom_field_values.each do |custom_value|
10 render_api_custom_values project.visible_custom_field_values, api
11 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
11
12 end
13 end unless project.custom_field_values.empty?
14 api.created_on project.created_on
12 api.created_on project.created_on
15 api.updated_on project.updated_on
13 api.updated_on project.updated_on
16 end
14 end
17 end
15 end
18 end
16 end
@@ -1,22 +1,18
1 api.project do
1 api.project do
2 api.id @project.id
2 api.id @project.id
3 api.name @project.name
3 api.name @project.name
4 api.identifier @project.identifier
4 api.identifier @project.identifier
5 api.description @project.description
5 api.description @project.description
6 api.homepage @project.homepage
6 api.homepage @project.homepage
7
7
8 api.array :custom_fields do
8 render_api_custom_values @project.visible_custom_field_values, api
9 @project.visible_custom_field_values.each do |custom_value|
10 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
11 end
12 end unless @project.custom_field_values.empty?
13
9
14 api.created_on @project.created_on
10 api.created_on @project.created_on
15 api.updated_on @project.updated_on
11 api.updated_on @project.updated_on
16
12
17 api.array :trackers do
13 api.array :trackers do
18 @project.trackers.each do |tracker|
14 @project.trackers.each do |tracker|
19 api.tracker(:id => tracker.id, :name => tracker.name)
15 api.tracker(:id => tracker.id, :name => tracker.name)
20 end
16 end
21 end
17 end
22 end
18 end
@@ -1,19 +1,15
1 api.array :users do
1 api.array :users do
2 @users.each do |user|
2 @users.each do |user|
3 api.user do
3 api.user do
4 api.id user.id
4 api.id user.id
5 api.login user.login
5 api.login user.login
6 api.firstname user.firstname
6 api.firstname user.firstname
7 api.lastname user.lastname
7 api.lastname user.lastname
8 api.mail user.mail
8 api.mail user.mail
9 api.created_on user.created_on
9 api.created_on user.created_on
10 api.last_login_on user.last_login_on
10 api.last_login_on user.last_login_on
11
11
12 api.array :custom_fields do
12 render_api_custom_values user.visible_custom_field_values, api
13 user.visible_custom_field_values.each do |custom_value|
14 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
15 end
16 end unless user.visible_custom_field_values.empty?
17 end
13 end
18 end
14 end
19 end
15 end
@@ -1,28 +1,24
1 api.user do
1 api.user do
2 api.id @user.id
2 api.id @user.id
3 api.login @user.login if User.current.admin?
3 api.login @user.login if User.current.admin?
4 api.firstname @user.firstname
4 api.firstname @user.firstname
5 api.lastname @user.lastname
5 api.lastname @user.lastname
6 api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail
6 api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail
7 api.created_on @user.created_on
7 api.created_on @user.created_on
8 api.last_login_on @user.last_login_on
8 api.last_login_on @user.last_login_on
9
9
10 api.array :custom_fields do
10 render_api_custom_values @user.visible_custom_field_values, api
11 @user.visible_custom_field_values.each do |custom_value|
12 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
13 end
14 end unless @user.visible_custom_field_values.empty?
15
11
16 api.array :memberships do
12 api.array :memberships do
17 @memberships.each do |membership|
13 @memberships.each do |membership|
18 api.membership do
14 api.membership do
19 api.project :id => membership.project.id, :name => membership.project.name
15 api.project :id => membership.project.id, :name => membership.project.name
20 api.array :roles do
16 api.array :roles do
21 membership.roles.each do |role|
17 membership.roles.each do |role|
22 api.role :id => role.id, :name => role.name
18 api.role :id => role.id, :name => role.name
23 end
19 end
24 end
20 end
25 end if membership.project
21 end if membership.project
26 end
22 end
27 end if @memberships.present?
23 end if @memberships.present?
28 end
24 end
@@ -1,394 +1,420
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require "#{File.dirname(__FILE__)}/../../test_helper"
18 require "#{File.dirname(__FILE__)}/../../test_helper"
19
19
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :versions,
28 :versions,
29 :trackers,
29 :trackers,
30 :projects_trackers,
30 :projects_trackers,
31 :issue_categories,
31 :issue_categories,
32 :enabled_modules,
32 :enabled_modules,
33 :enumerations,
33 :enumerations,
34 :attachments,
34 :attachments,
35 :workflows,
35 :workflows,
36 :custom_fields,
36 :custom_fields,
37 :custom_values,
37 :custom_values,
38 :custom_fields_projects,
38 :custom_fields_projects,
39 :custom_fields_trackers,
39 :custom_fields_trackers,
40 :time_entries,
40 :time_entries,
41 :journals,
41 :journals,
42 :journal_details,
42 :journal_details,
43 :queries
43 :queries
44
44
45 def setup
45 def setup
46 Setting.rest_api_enabled = '1'
46 Setting.rest_api_enabled = '1'
47 end
47 end
48
48
49 # Use a private project to make sure auth is really working and not just
49 # Use a private project to make sure auth is really working and not just
50 # only showing public issues.
50 # only showing public issues.
51 context "/index.xml" do
51 context "/index.xml" do
52 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
52 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
53 end
53 end
54
54
55 context "/index.json" do
55 context "/index.json" do
56 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
56 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
57 end
57 end
58
58
59 context "/index.xml with filter" do
59 context "/index.xml with filter" do
60 should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5")
60 should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5")
61
61
62 should "show only issues with the status_id" do
62 should "show only issues with the status_id" do
63 get '/issues.xml?status_id=5'
63 get '/issues.xml?status_id=5'
64 assert_tag :tag => 'issues',
64 assert_tag :tag => 'issues',
65 :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}),
65 :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}),
66 :only => { :tag => 'issue' } }
66 :only => { :tag => 'issue' } }
67 end
67 end
68 end
68 end
69
69
70 context "/index.json with filter" do
70 context "/index.json with filter" do
71 should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5")
71 should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5")
72
72
73 should "show only issues with the status_id" do
73 should "show only issues with the status_id" do
74 get '/issues.json?status_id=5'
74 get '/issues.json?status_id=5'
75
75
76 json = ActiveSupport::JSON.decode(response.body)
76 json = ActiveSupport::JSON.decode(response.body)
77 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
77 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
78 assert_equal 3, status_ids_used.length
78 assert_equal 3, status_ids_used.length
79 assert status_ids_used.all? {|id| id == 5 }
79 assert status_ids_used.all? {|id| id == 5 }
80 end
80 end
81
81
82 end
82 end
83
83
84 # Issue 6 is on a private project
84 # Issue 6 is on a private project
85 context "/issues/6.xml" do
85 context "/issues/6.xml" do
86 should_allow_api_authentication(:get, "/issues/6.xml")
86 should_allow_api_authentication(:get, "/issues/6.xml")
87 end
87 end
88
88
89 context "/issues/6.json" do
89 context "/issues/6.json" do
90 should_allow_api_authentication(:get, "/issues/6.json")
90 should_allow_api_authentication(:get, "/issues/6.json")
91 end
91 end
92
92
93 context "GET /issues/:id" do
93 context "GET /issues/:id" do
94 context "with custom fields" do
95 context ".xml" do
96 should "display custom fields" do
97 get '/issues/3.xml'
98
99 assert_tag :tag => 'issue',
100 :child => {
101 :tag => 'custom_fields',
102 :attributes => { :type => 'array' },
103 :child => {
104 :tag => 'custom_field',
105 :attributes => { :id => '1'},
106 :child => {
107 :tag => 'value',
108 :content => 'MySQL'
109 }
110 }
111 }
112
113 assert_nothing_raised do
114 Hash.from_xml(response.body).to_xml
115 end
116 end
117 end
118 end
119
94 context "with subtasks" do
120 context "with subtasks" do
95 setup do
121 setup do
96 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
122 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
97 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
123 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
98 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
124 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
99 end
125 end
100
126
101 context ".xml" do
127 context ".xml" do
102 should "display children" do
128 should "display children" do
103 get '/issues/1.xml'
129 get '/issues/1.xml'
104
130
105 assert_tag :tag => 'issue',
131 assert_tag :tag => 'issue',
106 :child => {
132 :child => {
107 :tag => 'children',
133 :tag => 'children',
108 :children => {:count => 2},
134 :children => {:count => 2},
109 :child => {
135 :child => {
110 :tag => 'issue',
136 :tag => 'issue',
111 :attributes => {:id => @c1.id.to_s},
137 :attributes => {:id => @c1.id.to_s},
112 :child => {
138 :child => {
113 :tag => 'subject',
139 :tag => 'subject',
114 :content => 'child c1',
140 :content => 'child c1',
115 :sibling => {
141 :sibling => {
116 :tag => 'children',
142 :tag => 'children',
117 :children => {:count => 1},
143 :children => {:count => 1},
118 :child => {
144 :child => {
119 :tag => 'issue',
145 :tag => 'issue',
120 :attributes => {:id => @c3.id.to_s}
146 :attributes => {:id => @c3.id.to_s}
121 }
147 }
122 }
148 }
123 }
149 }
124 }
150 }
125 }
151 }
126 end
152 end
127
153
128 context ".json" do
154 context ".json" do
129 should "display children" do
155 should "display children" do
130 get '/issues/1.json'
156 get '/issues/1.json'
131
157
132 json = ActiveSupport::JSON.decode(response.body)
158 json = ActiveSupport::JSON.decode(response.body)
133 assert_equal([
159 assert_equal([
134 {
160 {
135 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
161 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
136 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
162 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
137 },
163 },
138 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
164 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
139 ],
165 ],
140 json['issue']['children'])
166 json['issue']['children'])
141 end
167 end
142 end
168 end
143 end
169 end
144 end
170 end
145 end
171 end
146
172
147 context "POST /issues.xml" do
173 context "POST /issues.xml" do
148 should_allow_api_authentication(:post,
174 should_allow_api_authentication(:post,
149 '/issues.xml',
175 '/issues.xml',
150 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
176 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
151 {:success_code => :created})
177 {:success_code => :created})
152
178
153 should "create an issue with the attributes" do
179 should "create an issue with the attributes" do
154 assert_difference('Issue.count') do
180 assert_difference('Issue.count') do
155 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
181 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
156 end
182 end
157
183
158 issue = Issue.first(:order => 'id DESC')
184 issue = Issue.first(:order => 'id DESC')
159 assert_equal 1, issue.project_id
185 assert_equal 1, issue.project_id
160 assert_equal 2, issue.tracker_id
186 assert_equal 2, issue.tracker_id
161 assert_equal 3, issue.status_id
187 assert_equal 3, issue.status_id
162 assert_equal 'API test', issue.subject
188 assert_equal 'API test', issue.subject
163
189
164 assert_response :created
190 assert_response :created
165 assert_equal 'application/xml', @response.content_type
191 assert_equal 'application/xml', @response.content_type
166 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
192 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
167 end
193 end
168 end
194 end
169
195
170 context "POST /issues.xml with failure" do
196 context "POST /issues.xml with failure" do
171 should_allow_api_authentication(:post,
197 should_allow_api_authentication(:post,
172 '/issues.xml',
198 '/issues.xml',
173 {:issue => {:project_id => 1}},
199 {:issue => {:project_id => 1}},
174 {:success_code => :unprocessable_entity})
200 {:success_code => :unprocessable_entity})
175
201
176 should "have an errors tag" do
202 should "have an errors tag" do
177 assert_no_difference('Issue.count') do
203 assert_no_difference('Issue.count') do
178 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
204 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
179 end
205 end
180
206
181 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
207 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
182 end
208 end
183 end
209 end
184
210
185 context "POST /issues.json" do
211 context "POST /issues.json" do
186 should_allow_api_authentication(:post,
212 should_allow_api_authentication(:post,
187 '/issues.json',
213 '/issues.json',
188 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
214 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
189 {:success_code => :created})
215 {:success_code => :created})
190
216
191 should "create an issue with the attributes" do
217 should "create an issue with the attributes" do
192 assert_difference('Issue.count') do
218 assert_difference('Issue.count') do
193 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
219 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
194 end
220 end
195
221
196 issue = Issue.first(:order => 'id DESC')
222 issue = Issue.first(:order => 'id DESC')
197 assert_equal 1, issue.project_id
223 assert_equal 1, issue.project_id
198 assert_equal 2, issue.tracker_id
224 assert_equal 2, issue.tracker_id
199 assert_equal 3, issue.status_id
225 assert_equal 3, issue.status_id
200 assert_equal 'API test', issue.subject
226 assert_equal 'API test', issue.subject
201 end
227 end
202
228
203 end
229 end
204
230
205 context "POST /issues.json with failure" do
231 context "POST /issues.json with failure" do
206 should_allow_api_authentication(:post,
232 should_allow_api_authentication(:post,
207 '/issues.json',
233 '/issues.json',
208 {:issue => {:project_id => 1}},
234 {:issue => {:project_id => 1}},
209 {:success_code => :unprocessable_entity})
235 {:success_code => :unprocessable_entity})
210
236
211 should "have an errors element" do
237 should "have an errors element" do
212 assert_no_difference('Issue.count') do
238 assert_no_difference('Issue.count') do
213 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
239 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
214 end
240 end
215
241
216 json = ActiveSupport::JSON.decode(response.body)
242 json = ActiveSupport::JSON.decode(response.body)
217 assert json['errors'].include?(['subject', "can't be blank"])
243 assert json['errors'].include?(['subject', "can't be blank"])
218 end
244 end
219 end
245 end
220
246
221 # Issue 6 is on a private project
247 # Issue 6 is on a private project
222 context "PUT /issues/6.xml" do
248 context "PUT /issues/6.xml" do
223 setup do
249 setup do
224 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
250 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
225 @headers = { :authorization => credentials('jsmith') }
251 @headers = { :authorization => credentials('jsmith') }
226 end
252 end
227
253
228 should_allow_api_authentication(:put,
254 should_allow_api_authentication(:put,
229 '/issues/6.xml',
255 '/issues/6.xml',
230 {:issue => {:subject => 'API update', :notes => 'A new note'}},
256 {:issue => {:subject => 'API update', :notes => 'A new note'}},
231 {:success_code => :ok})
257 {:success_code => :ok})
232
258
233 should "not create a new issue" do
259 should "not create a new issue" do
234 assert_no_difference('Issue.count') do
260 assert_no_difference('Issue.count') do
235 put '/issues/6.xml', @parameters, @headers
261 put '/issues/6.xml', @parameters, @headers
236 end
262 end
237 end
263 end
238
264
239 should "create a new journal" do
265 should "create a new journal" do
240 assert_difference('Journal.count') do
266 assert_difference('Journal.count') do
241 put '/issues/6.xml', @parameters, @headers
267 put '/issues/6.xml', @parameters, @headers
242 end
268 end
243 end
269 end
244
270
245 should "add the note to the journal" do
271 should "add the note to the journal" do
246 put '/issues/6.xml', @parameters, @headers
272 put '/issues/6.xml', @parameters, @headers
247
273
248 journal = Journal.last
274 journal = Journal.last
249 assert_equal "A new note", journal.notes
275 assert_equal "A new note", journal.notes
250 end
276 end
251
277
252 should "update the issue" do
278 should "update the issue" do
253 put '/issues/6.xml', @parameters, @headers
279 put '/issues/6.xml', @parameters, @headers
254
280
255 issue = Issue.find(6)
281 issue = Issue.find(6)
256 assert_equal "API update", issue.subject
282 assert_equal "API update", issue.subject
257 end
283 end
258
284
259 end
285 end
260
286
261 context "PUT /issues/6.xml with failed update" do
287 context "PUT /issues/6.xml with failed update" do
262 setup do
288 setup do
263 @parameters = {:issue => {:subject => ''}}
289 @parameters = {:issue => {:subject => ''}}
264 @headers = { :authorization => credentials('jsmith') }
290 @headers = { :authorization => credentials('jsmith') }
265 end
291 end
266
292
267 should_allow_api_authentication(:put,
293 should_allow_api_authentication(:put,
268 '/issues/6.xml',
294 '/issues/6.xml',
269 {:issue => {:subject => ''}}, # Missing subject should fail
295 {:issue => {:subject => ''}}, # Missing subject should fail
270 {:success_code => :unprocessable_entity})
296 {:success_code => :unprocessable_entity})
271
297
272 should "not create a new issue" do
298 should "not create a new issue" do
273 assert_no_difference('Issue.count') do
299 assert_no_difference('Issue.count') do
274 put '/issues/6.xml', @parameters, @headers
300 put '/issues/6.xml', @parameters, @headers
275 end
301 end
276 end
302 end
277
303
278 should "not create a new journal" do
304 should "not create a new journal" do
279 assert_no_difference('Journal.count') do
305 assert_no_difference('Journal.count') do
280 put '/issues/6.xml', @parameters, @headers
306 put '/issues/6.xml', @parameters, @headers
281 end
307 end
282 end
308 end
283
309
284 should "have an errors tag" do
310 should "have an errors tag" do
285 put '/issues/6.xml', @parameters, @headers
311 put '/issues/6.xml', @parameters, @headers
286
312
287 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
313 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
288 end
314 end
289 end
315 end
290
316
291 context "PUT /issues/6.json" do
317 context "PUT /issues/6.json" do
292 setup do
318 setup do
293 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
319 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
294 @headers = { :authorization => credentials('jsmith') }
320 @headers = { :authorization => credentials('jsmith') }
295 end
321 end
296
322
297 should_allow_api_authentication(:put,
323 should_allow_api_authentication(:put,
298 '/issues/6.json',
324 '/issues/6.json',
299 {:issue => {:subject => 'API update', :notes => 'A new note'}},
325 {:issue => {:subject => 'API update', :notes => 'A new note'}},
300 {:success_code => :ok})
326 {:success_code => :ok})
301
327
302 should "not create a new issue" do
328 should "not create a new issue" do
303 assert_no_difference('Issue.count') do
329 assert_no_difference('Issue.count') do
304 put '/issues/6.json', @parameters, @headers
330 put '/issues/6.json', @parameters, @headers
305 end
331 end
306 end
332 end
307
333
308 should "create a new journal" do
334 should "create a new journal" do
309 assert_difference('Journal.count') do
335 assert_difference('Journal.count') do
310 put '/issues/6.json', @parameters, @headers
336 put '/issues/6.json', @parameters, @headers
311 end
337 end
312 end
338 end
313
339
314 should "add the note to the journal" do
340 should "add the note to the journal" do
315 put '/issues/6.json', @parameters, @headers
341 put '/issues/6.json', @parameters, @headers
316
342
317 journal = Journal.last
343 journal = Journal.last
318 assert_equal "A new note", journal.notes
344 assert_equal "A new note", journal.notes
319 end
345 end
320
346
321 should "update the issue" do
347 should "update the issue" do
322 put '/issues/6.json', @parameters, @headers
348 put '/issues/6.json', @parameters, @headers
323
349
324 issue = Issue.find(6)
350 issue = Issue.find(6)
325 assert_equal "API update", issue.subject
351 assert_equal "API update", issue.subject
326 end
352 end
327
353
328 end
354 end
329
355
330 context "PUT /issues/6.json with failed update" do
356 context "PUT /issues/6.json with failed update" do
331 setup do
357 setup do
332 @parameters = {:issue => {:subject => ''}}
358 @parameters = {:issue => {:subject => ''}}
333 @headers = { :authorization => credentials('jsmith') }
359 @headers = { :authorization => credentials('jsmith') }
334 end
360 end
335
361
336 should_allow_api_authentication(:put,
362 should_allow_api_authentication(:put,
337 '/issues/6.json',
363 '/issues/6.json',
338 {:issue => {:subject => ''}}, # Missing subject should fail
364 {:issue => {:subject => ''}}, # Missing subject should fail
339 {:success_code => :unprocessable_entity})
365 {:success_code => :unprocessable_entity})
340
366
341 should "not create a new issue" do
367 should "not create a new issue" do
342 assert_no_difference('Issue.count') do
368 assert_no_difference('Issue.count') do
343 put '/issues/6.json', @parameters, @headers
369 put '/issues/6.json', @parameters, @headers
344 end
370 end
345 end
371 end
346
372
347 should "not create a new journal" do
373 should "not create a new journal" do
348 assert_no_difference('Journal.count') do
374 assert_no_difference('Journal.count') do
349 put '/issues/6.json', @parameters, @headers
375 put '/issues/6.json', @parameters, @headers
350 end
376 end
351 end
377 end
352
378
353 should "have an errors attribute" do
379 should "have an errors attribute" do
354 put '/issues/6.json', @parameters, @headers
380 put '/issues/6.json', @parameters, @headers
355
381
356 json = ActiveSupport::JSON.decode(response.body)
382 json = ActiveSupport::JSON.decode(response.body)
357 assert json['errors'].include?(['subject', "can't be blank"])
383 assert json['errors'].include?(['subject', "can't be blank"])
358 end
384 end
359 end
385 end
360
386
361 context "DELETE /issues/1.xml" do
387 context "DELETE /issues/1.xml" do
362 should_allow_api_authentication(:delete,
388 should_allow_api_authentication(:delete,
363 '/issues/6.xml',
389 '/issues/6.xml',
364 {},
390 {},
365 {:success_code => :ok})
391 {:success_code => :ok})
366
392
367 should "delete the issue" do
393 should "delete the issue" do
368 assert_difference('Issue.count',-1) do
394 assert_difference('Issue.count',-1) do
369 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
395 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
370 end
396 end
371
397
372 assert_nil Issue.find_by_id(6)
398 assert_nil Issue.find_by_id(6)
373 end
399 end
374 end
400 end
375
401
376 context "DELETE /issues/1.json" do
402 context "DELETE /issues/1.json" do
377 should_allow_api_authentication(:delete,
403 should_allow_api_authentication(:delete,
378 '/issues/6.json',
404 '/issues/6.json',
379 {},
405 {},
380 {:success_code => :ok})
406 {:success_code => :ok})
381
407
382 should "delete the issue" do
408 should "delete the issue" do
383 assert_difference('Issue.count',-1) do
409 assert_difference('Issue.count',-1) do
384 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
410 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
385 end
411 end
386
412
387 assert_nil Issue.find_by_id(6)
413 assert_nil Issue.find_by_id(6)
388 end
414 end
389 end
415 end
390
416
391 def credentials(user, password=nil)
417 def credentials(user, password=nil)
392 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
418 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
393 end
419 end
394 end
420 end
General Comments 0
You need to be logged in to leave comments. Login now