##// END OF EJS Templates
XML REST API for Projects (#296)....
Jean-Philippe Lang -
r3199:68a4cd38f543
parent child
Show More
@@ -0,0 +1,18
1 xml.instruct!
2 xml.projects :type => 'array' do
3 @projects.each do |project|
4 xml.project :id => project.id do
5 xml.name project.name
6 xml.identifier project.identifier
7 xml.description project.description
8 xml.parent(:id => project.parent_id, :name => project.parent.name) unless project.parent.nil?
9 xml.custom_fields do
10 project.custom_field_values.each do |custom_value|
11 xml.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
12 end
13 end unless project.custom_field_values.empty?
14 xml.created_on project.created_on
15 xml.updated_on project.updated_on
16 end
17 end
18 end
@@ -0,0 +1,16
1 xml.instruct!
2 xml.project :id => @project.id do
3 xml.name @project.name
4 xml.identifier @project.identifier
5 xml.description @project.description
6 xml.homepage @project.homepage
7
8 xml.custom_fields do
9 @project.custom_field_values.each do |custom_value|
10 xml.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
14 xml.created_on @project.created_on
15 xml.updated_on @project.updated_on
16 end
@@ -0,0 +1,134
1 # Redmine - project management software
2 # Copyright (C) 2006-2010 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.dirname(__FILE__)}/../test_helper"
19
20 class ProjectsApiTest < ActionController::IntegrationTest
21 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
22 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
23 :attachments, :custom_fields, :custom_values, :time_entries
24
25 def setup
26 Setting.rest_api_enabled = '1'
27 end
28
29 def test_index_routing
30 assert_routing(
31 {:method => :get, :path => '/projects.xml'},
32 :controller => 'projects', :action => 'index', :format => 'xml'
33 )
34 end
35
36 def test_index
37 get '/projects.xml'
38 assert_response :success
39 assert_equal 'application/xml', @response.content_type
40 end
41
42 def test_show_routing
43 assert_routing(
44 {:method => :get, :path => '/projects/1.xml'},
45 :controller => 'projects', :action => 'show', :id => '1', :format => 'xml'
46 )
47 end
48
49 def test_show
50 get '/projects/1.xml'
51 assert_response :success
52 assert_equal 'application/xml', @response.content_type
53 end
54
55 def test_create_routing
56 assert_routing(
57 {:method => :post, :path => '/projects.xml'},
58 :controller => 'projects', :action => 'add', :format => 'xml'
59 )
60 end
61
62 def test_create
63 attributes = {:name => 'API test', :identifier => 'api-test'}
64 assert_difference 'Project.count' do
65 post '/projects.xml', {:project => attributes}, :authorization => credentials('admin')
66 end
67 assert_response :created
68 assert_equal 'application/xml', @response.content_type
69 project = Project.first(:order => 'id DESC')
70 attributes.each do |attribute, value|
71 assert_equal value, project.send(attribute)
72 end
73 end
74
75 def test_create_failure
76 attributes = {:name => 'API test'}
77 assert_no_difference 'Project.count' do
78 post '/projects.xml', {:project => attributes}, :authorization => credentials('admin')
79 end
80 assert_response :unprocessable_entity
81 assert_equal 'application/xml', @response.content_type
82 assert_tag :errors, :child => {:tag => 'error', :content => "Identifier can't be blank"}
83 end
84
85 def test_update_routing
86 assert_routing(
87 {:method => :put, :path => '/projects/1.xml'},
88 :controller => 'projects', :action => 'edit', :id => '1', :format => 'xml'
89 )
90 end
91
92 def test_update
93 attributes = {:name => 'API update'}
94 assert_no_difference 'Project.count' do
95 put '/projects/1.xml', {:project => attributes}, :authorization => credentials('jsmith')
96 end
97 assert_response :ok
98 assert_equal 'application/xml', @response.content_type
99 project = Project.find(1)
100 attributes.each do |attribute, value|
101 assert_equal value, project.send(attribute)
102 end
103 end
104
105 def test_update_failure
106 attributes = {:name => ''}
107 assert_no_difference 'Project.count' do
108 put '/projects/1.xml', {:project => attributes}, :authorization => credentials('jsmith')
109 end
110 assert_response :unprocessable_entity
111 assert_equal 'application/xml', @response.content_type
112 assert_tag :errors, :child => {:tag => 'error', :content => "Name can't be blank"}
113 end
114
115 def test_destroy_routing
116 assert_routing(
117 {:method => :delete, :path => '/projects/1.xml'},
118 :controller => 'projects', :action => 'destroy', :id => '1', :format => 'xml'
119 )
120 end
121
122 def test_destroy
123 assert_difference 'Project.count', -1 do
124 delete '/projects/2.xml', {}, :authorization => credentials('admin')
125 end
126 assert_response :ok
127 assert_equal 'application/xml', @response.content_type
128 assert_nil Project.find_by_id(2)
129 end
130
131 def credentials(user, password=nil)
132 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
133 end
134 end
@@ -22,6 +22,7 class ApplicationController < ActionController::Base
22 include Redmine::I18n
22 include Redmine::I18n
23
23
24 layout 'base'
24 layout 'base'
25 exempt_from_layout 'builder'
25
26
26 # Remove broken cookie after upgrade from 0.8.x (#4292)
27 # Remove broken cookie after upgrade from 0.8.x (#4292)
27 # See https://rails.lighthouseapp.com/projects/8994/tickets/3360
28 # See https://rails.lighthouseapp.com/projects/8994/tickets/3360
@@ -53,6 +53,9 class ProjectsController < ApplicationController
53 format.html {
53 format.html {
54 @projects = Project.visible.find(:all, :order => 'lft')
54 @projects = Project.visible.find(:all, :order => 'lft')
55 }
55 }
56 format.xml {
57 @projects = Project.visible.find(:all, :order => 'lft')
58 }
56 format.atom {
59 format.atom {
57 projects = Project.visible.find(:all, :order => 'created_on DESC',
60 projects = Project.visible.find(:all, :order => 'created_on DESC',
58 :limit => Setting.feeds_limit.to_i)
61 :limit => Setting.feeds_limit.to_i)
@@ -81,8 +84,18 class ProjectsController < ApplicationController
81 m = Member.new(:user => User.current, :roles => [r])
84 m = Member.new(:user => User.current, :roles => [r])
82 @project.members << m
85 @project.members << m
83 end
86 end
84 flash[:notice] = l(:notice_successful_create)
87 respond_to do |format|
85 redirect_to :controller => 'projects', :action => 'settings', :id => @project
88 format.html {
89 flash[:notice] = l(:notice_successful_create)
90 redirect_to :controller => 'projects', :action => 'settings', :id => @project
91 }
92 format.xml { head :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
93 end
94 else
95 respond_to do |format|
96 format.html
97 format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
98 end
86 end
99 end
87 end
100 end
88 end
101 end
@@ -147,6 +160,11 class ProjectsController < ApplicationController
147 :conditions => cond).to_f
160 :conditions => cond).to_f
148 end
161 end
149 @key = User.current.rss_key
162 @key = User.current.rss_key
163
164 respond_to do |format|
165 format.html
166 format.xml
167 end
150 end
168 end
151
169
152 def settings
170 def settings
@@ -160,15 +178,26 class ProjectsController < ApplicationController
160
178
161 # Edit @project
179 # Edit @project
162 def edit
180 def edit
163 if request.post?
181 if request.get?
182 else
164 @project.attributes = params[:project]
183 @project.attributes = params[:project]
165 if validate_parent_id && @project.save
184 if validate_parent_id && @project.save
166 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
185 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
167 flash[:notice] = l(:notice_successful_update)
186 respond_to do |format|
168 redirect_to :action => 'settings', :id => @project
187 format.html {
188 flash[:notice] = l(:notice_successful_update)
189 redirect_to :action => 'settings', :id => @project
190 }
191 format.xml { head :ok }
192 end
169 else
193 else
170 settings
194 respond_to do |format|
171 render :action => 'settings'
195 format.html {
196 settings
197 render :action => 'settings'
198 }
199 format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
200 end
172 end
201 end
173 end
202 end
174 end
203 end
@@ -195,9 +224,16 class ProjectsController < ApplicationController
195 # Delete @project
224 # Delete @project
196 def destroy
225 def destroy
197 @project_to_destroy = @project
226 @project_to_destroy = @project
198 if request.post? and params[:confirm]
227 if request.get?
199 @project_to_destroy.destroy
228 # display confirmation view
200 redirect_to :controller => 'admin', :action => 'projects'
229 else
230 if params[:format] == 'xml' || params[:confirm]
231 @project_to_destroy.destroy
232 respond_to do |format|
233 format.html { redirect_to :controller => 'admin', :action => 'projects' }
234 format.xml { head :ok }
235 end
236 end
201 end
237 end
202 # hide project in layout
238 # hide project in layout
203 @project = nil
239 @project = nil
@@ -186,6 +186,7 ActionController::Routing::Routes.draw do |map|
186 project_views.connect 'projects.:format', :action => 'index'
186 project_views.connect 'projects.:format', :action => 'index'
187 project_views.connect 'projects/new', :action => 'add'
187 project_views.connect 'projects/new', :action => 'add'
188 project_views.connect 'projects/:id', :action => 'show'
188 project_views.connect 'projects/:id', :action => 'show'
189 project_views.connect 'projects/:id.:format', :action => 'show'
189 project_views.connect 'projects/:id/:action', :action => /roadmap|destroy|settings/
190 project_views.connect 'projects/:id/:action', :action => /roadmap|destroy|settings/
190 project_views.connect 'projects/:id/files', :action => 'list_files'
191 project_views.connect 'projects/:id/files', :action => 'list_files'
191 project_views.connect 'projects/:id/files/new', :action => 'add_file'
192 project_views.connect 'projects/:id/files/new', :action => 'add_file'
@@ -204,6 +205,7 ActionController::Routing::Routes.draw do |map|
204 projects.with_options :conditions => {:method => :post} do |project_actions|
205 projects.with_options :conditions => {:method => :post} do |project_actions|
205 project_actions.connect 'projects/new', :action => 'add'
206 project_actions.connect 'projects/new', :action => 'add'
206 project_actions.connect 'projects', :action => 'add'
207 project_actions.connect 'projects', :action => 'add'
208 project_actions.connect 'projects.:format', :action => 'add', :format => /xml/
207 project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/
209 project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/
208 project_actions.connect 'projects/:id/files/new', :action => 'add_file'
210 project_actions.connect 'projects/:id/files/new', :action => 'add_file'
209 project_actions.connect 'projects/:id/versions/new', :action => 'add_version'
211 project_actions.connect 'projects/:id/versions/new', :action => 'add_version'
@@ -211,7 +213,12 ActionController::Routing::Routes.draw do |map|
211 project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'
213 project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'
212 end
214 end
213
215
216 projects.with_options :conditions => {:method => :put} do |project_actions|
217 project_actions.conditions 'projects/:id.:format', :action => 'edit', :format => /xml/
218 end
219
214 projects.with_options :conditions => {:method => :delete} do |project_actions|
220 projects.with_options :conditions => {:method => :delete} do |project_actions|
221 project_actions.conditions 'projects/:id.:format', :action => 'destroy', :format => /xml/
215 project_actions.conditions 'projects/:id/reset_activities', :action => 'reset_activities'
222 project_actions.conditions 'projects/:id/reset_activities', :action => 'reset_activities'
216 end
223 end
217 end
224 end
@@ -44,7 +44,7 custom_fields_003:
44 - Alpha
44 - Alpha
45 - Planning
45 - Planning
46 id: 3
46 id: 3
47 is_required: true
47 is_required: false
48 field_format: list
48 field_format: list
49 default_value: ""
49 default_value: ""
50 editable: true
50 editable: true
General Comments 0
You need to be logged in to leave comments. Login now