XML REST API for Projects (#296).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3313 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
64f4b50139
commit
68a4cd38f5
|
@ -22,6 +22,7 @@ class ApplicationController < ActionController::Base
|
||||||
include Redmine::I18n
|
include Redmine::I18n
|
||||||
|
|
||||||
layout 'base'
|
layout 'base'
|
||||||
|
exempt_from_layout 'builder'
|
||||||
|
|
||||||
# Remove broken cookie after upgrade from 0.8.x (#4292)
|
# Remove broken cookie after upgrade from 0.8.x (#4292)
|
||||||
# See https://rails.lighthouseapp.com/projects/8994/tickets/3360
|
# See https://rails.lighthouseapp.com/projects/8994/tickets/3360
|
||||||
|
|
|
@ -53,6 +53,9 @@ class ProjectsController < ApplicationController
|
||||||
format.html {
|
format.html {
|
||||||
@projects = Project.visible.find(:all, :order => 'lft')
|
@projects = Project.visible.find(:all, :order => 'lft')
|
||||||
}
|
}
|
||||||
|
format.xml {
|
||||||
|
@projects = Project.visible.find(:all, :order => 'lft')
|
||||||
|
}
|
||||||
format.atom {
|
format.atom {
|
||||||
projects = Project.visible.find(:all, :order => 'created_on DESC',
|
projects = Project.visible.find(:all, :order => 'created_on DESC',
|
||||||
:limit => Setting.feeds_limit.to_i)
|
:limit => Setting.feeds_limit.to_i)
|
||||||
|
@ -81,8 +84,18 @@ class ProjectsController < ApplicationController
|
||||||
m = Member.new(:user => User.current, :roles => [r])
|
m = Member.new(:user => User.current, :roles => [r])
|
||||||
@project.members << m
|
@project.members << m
|
||||||
end
|
end
|
||||||
flash[:notice] = l(:notice_successful_create)
|
respond_to do |format|
|
||||||
redirect_to :controller => 'projects', :action => 'settings', :id => @project
|
format.html {
|
||||||
|
flash[:notice] = l(:notice_successful_create)
|
||||||
|
redirect_to :controller => 'projects', :action => 'settings', :id => @project
|
||||||
|
}
|
||||||
|
format.xml { head :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -147,6 +160,11 @@ class ProjectsController < ApplicationController
|
||||||
:conditions => cond).to_f
|
:conditions => cond).to_f
|
||||||
end
|
end
|
||||||
@key = User.current.rss_key
|
@key = User.current.rss_key
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.xml
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def settings
|
def settings
|
||||||
|
@ -160,15 +178,26 @@ class ProjectsController < ApplicationController
|
||||||
|
|
||||||
# Edit @project
|
# Edit @project
|
||||||
def edit
|
def edit
|
||||||
if request.post?
|
if request.get?
|
||||||
|
else
|
||||||
@project.attributes = params[:project]
|
@project.attributes = params[:project]
|
||||||
if validate_parent_id && @project.save
|
if validate_parent_id && @project.save
|
||||||
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
|
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
|
||||||
flash[:notice] = l(:notice_successful_update)
|
respond_to do |format|
|
||||||
redirect_to :action => 'settings', :id => @project
|
format.html {
|
||||||
|
flash[:notice] = l(:notice_successful_update)
|
||||||
|
redirect_to :action => 'settings', :id => @project
|
||||||
|
}
|
||||||
|
format.xml { head :ok }
|
||||||
|
end
|
||||||
else
|
else
|
||||||
settings
|
respond_to do |format|
|
||||||
render :action => 'settings'
|
format.html {
|
||||||
|
settings
|
||||||
|
render :action => 'settings'
|
||||||
|
}
|
||||||
|
format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -195,9 +224,16 @@ class ProjectsController < ApplicationController
|
||||||
# Delete @project
|
# Delete @project
|
||||||
def destroy
|
def destroy
|
||||||
@project_to_destroy = @project
|
@project_to_destroy = @project
|
||||||
if request.post? and params[:confirm]
|
if request.get?
|
||||||
@project_to_destroy.destroy
|
# display confirmation view
|
||||||
redirect_to :controller => 'admin', :action => 'projects'
|
else
|
||||||
|
if params[:format] == 'xml' || params[:confirm]
|
||||||
|
@project_to_destroy.destroy
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to :controller => 'admin', :action => 'projects' }
|
||||||
|
format.xml { head :ok }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
# hide project in layout
|
# hide project in layout
|
||||||
@project = nil
|
@project = nil
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
xml.instruct!
|
||||||
|
xml.projects :type => 'array' do
|
||||||
|
@projects.each do |project|
|
||||||
|
xml.project :id => project.id do
|
||||||
|
xml.name project.name
|
||||||
|
xml.identifier project.identifier
|
||||||
|
xml.description project.description
|
||||||
|
xml.parent(:id => project.parent_id, :name => project.parent.name) unless project.parent.nil?
|
||||||
|
xml.custom_fields do
|
||||||
|
project.custom_field_values.each do |custom_value|
|
||||||
|
xml.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
|
||||||
|
end
|
||||||
|
end unless project.custom_field_values.empty?
|
||||||
|
xml.created_on project.created_on
|
||||||
|
xml.updated_on project.updated_on
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
xml.instruct!
|
||||||
|
xml.project :id => @project.id do
|
||||||
|
xml.name @project.name
|
||||||
|
xml.identifier @project.identifier
|
||||||
|
xml.description @project.description
|
||||||
|
xml.homepage @project.homepage
|
||||||
|
|
||||||
|
xml.custom_fields do
|
||||||
|
@project.custom_field_values.each do |custom_value|
|
||||||
|
xml.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
|
||||||
|
end
|
||||||
|
end unless @project.custom_field_values.empty?
|
||||||
|
|
||||||
|
xml.created_on @project.created_on
|
||||||
|
xml.updated_on @project.updated_on
|
||||||
|
end
|
|
@ -186,6 +186,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
project_views.connect 'projects.:format', :action => 'index'
|
project_views.connect 'projects.:format', :action => 'index'
|
||||||
project_views.connect 'projects/new', :action => 'add'
|
project_views.connect 'projects/new', :action => 'add'
|
||||||
project_views.connect 'projects/:id', :action => 'show'
|
project_views.connect 'projects/:id', :action => 'show'
|
||||||
|
project_views.connect 'projects/:id.:format', :action => 'show'
|
||||||
project_views.connect 'projects/:id/:action', :action => /roadmap|destroy|settings/
|
project_views.connect 'projects/:id/:action', :action => /roadmap|destroy|settings/
|
||||||
project_views.connect 'projects/:id/files', :action => 'list_files'
|
project_views.connect 'projects/:id/files', :action => 'list_files'
|
||||||
project_views.connect 'projects/:id/files/new', :action => 'add_file'
|
project_views.connect 'projects/:id/files/new', :action => 'add_file'
|
||||||
|
@ -204,6 +205,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
projects.with_options :conditions => {:method => :post} do |project_actions|
|
projects.with_options :conditions => {:method => :post} do |project_actions|
|
||||||
project_actions.connect 'projects/new', :action => 'add'
|
project_actions.connect 'projects/new', :action => 'add'
|
||||||
project_actions.connect 'projects', :action => 'add'
|
project_actions.connect 'projects', :action => 'add'
|
||||||
|
project_actions.connect 'projects.:format', :action => 'add', :format => /xml/
|
||||||
project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/
|
project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/
|
||||||
project_actions.connect 'projects/:id/files/new', :action => 'add_file'
|
project_actions.connect 'projects/:id/files/new', :action => 'add_file'
|
||||||
project_actions.connect 'projects/:id/versions/new', :action => 'add_version'
|
project_actions.connect 'projects/:id/versions/new', :action => 'add_version'
|
||||||
|
@ -211,7 +213,12 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'
|
project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
projects.with_options :conditions => {:method => :put} do |project_actions|
|
||||||
|
project_actions.conditions 'projects/:id.:format', :action => 'edit', :format => /xml/
|
||||||
|
end
|
||||||
|
|
||||||
projects.with_options :conditions => {:method => :delete} do |project_actions|
|
projects.with_options :conditions => {:method => :delete} do |project_actions|
|
||||||
|
project_actions.conditions 'projects/:id.:format', :action => 'destroy', :format => /xml/
|
||||||
project_actions.conditions 'projects/:id/reset_activities', :action => 'reset_activities'
|
project_actions.conditions 'projects/:id/reset_activities', :action => 'reset_activities'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ custom_fields_003:
|
||||||
- Alpha
|
- Alpha
|
||||||
- Planning
|
- Planning
|
||||||
id: 3
|
id: 3
|
||||||
is_required: true
|
is_required: false
|
||||||
field_format: list
|
field_format: list
|
||||||
default_value: ""
|
default_value: ""
|
||||||
editable: true
|
editable: true
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
# Redmine - project management software
|
||||||
|
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
require "#{File.dirname(__FILE__)}/../test_helper"
|
||||||
|
|
||||||
|
class ProjectsApiTest < ActionController::IntegrationTest
|
||||||
|
fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
|
||||||
|
:trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
|
||||||
|
:attachments, :custom_fields, :custom_values, :time_entries
|
||||||
|
|
||||||
|
def setup
|
||||||
|
Setting.rest_api_enabled = '1'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_index_routing
|
||||||
|
assert_routing(
|
||||||
|
{:method => :get, :path => '/projects.xml'},
|
||||||
|
:controller => 'projects', :action => 'index', :format => 'xml'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_index
|
||||||
|
get '/projects.xml'
|
||||||
|
assert_response :success
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_show_routing
|
||||||
|
assert_routing(
|
||||||
|
{:method => :get, :path => '/projects/1.xml'},
|
||||||
|
:controller => 'projects', :action => 'show', :id => '1', :format => 'xml'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_show
|
||||||
|
get '/projects/1.xml'
|
||||||
|
assert_response :success
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_routing
|
||||||
|
assert_routing(
|
||||||
|
{:method => :post, :path => '/projects.xml'},
|
||||||
|
:controller => 'projects', :action => 'add', :format => 'xml'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create
|
||||||
|
attributes = {:name => 'API test', :identifier => 'api-test'}
|
||||||
|
assert_difference 'Project.count' do
|
||||||
|
post '/projects.xml', {:project => attributes}, :authorization => credentials('admin')
|
||||||
|
end
|
||||||
|
assert_response :created
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
project = Project.first(:order => 'id DESC')
|
||||||
|
attributes.each do |attribute, value|
|
||||||
|
assert_equal value, project.send(attribute)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_failure
|
||||||
|
attributes = {:name => 'API test'}
|
||||||
|
assert_no_difference 'Project.count' do
|
||||||
|
post '/projects.xml', {:project => attributes}, :authorization => credentials('admin')
|
||||||
|
end
|
||||||
|
assert_response :unprocessable_entity
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
assert_tag :errors, :child => {:tag => 'error', :content => "Identifier can't be blank"}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_routing
|
||||||
|
assert_routing(
|
||||||
|
{:method => :put, :path => '/projects/1.xml'},
|
||||||
|
:controller => 'projects', :action => 'edit', :id => '1', :format => 'xml'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update
|
||||||
|
attributes = {:name => 'API update'}
|
||||||
|
assert_no_difference 'Project.count' do
|
||||||
|
put '/projects/1.xml', {:project => attributes}, :authorization => credentials('jsmith')
|
||||||
|
end
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
project = Project.find(1)
|
||||||
|
attributes.each do |attribute, value|
|
||||||
|
assert_equal value, project.send(attribute)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_failure
|
||||||
|
attributes = {:name => ''}
|
||||||
|
assert_no_difference 'Project.count' do
|
||||||
|
put '/projects/1.xml', {:project => attributes}, :authorization => credentials('jsmith')
|
||||||
|
end
|
||||||
|
assert_response :unprocessable_entity
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
assert_tag :errors, :child => {:tag => 'error', :content => "Name can't be blank"}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_destroy_routing
|
||||||
|
assert_routing(
|
||||||
|
{:method => :delete, :path => '/projects/1.xml'},
|
||||||
|
:controller => 'projects', :action => 'destroy', :id => '1', :format => 'xml'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_destroy
|
||||||
|
assert_difference 'Project.count', -1 do
|
||||||
|
delete '/projects/2.xml', {}, :authorization => credentials('admin')
|
||||||
|
end
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 'application/xml', @response.content_type
|
||||||
|
assert_nil Project.find_by_id(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
def credentials(user, password=nil)
|
||||||
|
ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue