diff -r 1089a231fa7b -r 9d67c3d4674b app/controllers/members_controller.rb
--- a/app/controllers/members_controller.rb	Tue Dec 13 19:03:10 2011 +0100
+++ b/app/controllers/members_controller.rb	Wed Dec 14 11:28:46 2011 +0100
@@ -16,16 +16,17 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 class MembersController < ApplicationController
   model_object Member
   before_filter :find_model_object, :except => [:new, :autocomplete_for_member]
   before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member]
   before_filter :find_project, :only => [:new, :autocomplete_for_member]
   before_filter :authorize
+  accept_api_auth :new, :edit, :show, :destroy
 
   def new
     members = []
     if params[:member] && request.post?
       attrs = params[:member].dup
       if (user_ids = attrs.delete(:user_ids))
         user_ids.each do |user_id|
           members << Member.new(attrs.merge(:user_id => user_id))
@@ -42,59 +43,68 @@ class MembersController < ApplicationCon
 
         format.js {
           render(:update) {|page|
             page.replace_html "tab-content-members", :partial => 'projects/settings/members'
             page << 'hideOnLoad()'
             members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
           }
         }
+        format.api { head :ok }
       else
 
         format.js {
           render(:update) {|page|
             errors = members.collect {|m|
               m.errors.full_messages
             }.flatten.uniq
 
             page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', ')))
           }
         }
 
+        format.api { head 304 }
       end
     end
   end
 
   def edit
-    if request.post? and @member.update_attributes(params[:member])
-  	 respond_to do |format|
+    if (request.post? or request.put?) and @member.update_attributes(params[:member])
+      respond_to do |format|
         format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
         format.js {
           render(:update) {|page|
             page.replace_html "tab-content-members", :partial => 'projects/settings/members'
             page << 'hideOnLoad()'
             page.visual_effect(:highlight, "member-#{@member.id}")
           }
         }
+        format.api { head :ok }
       end
     end
   end
 
   def destroy
-    if request.post? && @member.deletable?
+    if (request.post? or request.delete?) and @member.deletable?
       @member.destroy
     end
     respond_to do |format|
       format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
       format.js { render(:update) {|page|
           page.replace_html "tab-content-members", :partial => 'projects/settings/members'
           page << 'hideOnLoad()'
         }
       }
+      format.api { head :ok }
     end
   end
 
   def autocomplete_for_member
     @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
     render :layout => false
   end
 
+  def show
+    respond_to do |format|
+      format.api
+    end
+  end
 end
diff -r 1089a231fa7b -r 9d67c3d4674b app/controllers/roles_controller.rb
--- a/app/controllers/roles_controller.rb	Tue Dec 13 19:03:10 2011 +0100
+++ b/app/controllers/roles_controller.rb	Wed Dec 14 11:28:46 2011 +0100
@@ -13,24 +13,31 @@
 #
 # 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.
 
 class RolesController < ApplicationController
   layout 'admin'
 
-  before_filter :require_admin
+  before_filter :require_admin, :except => [ :show, :index ]
 
   verify :method => :post, :only => [ :destroy ],
          :redirect_to => { :action => :index }
 
   def index
-    @role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position'
-    render :action => "index", :layout => false if request.xhr?
+    respond_to do |format|
+      format.html do
+        @role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position'
+        render :action => "index", :layout => false if request.xhr?
+      end
+      format.api do
+        @roles = Role.find(:all)
+      end
+    end
   end
 
   def new
     # Prefills the form with 'Non member' role permissions
     @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions})
     if request.post? && @role.save
       # workflow copy
       if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from]))
@@ -70,9 +77,14 @@ class RolesController < ApplicationContr
       @roles.each do |role|
         role.permissions = params[:permissions][role.id.to_s]
         role.save
       end
       flash[:notice] = l(:notice_successful_update)
       redirect_to :action => 'index'
     end
   end
+
+  def show
+    @role = Role.find(params[:id])
+  end
+
 end
diff -r 1089a231fa7b -r 9d67c3d4674b app/models/member.rb
--- a/app/models/member.rb	Tue Dec 13 19:03:10 2011 +0100
+++ b/app/models/member.rb	Wed Dec 14 11:28:46 2011 +0100
@@ -67,17 +67,17 @@ class Member < ActiveRecord::Base
 
   def before_destroy
     if user
       # remove category based auto assignments for this member
       IssueCategory.update_all "assigned_to_id = NULL", ["project_id = ? AND assigned_to_id = ?", project.id, user.id]
     end
   end
 
-  # Find or initilize a Member with an id, attributes, and for a Principal
+  # Find or initialize a Member with an id, attributes, and for a Principal
   def self.edit_membership(id, new_attributes, principal=nil)
     @membership = id.present? ? Member.find(id) : Member.new(:principal => principal)
     @membership.attributes = new_attributes
     @membership
   end
 
   protected
 
