Feature #13244 » 0001-Setting-to-restrict-adding-editing-deleting-log-time.patch
| app/models/time_entry.rb | ||
|---|---|---|
| 159 | 159 |
errors.add :activity_id, :inclusion if activity_id_changed? && project && !project.activities.include?(activity) |
| 160 | 160 |
if spent_on_changed? && user |
| 161 | 161 |
errors.add :base, I18n.t(:error_spent_on_future_date) if !Setting.timelog_accept_future_dates? && (spent_on > user.today) |
| 162 |
errors.add :base, I18n.t(:error_spent_on_old_date, :days => Setting.timelog_lock_days_older_than.to_i) if date_is_locked_for_user? |
|
| 162 | 163 |
end |
| 163 | 164 |
end |
| 164 | 165 | |
| ... | ... | |
| 186 | 187 | |
| 187 | 188 |
# Returns true if the time entry can be edited by usr, otherwise false |
| 188 | 189 |
def editable_by?(usr) |
| 189 |
visible?(usr) && ( |
|
| 190 |
visible?(usr) && !date_is_locked_for_user? && (
|
|
| 190 | 191 |
(usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project) |
| 191 | 192 |
) |
| 192 | 193 |
end |
| ... | ... | |
| 231 | 232 |
0.0 |
| 232 | 233 |
end |
| 233 | 234 |
end |
| 235 | ||
| 236 |
# Returns true if time entry is logged on a locked date and the user doesn't have the permission |
|
| 237 |
# to manage time entries on locked dates |
|
| 238 |
def date_is_locked_for_user? |
|
| 239 |
if user && spent_on |
|
| 240 |
number_of_days = Setting.timelog_lock_days_older_than.to_i |
|
| 241 |
((user.today - spent_on).to_i > number_of_days) && !User.current.allowed_to?(:manage_time_entries_on_locked_dates, self.project) |
|
| 242 |
end |
|
| 243 |
end |
|
| 234 | 244 |
end |
| app/views/settings/_timelog.html.erb | ||
|---|---|---|
| 9 | 9 |
<p><%= setting_check_box :timelog_accept_0_hours %></p> |
| 10 | 10 | |
| 11 | 11 |
<p><%= setting_check_box :timelog_accept_future_dates %></p> |
| 12 | ||
| 13 |
<p><%= setting_text_field :timelog_lock_days_older_than, :size => 6 %> <%= l(:label_day_plural) %></p> |
|
| 14 | ||
| 12 | 15 |
</div> |
| 13 | 16 | |
| 14 | 17 |
<fieldset class="box"> |
| config/locales/en.yml | ||
|---|---|---|
| 233 | 233 |
error_can_not_delete_auth_source: "This authentication mode is in use and cannot be deleted." |
| 234 | 234 |
error_spent_on_future_date: "Cannot log time on a future date" |
| 235 | 235 |
error_not_allowed_to_log_time_for_other_users: "You are not allowed to log time for other users" |
| 236 |
error_spent_on_old_date: "Cannot log time on a date older than %{days} days"
|
|
| 236 | 237 | |
| 237 | 238 |
mail_subject_lost_password: "Your %{value} password"
|
| 238 | 239 |
mail_body_lost_password: 'To change your password, click on the following link:' |
| ... | ... | |
| 494 | 495 |
setting_timelog_accept_future_dates: Accept time logs on future dates |
| 495 | 496 |
setting_show_status_changes_in_mail_subject: Show status changes in issue mail notifications subject |
| 496 | 497 |
setting_project_list_defaults: Projects list defaults |
| 498 |
setting_timelog_lock_days_older_than: Lock (add/edit/delete time logs) dates older than |
|
| 497 | 499 | |
| 498 | 500 |
permission_add_project: Create project |
| 499 | 501 |
permission_add_subprojects: Create subprojects |
| config/settings.yml | ||
|---|---|---|
| 337 | 337 |
default: 1 |
| 338 | 338 |
show_status_changes_in_mail_subject: |
| 339 | 339 |
default: 1 |
| 340 |
timelog_lock_days_older_than: |
|
| 341 |
format: int |
|
| 342 |
default: 9999 |
|
| lib/redmine.rb | ||
|---|---|---|
| 133 | 133 |
map.permission :manage_project_activities, {:projects => :settings, :project_enumerations => [:update, :destroy]}, :require => :member
|
| 134 | 134 |
map.permission :log_time_for_other_users, :require => :member |
| 135 | 135 |
map.permission :import_time_entries, {}
|
| 136 |
map.permission :manage_time_entries_on_locked_dates, {}, :require => :loggedin
|
|
| 137 |
map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
|
|
| 136 | 138 |
end |
| 137 | 139 | |
| 138 | 140 |
map.project_module :news do |map| |
| test/fixtures/roles.yml | ||
|---|---|---|
| 37 | 37 |
- :edit_time_entries |
| 38 | 38 |
- :delete_time_entries |
| 39 | 39 |
- :import_time_entries |
| 40 |
- :manage_time_entries_on_locked_dates |
|
| 40 | 41 |
- :view_news |
| 41 | 42 |
- :manage_news |
| 42 | 43 |
- :comment_news |
| ... | ... | |
| 95 | 96 |
- :log_time |
| 96 | 97 |
- :view_time_entries |
| 97 | 98 |
- :edit_own_time_entries |
| 99 |
- :manage_time_entries_on_locked_dates |
|
| 98 | 100 |
- :view_news |
| 99 | 101 |
- :manage_news |
| 100 | 102 |
- :comment_news |
| ... | ... | |
| 141 | 143 |
- :view_calendar |
| 142 | 144 |
- :log_time |
| 143 | 145 |
- :view_time_entries |
| 146 |
- :manage_time_entries_on_locked_dates |
|
| 144 | 147 |
- :view_news |
| 145 | 148 |
- :manage_news |
| 146 | 149 |
- :comment_news |
| ... | ... | |
| 179 | 182 |
- :view_calendar |
| 180 | 183 |
- :log_time |
| 181 | 184 |
- :view_time_entries |
| 185 |
- :manage_time_entries_on_locked_dates |
|
| 182 | 186 |
- :view_news |
| 183 | 187 |
- :comment_news |
| 184 | 188 |
- :view_documents |
| ... | ... | |
| 206 | 210 |
- :view_gantt |
| 207 | 211 |
- :view_calendar |
| 208 | 212 |
- :view_time_entries |
| 213 |
- :manage_time_entries_on_locked_dates |
|
| 209 | 214 |
- :view_news |
| 210 | 215 |
- :view_documents |
| 211 | 216 |
- :view_wiki_pages |
| test/unit/time_entry_test.rb | ||
|---|---|---|
| 127 | 127 | |
| 128 | 128 |
def test_should_accept_future_dates |
| 129 | 129 |
entry = TimeEntry.generate |
| 130 |
entry.spent_on = Date.tomorrow |
|
| 130 | 131 |
entry.spent_on = User.current.today + 1 |
| 131 | 132 | |
| 132 | 133 |
assert entry.save |
| ... | ... | |
| 135 | 136 |
def test_should_not_accept_future_dates_if_disabled |
| 136 | 137 |
with_settings :timelog_accept_future_dates => '0' do |
| 137 | 138 |
entry = TimeEntry.generate |
| 139 |
entry.spent_on = Date.tomorrow |
|
| 138 | 140 |
entry.spent_on = User.current.today + 1 |
| 139 | 141 | |
| 140 | 142 |
assert !entry.save |
| ... | ... | |
| 142 | 144 |
end |
| 143 | 145 |
end |
| 144 | 146 | |
| 147 |
def test_should_allow_time_entries_on_locked_dates_for_users_with_permission |
|
| 148 |
User.current = User.find(2) |
|
| 149 | ||
| 150 |
with_settings :timelog_lock_days_older_than => '5' do |
|
| 151 |
entry = TimeEntry.generate(:project => Project.find(1)) |
|
| 152 |
entry.spent_on = Date.today - 6 |
|
| 153 | ||
| 154 |
assert entry.save |
|
| 155 |
end |
|
| 156 |
end |
|
| 157 | ||
| 158 |
def test_should_not_allow_time_entries_on_locked_dates_for_users_without_permission |
|
| 159 |
User.current = User.find(2) |
|
| 160 |
Role.find(1).remove_permission!(:manage_time_entries_on_locked_dates) |
|
| 161 | ||
| 162 |
with_settings :timelog_lock_days_older_than => '5' do |
|
| 163 |
entry = TimeEntry.generate(:project => Project.find(1)) |
|
| 164 |
entry.spent_on = Date.today - 6 |
|
| 165 | ||
| 166 |
assert !entry.save |
|
| 167 |
assert entry.errors[:base].present? |
|
| 168 |
end |
|
| 169 |
end |
|
| 170 | ||
| 171 |
def test_editable_by_should_return_true_for_time_entry_on_locked_date_and_user_with_permission |
|
| 172 |
user = User.find(2) |
|
| 173 |
User.current = user |
|
| 174 |
time_entry = TimeEntry.find(1) |
|
| 175 | ||
| 176 |
with_settings :timelog_lock_days_older_than => '5' do |
|
| 177 |
assert time_entry.editable_by?(user) |
|
| 178 |
end |
|
| 179 |
end |
|
| 180 | ||
| 181 |
def test_editable_by_should_return_false_for_time_entry_on_locked_date_and_user_without_permission |
|
| 182 |
user = User.find(2) |
|
| 183 |
User.current = user |
|
| 184 |
Role.find(1).remove_permission!(:manage_time_entries_on_locked_dates) |
|
| 185 |
time_entry = TimeEntry.find(1) |
|
| 186 | ||
| 187 |
with_settings :timelog_lock_days_older_than => '5' do |
|
| 188 |
assert !time_entry.editable_by?(user) |
|
| 189 |
end |
|
| 190 |
end |
|
| 191 | ||
| 145 | 192 |
def test_spent_on_with_blank |
| 146 | 193 |
c = TimeEntry.new |
| 147 | 194 |
c.spent_on = '' |