From 993b60d61eb927cff21ea0b06c1631eb986f6a51 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 14 Mar 2008 21:17:09 +0000 Subject: [PATCH] Adds 2 permissions (closes #859): * edit_time_entries: lets a user edit/delete any time entry * edit_own_time_entries: lets a user edit/delete its own time entries only git-svn-id: http://redmine.rubyforge.org/svn/trunk@1249 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/timelog_controller.rb | 16 +++++++- app/models/time_entry.rb | 2 +- app/views/issues/show.rhtml | 2 +- app/views/timelog/_list.rhtml | 13 +++++-- config/routes.rb | 1 + lib/redmine.rb | 2 + test/fixtures/roles.yml | 3 ++ test/functional/timelog_controller_test.rb | 45 +++++++++++++++++++++- 8 files changed, 76 insertions(+), 8 deletions(-) diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb index d672ac577..38c1fb04c 100644 --- a/app/controllers/timelog_controller.rb +++ b/app/controllers/timelog_controller.rb @@ -20,6 +20,8 @@ class TimelogController < ApplicationController menu_item :issues before_filter :find_project, :authorize + verify :method => :post, :only => :destroy, :redirect_to => { :action => :details } + helper :sort include SortHelper helper :issues @@ -198,16 +200,24 @@ class TimelogController < ApplicationController end def edit - render_404 and return if @time_entry && @time_entry.user != User.current + render_403 and return if @time_entry && !@time_entry.editable_by?(User.current) @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today) @time_entry.attributes = params[:time_entry] if request.post? and @time_entry.save flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'details', :project_id => @time_entry.project, :issue_id => @time_entry.issue + redirect_to :action => 'details', :project_id => @time_entry.project return end @activities = Enumeration::get_values('ACTI') end + + def destroy + render_404 and return unless @time_entry + render_403 and return unless @time_entry.editable_by?(User.current) + @time_entry.destroy + flash[:notice] = l(:notice_successful_delete) + redirect_to :action => 'details', :project_id => @time_entry.project + end private def find_project @@ -223,5 +233,7 @@ private render_404 return false end + rescue ActiveRecord::RecordNotFound + render_404 end end diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb index 0f8f62889..bcf6d1223 100644 --- a/app/models/time_entry.rb +++ b/app/models/time_entry.rb @@ -50,7 +50,7 @@ class TimeEntry < ActiveRecord::Base # Returns true if the time entry can be edited by usr, otherwise false def editable_by?(usr) - usr == self.user + (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project) end def self.visible_by(usr) diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index d9727cae7..77d9ce640 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -33,7 +33,7 @@ <%=l(:field_category)%> :<%=h @issue.category ? @issue.category.name : "-" %> <% if User.current.allowed_to?(:view_time_entries, @project) %> <%=l(:label_spent_time)%> : - <%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :issue_id => @issue}, :class => 'icon icon-time') : "-" %> + <%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time') : "-" %> <% end %> diff --git a/app/views/timelog/_list.rhtml b/app/views/timelog/_list.rhtml index ae5b6376a..67e3c67d5 100644 --- a/app/views/timelog/_list.rhtml +++ b/app/views/timelog/_list.rhtml @@ -23,9 +23,16 @@ <%=h entry.comments %> <%= html_hours("%.2f" % entry.hours) %> -<%= link_to_if_authorized(l(:button_edit), - {:controller => 'timelog', :action => 'edit', :id => entry}, - :class => 'icon icon-edit') if entry.editable_by?(User.current) %> + +<% if entry.editable_by?(User.current) -%> + <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry}, + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry}, + :confirm => l(:text_are_you_sure), + :method => :post, + :title => l(:button_delete) %> +<% end -%> + <% end -%> diff --git a/config/routes.rb b/config/routes.rb index 2610c2623..0edb71a06 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -20,6 +20,7 @@ ActionController::Routing::Routes.draw do |map| map.connect 'projects/:project_id/news/:action', :controller => 'news' map.connect 'projects/:project_id/documents/:action', :controller => 'documents' map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards' + map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog' map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages' map.with_options :controller => 'repositories' do |omap| diff --git a/lib/redmine.rb b/lib/redmine.rb index 4c5cbdaae..5443eef4a 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -49,6 +49,8 @@ Redmine::AccessControl.map do |map| map.project_module :time_tracking do |map| map.permission :log_time, {:timelog => :edit}, :require => :loggedin map.permission :view_time_entries, :timelog => [:details, :report] + map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member + map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin end map.project_module :news do |map| diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml index c4d417a09..c834828c6 100644 --- a/test/fixtures/roles.yml +++ b/test/fixtures/roles.yml @@ -66,6 +66,8 @@ roles_001: - :view_calendar - :log_time - :view_time_entries + - :edit_time_entries + - :delete_time_entries - :manage_news - :comment_news - :view_documents @@ -106,6 +108,7 @@ roles_002: - :view_calendar - :log_time - :view_time_entries + - :edit_own_time_entries - :manage_news - :comment_news - :view_documents diff --git a/test/functional/timelog_controller_test.rb b/test/functional/timelog_controller_test.rb index 4163ce548..66247e569 100644 --- a/test/functional/timelog_controller_test.rb +++ b/test/functional/timelog_controller_test.rb @@ -22,13 +22,56 @@ require 'timelog_controller' class TimelogController; def rescue_action(e) raise e end; end class TimelogControllerTest < Test::Unit::TestCase - fixtures :projects, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses + fixtures :projects, :roles, :members, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses def setup @controller = TimelogController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end + + def test_create + @request.session[:user_id] = 3 + post :edit, :project_id => 1, + :time_entry => {:comments => 'Some work on TimelogControllerTest', + :activity_id => '10', + :spent_on => '2008-03-14', + :issue_id => '1', + :hours => '7.3'} + assert_redirected_to 'projects/ecookbook/timelog/details' + + i = Issue.find(1) + t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') + assert_not_nil t + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + assert_equal i, t.issue + assert_equal i.project, t.project + end + + def test_update + entry = TimeEntry.find(1) + assert_equal 1, entry.issue_id + assert_equal 2, entry.user_id + + @request.session[:user_id] = 1 + post :edit, :id => 1, + :time_entry => {:issue_id => '2', + :hours => '8'} + assert_redirected_to 'projects/ecookbook/timelog/details' + entry.reload + + assert_equal 8, entry.hours + assert_equal 2, entry.issue_id + assert_equal 2, entry.user_id + end + + def destroy + @request.session[:user_id] = 2 + post :destroy, :id => 1 + assert_redirected_to 'projects/ecookbook/timelog/details' + assert_nil TimeEntry.find_by_id(1) + end def test_report_no_criteria get :report, :project_id => 1