diff -r 1089a231fa7b -r 9d67c3d4674b app/views/members/show.api.rsb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/members/show.api.rsb	Wed Dec 14 11:28:46 2011 +0100
@@ -0,0 +1,11 @@
+api.member(:id => @member.id, :name => @member.name) do
+   #api.inspect @member.roles.inspect
+  api.array :role_ids do
+     @member.roles.each do |role|
+          api.role_id(role.id, :name => role.name)
+     end
+  end
+  api.array :user_ids do
+     api.user_id(@member.user_id, :login => @member.user.login, :mail => @member.user.mail)
+  end
+end
diff -r 1089a231fa7b -r 9d67c3d4674b app/views/projects/show.api.rsb
--- a/app/views/projects/show.api.rsb	Tue Dec 13 19:03:10 2011 +0100
+++ b/app/views/projects/show.api.rsb	Wed Dec 14 11:28:46 2011 +0100
@@ -17,9 +17,22 @@ api.project do
     end
   end if include_in_api_response?('trackers')
 
   api.array :issue_categories do
     @project.issue_categories.each do |category|
       api.issue_category(:id => category.id, :name => category.name)
     end
   end if include_in_api_response?('issue_categories')
+
+  api.array :members do
+    @project.members.each do |member|
+      api.member(:id => member.id, :name => member.name, :user => member.user_id, :login => member.user.login, :mail => member.user.mail)  do
+        api.array :roles do
+          member.roles.each do |role|
+            api.role(:id => role.id, :name => role.name)
+          end
+        end
+      end
+    end
+  end if include_in_api_response?('members')
+
 end
diff -r 1089a231fa7b -r 9d67c3d4674b app/views/roles/index.api.rsb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/roles/index.api.rsb	Wed Dec 14 11:28:46 2011 +0100
@@ -0,0 +1,5 @@
+api.array :members do
+  @roles.each do |role|
+    api.role(:id => role.id, :name => role.name)
+  end
+end
\ No newline at end of file
diff -r 1089a231fa7b -r 9d67c3d4674b app/views/roles/show.api.rsb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/roles/show.api.rsb	Wed Dec 14 11:28:46 2011 +0100
@@ -0,0 +1,8 @@
+api.role(:id => @role.id) do
+  api.name @role.name
+  api.array :permissions do
+    @role.permissions.each do |perm|
+      api.permission(perm.to_s)
+    end
+  end
+end
\ No newline at end of file
diff -r 1089a231fa7b -r 9d67c3d4674b config/routes.rb
--- a/config/routes.rb	Tue Dec 13 19:03:10 2011 +0100
+++ b/config/routes.rb	Wed Dec 14 11:28:46 2011 +0100
@@ -114,16 +114,29 @@ ActionController::Routing::Routes.draw d
     issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
   end
 
   map.resources :issues, :path_prefix => '/projects/:project_id', :collection => { :create => :post } do |issues|
     issues.resources :time_entries, :controller => 'timelog'
   end
 
   map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
+  #Restful-like project member access
+  map.connect 'projects/:id/members/new.:format', :controller => 'members', :action => 'new'
+  map.connect 'members/:id/edit.:format', :controller => 'members', :action => 'edit'
+  map.connect 'members/:id/destroy.:format', :controller => 'members', :action => 'destroy'
+
+  #Restful project member access
+  map.connect 'members/:id.:format', :controller => 'members', :action => 'show', :conditions => { :method => :get}
+  map.connect 'projects/:id/members.:format', :controller => 'members', :action => 'new', :conditions => { :method => :post}
+  map.connect 'members/:id.:format', :controller => 'members', :action => 'edit', :conditions => { :method => :put}
+  map.connect 'members/:id.:format', :controller => 'members', :action => 'destroy', :conditions => { :method => :delete}
+
+  map.connect 'roles.:format', :controller => 'roles', :action => 'index', :condition => {:method => :get}
+  map.connect 'roles/:id.:format', :controller => 'roles', :action => 'show', :condition => {:method => :get}
 
   map.with_options :controller => 'users' do |users|
     users.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil, :conditions => {:method => :get}
 
     users.with_options :conditions => {:method => :post} do |user_actions|
       user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
       user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
       user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
diff -r 1089a231fa7b -r 9d67c3d4674b lib/redmine.rb
--- a/lib/redmine.rb	Tue Dec 13 19:03:10 2011 +0100
+++ b/lib/redmine.rb	Wed Dec 14 11:28:46 2011 +0100
@@ -47,17 +47,17 @@ end
 
 # Permissions
 Redmine::AccessControl.map do |map|
   map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true
   map.permission :search_project, {:search => :index}, :public => true
   map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
   map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
   map.permission :select_project_modules, {:projects => :modules}, :require => :member
-  map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
+  map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :show, :autocomplete_for_member]}, :require => :member
   map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
   map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
 
   map.project_module :issue_tracking do |map|
     # Issue categories
     map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
     # Issues
     map.permission :view_issues, {:issues => [:index, :show],
