Revision 16859
Added by Jean-Philippe Lang almost 8 years ago
trunk/Gemfile | ||
---|---|---|
4 | 4 |
abort "Redmine requires Bundler 1.5.0 or higher (you're using #{Bundler::VERSION}).\nPlease update with 'gem update bundler'." |
5 | 5 |
end |
6 | 6 |
|
7 |
gem "rails", "4.2.8" |
|
8 |
gem "jquery-rails", "~> 3.1.4" |
|
7 |
gem "rails", "5.1.2" |
|
9 | 8 |
gem "coderay", "~> 1.1.1" |
10 | 9 |
gem "request_store", "1.0.5" |
11 | 10 |
gem "mime-types", "~> 3.0" |
12 |
gem "protected_attributes" |
|
13 | 11 |
gem "actionpack-xml_parser" |
14 |
gem "roadie-rails", "~> 1.1.1"
|
|
12 |
gem "roadie-rails" |
|
15 | 13 |
gem "roadie", "~> 3.2.1" |
16 | 14 |
gem "mimemagic" |
17 | 15 |
|
18 |
gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.7.2" : "~> 1.6.8")
|
|
16 |
gem "nokogiri", "~> 1.7.2"
|
|
19 | 17 |
gem "i18n", "~> 0.7.0" |
20 | 18 |
|
21 | 19 |
# Request at least rails-html-sanitizer 1.0.3 because of security advisories |
... | ... | |
85 | 83 |
end |
86 | 84 |
|
87 | 85 |
group :test do |
88 |
gem "minitest" |
|
89 | 86 |
gem "rails-dom-testing" |
90 | 87 |
gem "mocha" |
91 | 88 |
gem "simplecov", "~> 0.14.1", :require => false |
92 |
# TODO: remove this after upgrading to Rails 5 |
|
93 |
gem "test_after_commit", "~> 0.4.2" |
|
94 | 89 |
# For running UI tests |
95 | 90 |
gem "capybara" |
96 | 91 |
gem "selenium-webdriver", "~> 2.53.4" |
trunk/app/controllers/imports_controller.rb | ||
---|---|---|
109 | 109 |
end |
110 | 110 |
|
111 | 111 |
def update_from_params |
112 |
if params[:import_settings].is_a?(Hash)
|
|
112 |
if params[:import_settings].present?
|
|
113 | 113 |
@import.settings ||= {} |
114 |
@import.settings.merge!(params[:import_settings]) |
|
114 |
@import.settings.merge!(params[:import_settings].to_unsafe_hash)
|
|
115 | 115 |
@import.save! |
116 | 116 |
end |
117 | 117 |
end |
trunk/app/controllers/my_controller.rb | ||
---|---|---|
138 | 138 |
block_settings = params[:settings] || {} |
139 | 139 |
|
140 | 140 |
block_settings.each do |block, settings| |
141 |
@user.pref.update_block_settings(block, settings) |
|
141 |
@user.pref.update_block_settings(block, settings.to_unsafe_hash)
|
|
142 | 142 |
end |
143 | 143 |
@user.pref.save |
144 | 144 |
@updated_blocks = block_settings.keys |
trunk/app/controllers/project_enumerations_controller.rb | ||
---|---|---|
20 | 20 |
before_action :authorize |
21 | 21 |
|
22 | 22 |
def update |
23 |
if params[:enumerations] |
|
24 |
saved = Project.transaction do |
|
25 |
params[:enumerations].each do |id, activity| |
|
26 |
@project.update_or_create_time_entry_activity(id, activity) |
|
27 |
end |
|
28 |
end |
|
29 |
if saved |
|
30 |
flash[:notice] = l(:notice_successful_update) |
|
31 |
end |
|
23 |
if @project.update_or_create_time_entry_activities(update_params) |
|
24 |
flash[:notice] = l(:notice_successful_update) |
|
32 | 25 |
end |
33 | 26 |
|
34 | 27 |
redirect_to settings_project_path(@project, :tab => 'activities') |
... | ... | |
41 | 34 |
flash[:notice] = l(:notice_successful_update) |
42 | 35 |
redirect_to settings_project_path(@project, :tab => 'activities') |
43 | 36 |
end |
37 |
|
|
38 |
private |
|
39 |
|
|
40 |
def update_params |
|
41 |
params. |
|
42 |
permit(:enumerations => [:parent_id, :active, {:custom_field_values => {}}]). |
|
43 |
require(:enumerations) |
|
44 |
end |
|
44 | 45 |
end |
trunk/app/controllers/search_controller.rb | ||
---|---|---|
68 | 68 |
fetcher = Redmine::Search::Fetcher.new( |
69 | 69 |
@question, User.current, @scope, projects_to_search, |
70 | 70 |
:all_words => @all_words, :titles_only => @titles_only, :attachments => @search_attachments, :open_issues => @open_issues, |
71 |
:cache => params[:page].present?, :params => params |
|
71 |
:cache => params[:page].present?, :params => params.to_unsafe_hash
|
|
72 | 72 |
) |
73 | 73 |
|
74 | 74 |
if fetcher.tokens.present? |
trunk/app/controllers/settings_controller.rb | ||
---|---|---|
34 | 34 |
def edit |
35 | 35 |
@notifiables = Redmine::Notifiable.all |
36 | 36 |
if request.post? |
37 |
errors = Setting.set_all_from_params(params[:settings]) |
|
37 |
errors = Setting.set_all_from_params(params[:settings].to_unsafe_hash)
|
|
38 | 38 |
if errors.blank? |
39 | 39 |
flash[:notice] = l(:notice_successful_update) |
40 | 40 |
redirect_to settings_path(:tab => params[:tab]) |
trunk/app/controllers/users_controller.rb | ||
---|---|---|
101 | 101 |
format.html { |
102 | 102 |
flash[:notice] = l(:notice_user_successful_create, :id => view_context.link_to(@user.login, user_path(@user))) |
103 | 103 |
if params[:continue] |
104 |
attrs = params[:user].slice(:generate_password)
|
|
104 |
attrs = {:generate_password => @user.generate_password }
|
|
105 | 105 |
redirect_to new_user_path(:user => attrs) |
106 | 106 |
else |
107 | 107 |
redirect_to edit_user_path(@user) |
trunk/app/helpers/application_helper.rb | ||
---|---|---|
1440 | 1440 |
|
1441 | 1441 |
# Returns the javascript tags that are included in the html layout head |
1442 | 1442 |
def javascript_heads |
1443 |
tags = javascript_include_tag('jquery-1.11.1-ui-1.11.0-ujs-3.1.4', 'application', 'responsive')
|
|
1443 |
tags = javascript_include_tag('jquery-1.11.1-ui-1.11.0-ujs-5.1.2', 'application', 'responsive')
|
|
1444 | 1444 |
unless User.current.pref.warn_on_leaving_unsaved == '0' |
1445 | 1445 |
tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") |
1446 | 1446 |
end |
trunk/app/models/attachment.rb | ||
---|---|---|
28 | 28 |
validates_length_of :disk_filename, :maximum => 255 |
29 | 29 |
validates_length_of :description, :maximum => 255 |
30 | 30 |
validate :validate_max_file_size, :validate_file_extension |
31 |
attr_protected :id |
|
32 | 31 |
|
33 | 32 |
acts_as_event :title => :filename, |
34 | 33 |
:url => Proc.new {|o| {:controller => 'attachments', :action => 'show', :id => o.id, :filename => o.filename}} |
trunk/app/models/auth_source.rb | ||
---|---|---|
30 | 30 |
validates_presence_of :name |
31 | 31 |
validates_uniqueness_of :name |
32 | 32 |
validates_length_of :name, :maximum => 60 |
33 |
attr_protected :id |
|
34 | 33 |
|
35 | 34 |
safe_attributes 'name', |
36 | 35 |
'host', |
trunk/app/models/board.rb | ||
---|---|---|
28 | 28 |
validates_length_of :name, :maximum => 30 |
29 | 29 |
validates_length_of :description, :maximum => 255 |
30 | 30 |
validate :validate_board |
31 |
attr_protected :id |
|
32 | 31 |
|
33 | 32 |
scope :visible, lambda {|*args| |
34 | 33 |
joins(:project). |
trunk/app/models/change.rb | ||
---|---|---|
21 | 21 |
validates_presence_of :changeset_id, :action, :path |
22 | 22 |
before_save :init_path |
23 | 23 |
before_validation :replace_invalid_utf8_of_path |
24 |
attr_protected :id |
|
25 | 24 |
|
26 | 25 |
def replace_invalid_utf8_of_path |
27 | 26 |
self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path) |
trunk/app/models/changeset.rb | ||
---|---|---|
46 | 46 |
validates_presence_of :repository_id, :revision, :committed_on, :commit_date |
47 | 47 |
validates_uniqueness_of :revision, :scope => :repository_id |
48 | 48 |
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true |
49 |
attr_protected :id |
|
50 | 49 |
|
51 | 50 |
scope :visible, lambda {|*args| |
52 | 51 |
joins(:repository => :project). |
trunk/app/models/comment.rb | ||
---|---|---|
21 | 21 |
belongs_to :author, :class_name => 'User' |
22 | 22 |
|
23 | 23 |
validates_presence_of :commented, :author, :comments |
24 |
attr_protected :id |
|
25 | 24 |
|
26 | 25 |
after_create :send_notification |
27 | 26 |
|
trunk/app/models/custom_field.rb | ||
---|---|---|
35 | 35 |
validates_length_of :regexp, maximum: 255 |
36 | 36 |
validates_inclusion_of :field_format, :in => Proc.new { Redmine::FieldFormat.available_formats } |
37 | 37 |
validate :validate_custom_field |
38 |
attr_protected :id |
|
39 | 38 |
|
40 | 39 |
before_validation :set_searchable |
41 | 40 |
before_save do |field| |
... | ... | |
43 | 42 |
end |
44 | 43 |
after_save :handle_multiplicity_change |
45 | 44 |
after_save do |field| |
46 |
if field.visible_changed? && field.visible
|
|
45 |
if field.saved_change_to_visible? && field.visible
|
|
47 | 46 |
field.roles.clear |
48 | 47 |
end |
49 | 48 |
end |
... | ... | |
316 | 315 |
# Removes multiple values for the custom field after setting the multiple attribute to false |
317 | 316 |
# We kepp the value with the highest id for each customized object |
318 | 317 |
def handle_multiplicity_change |
319 |
if !new_record? && multiple_was && !multiple
|
|
318 |
if !new_record? && multiple_before_last_save && !multiple
|
|
320 | 319 |
ids = custom_values. |
321 | 320 |
where("EXISTS(SELECT 1 FROM #{CustomValue.table_name} cve WHERE cve.custom_field_id = #{CustomValue.table_name}.custom_field_id" + |
322 | 321 |
" AND cve.customized_type = #{CustomValue.table_name}.customized_type AND cve.customized_id = #{CustomValue.table_name}.customized_id" + |
trunk/app/models/custom_value.rb | ||
---|---|---|
18 | 18 |
class CustomValue < ActiveRecord::Base |
19 | 19 |
belongs_to :custom_field |
20 | 20 |
belongs_to :customized, :polymorphic => true |
21 |
attr_protected :id |
|
22 | 21 |
|
23 | 22 |
after_save :custom_field_after_save_custom_value |
24 | 23 |
|
trunk/app/models/document.rb | ||
---|---|---|
31 | 31 |
|
32 | 32 |
validates_presence_of :project, :title, :category |
33 | 33 |
validates_length_of :title, :maximum => 255 |
34 |
attr_protected :id |
|
35 | 34 |
|
36 | 35 |
after_create :send_notification |
37 | 36 |
|
trunk/app/models/email_address.rb | ||
---|---|---|
19 | 19 |
include Redmine::SafeAttributes |
20 | 20 |
|
21 | 21 |
belongs_to :user |
22 |
attr_protected :id |
|
23 | 22 |
|
24 | 23 |
after_create :deliver_security_notification_create |
25 | 24 |
after_update :destroy_tokens, :deliver_security_notification_update |
... | ... | |
63 | 62 |
|
64 | 63 |
# send a security notification to user that an email has been changed (notified/not notified) |
65 | 64 |
def deliver_security_notification_update |
66 |
if address_changed?
|
|
67 |
recipients = [user, address_was]
|
|
65 |
if saved_change_to_address?
|
|
66 |
recipients = [user, address_before_last_save]
|
|
68 | 67 |
options = { |
69 | 68 |
message: :mail_body_security_notification_change_to, |
70 | 69 |
field: :field_mail, |
71 | 70 |
value: address |
72 | 71 |
} |
73 |
elsif notify_changed?
|
|
72 |
elsif saved_change_to_notify?
|
|
74 | 73 |
recipients = [user, address] |
75 | 74 |
options = { |
76 |
message: notify_was ? :mail_body_security_notification_notify_disabled : :mail_body_security_notification_notify_enabled,
|
|
75 |
message: notify_before_last_save ? :mail_body_security_notification_notify_disabled : :mail_body_security_notification_notify_enabled,
|
|
77 | 76 |
value: address |
78 | 77 |
} |
79 | 78 |
end |
... | ... | |
103 | 102 |
# This helps to keep the account secure in case the associated email account |
104 | 103 |
# was compromised. |
105 | 104 |
def destroy_tokens |
106 |
if address_changed? || destroyed?
|
|
105 |
if saved_change_to_address? || destroyed?
|
|
107 | 106 |
tokens = ['recovery'] |
108 | 107 |
Token.where(:user_id => user_id, :action => tokens).delete_all |
109 | 108 |
end |
trunk/app/models/enabled_module.rb | ||
---|---|---|
21 | 21 |
|
22 | 22 |
validates_presence_of :name |
23 | 23 |
validates_uniqueness_of :name, :scope => :project_id |
24 |
attr_protected :id |
|
25 | 24 |
|
26 | 25 |
after_create :module_enabled |
27 | 26 |
|
trunk/app/models/enumeration.rb | ||
---|---|---|
29 | 29 |
before_destroy :check_integrity |
30 | 30 |
before_save :check_default |
31 | 31 |
|
32 |
attr_protected :type |
|
33 |
|
|
34 | 32 |
validates_presence_of :name |
35 | 33 |
validates_uniqueness_of :name, :scope => [:type, :project_id] |
36 | 34 |
validates_length_of :name, :maximum => 30 |
... | ... | |
148 | 146 |
# position as the overridden enumeration |
149 | 147 |
def update_position |
150 | 148 |
super |
151 |
if position_changed?
|
|
149 |
if saved_change_to_position?
|
|
152 | 150 |
self.class.where.not(:parent_id => nil).update_all( |
153 | 151 |
"position = coalesce(( |
154 | 152 |
select position |
trunk/app/models/group.rb | ||
---|---|---|
28 | 28 |
validates_presence_of :lastname |
29 | 29 |
validates_uniqueness_of :lastname, :case_sensitive => false |
30 | 30 |
validates_length_of :lastname, :maximum => 255 |
31 |
attr_protected :id |
|
32 | 31 |
|
33 | 32 |
self.valid_statuses = [STATUS_ACTIVE] |
34 | 33 |
|
trunk/app/models/issue.rb | ||
---|---|---|
69 | 69 |
validates :start_date, :date => true |
70 | 70 |
validates :due_date, :date => true |
71 | 71 |
validate :validate_issue, :validate_required_fields, :validate_permissions |
72 |
attr_protected :id |
|
73 | 72 |
|
74 | 73 |
scope :visible, lambda {|*args| |
75 | 74 |
joins(:project). |
... | ... | |
108 | 107 |
before_validation :default_assign, on: :create |
109 | 108 |
before_validation :clear_disabled_fields |
110 | 109 |
before_save :close_duplicates, :update_done_ratio_from_issue_status, |
111 |
:force_updated_on_change, :update_closed_on, :set_assigned_to_was
|
|
112 |
after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?}
|
|
110 |
:force_updated_on_change, :update_closed_on |
|
111 |
after_save {|issue| issue.send :after_project_change if !issue.saved_change_to_id? && issue.saved_change_to_project_id?}
|
|
113 | 112 |
after_save :reschedule_following_issues, :update_nested_set_attributes, |
114 | 113 |
:update_parent_attributes, :delete_selected_attachments, :create_journal |
115 | 114 |
# Should be after_create but would be called before previous after_save callbacks |
116 | 115 |
after_save :after_create_from_copy |
117 | 116 |
after_destroy :update_parent_attributes |
118 | 117 |
after_create :send_notification |
119 |
# Keep it at the end of after_save callbacks |
|
120 |
after_save :clear_assigned_to_was |
|
121 | 118 |
|
122 | 119 |
# Returns a SQL conditions string used to find all issues visible by the specified user |
123 | 120 |
def self.visible_condition(user, options={}) |
... | ... | |
208 | 205 |
end |
209 | 206 |
end |
210 | 207 |
|
211 |
def create_or_update |
|
208 |
def create_or_update(*args)
|
|
212 | 209 |
super |
213 | 210 |
ensure |
214 | 211 |
@status_was = nil |
... | ... | |
512 | 509 |
# attr_accessible is too rough because we still want things like |
513 | 510 |
# Issue.new(:project => foo) to work |
514 | 511 |
def safe_attributes=(attrs, user=User.current) |
512 |
if attrs.respond_to?(:to_unsafe_hash) |
|
513 |
attrs = attrs.to_unsafe_hash |
|
514 |
end |
|
515 |
|
|
515 | 516 |
@attributes_set_by = user |
516 | 517 |
return unless attrs.is_a?(Hash) |
517 | 518 |
|
... | ... | |
586 | 587 |
attrs['custom_fields'].select! {|c| editable_custom_field_ids.include?(c['id'].to_s)} |
587 | 588 |
end |
588 | 589 |
|
589 |
# mass-assignment security bypass |
|
590 |
assign_attributes attrs, :without_protection => true |
|
590 |
assign_attributes attrs |
|
591 | 591 |
end |
592 | 592 |
|
593 | 593 |
def disabled_core_fields |
... | ... | |
1007 | 1007 |
statuses |
1008 | 1008 |
end |
1009 | 1009 |
|
1010 |
# Returns the previous assignee (user or group) if changed |
|
1011 |
def assigned_to_was |
|
1012 |
# assigned_to_id_was is reset before after_save callbacks |
|
1013 |
user_id = @previous_assigned_to_id || assigned_to_id_was |
|
1014 |
if user_id && user_id != assigned_to_id |
|
1015 |
@assigned_to_was ||= Principal.find_by_id(user_id) |
|
1016 |
end |
|
1017 |
end |
|
1018 |
|
|
1019 | 1010 |
# Returns the original tracker |
1020 | 1011 |
def tracker_was |
1021 |
Tracker.find_by_id(tracker_id_was)
|
|
1012 |
Tracker.find_by_id(tracker_id_in_database)
|
|
1022 | 1013 |
end |
1023 | 1014 |
|
1015 |
# Returns the previous assignee whenever we're before the save |
|
1016 |
# or in after_* callbacks |
|
1017 |
def previous_assignee |
|
1018 |
# This is how ActiveRecord::AttributeMethods::Dirty checks if we're in a after_* callback |
|
1019 |
if previous_assigned_to_id = mutation_tracker.equal?(mutations_from_database) ? assigned_to_id_in_database : assigned_to_id_before_last_save |
|
1020 |
Principal.find_by_id(previous_assigned_to_id) |
|
1021 |
end |
|
1022 |
end |
|
1023 |
|
|
1024 | 1024 |
# Returns the users that should be notified |
1025 | 1025 |
def notified_users |
1026 |
notified = [] |
|
1027 | 1026 |
# Author and assignee are always notified unless they have been |
1028 | 1027 |
# locked or don't want to be notified |
1029 |
notified << author if author |
|
1030 |
if assigned_to |
|
1031 |
notified += (assigned_to.is_a?(Group) ? assigned_to.users : [assigned_to]) |
|
1032 |
end |
|
1033 |
if assigned_to_was |
|
1034 |
notified += (assigned_to_was.is_a?(Group) ? assigned_to_was.users : [assigned_to_was]) |
|
1035 |
end |
|
1028 |
notified = [author, assigned_to, previous_assignee].compact.uniq |
|
1029 |
notified = notified.map {|n| n.is_a?(Group) ? n.users : n}.flatten |
|
1030 |
notified.uniq! |
|
1036 | 1031 |
notified = notified.select {|u| u.active? && u.notify_about?(self)} |
1037 | 1032 |
|
1038 | 1033 |
notified += project.notified_users |
... | ... | |
1587 | 1582 |
|
1588 | 1583 |
# Move subtasks that were in the same project |
1589 | 1584 |
children.each do |child| |
1590 |
next unless child.project_id == project_id_was
|
|
1585 |
next unless child.project_id == project_id_before_last_save
|
|
1591 | 1586 |
# Change project and keep project |
1592 | 1587 |
child.send :project=, project, true |
1593 | 1588 |
unless child.save |
... | ... | |
1644 | 1639 |
end |
1645 | 1640 |
|
1646 | 1641 |
def update_nested_set_attributes |
1647 |
if parent_id_changed?
|
|
1642 |
if saved_change_to_parent_id?
|
|
1648 | 1643 |
update_nested_set_attributes_on_parent_change |
1649 | 1644 |
end |
1650 | 1645 |
remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue) |
... | ... | |
1652 | 1647 |
|
1653 | 1648 |
# Updates the nested set for when an existing issue is moved |
1654 | 1649 |
def update_nested_set_attributes_on_parent_change |
1655 |
former_parent_id = parent_id_was
|
|
1650 |
former_parent_id = parent_id_before_last_save
|
|
1656 | 1651 |
# delete invalid relations of all descendants |
1657 | 1652 |
self_and_descendants.each do |issue| |
1658 | 1653 |
issue.relations.each do |relation| |
... | ... | |
1789 | 1784 |
|
1790 | 1785 |
# Updates start/due dates of following issues |
1791 | 1786 |
def reschedule_following_issues |
1792 |
if start_date_changed? || due_date_changed?
|
|
1787 |
if saved_change_to_start_date? || saved_change_to_due_date?
|
|
1793 | 1788 |
relations_from.each do |relation| |
1794 | 1789 |
relation.set_issue_to_dates |
1795 | 1790 |
end |
... | ... | |
1848 | 1843 |
end |
1849 | 1844 |
end |
1850 | 1845 |
|
1851 |
# Stores the previous assignee so we can still have access |
|
1852 |
# to it during after_save callbacks (assigned_to_id_was is reset) |
|
1853 |
def set_assigned_to_was |
|
1854 |
@previous_assigned_to_id = assigned_to_id_was |
|
1855 |
end |
|
1856 |
|
|
1857 |
# Clears the previous assignee at the end of after_save callbacks |
|
1858 |
def clear_assigned_to_was |
|
1859 |
@assigned_to_was = nil |
|
1860 |
@previous_assigned_to_id = nil |
|
1861 |
end |
|
1862 |
|
|
1863 | 1846 |
def clear_disabled_fields |
1864 | 1847 |
if tracker |
1865 | 1848 |
tracker.disabled_core_fields.each do |attribute| |
trunk/app/models/issue_category.rb | ||
---|---|---|
24 | 24 |
validates_presence_of :name |
25 | 25 |
validates_uniqueness_of :name, :scope => [:project_id] |
26 | 26 |
validates_length_of :name, :maximum => 60 |
27 |
attr_protected :id |
|
28 | 27 |
|
29 | 28 |
safe_attributes 'name', 'assigned_to_id' |
30 | 29 |
|
trunk/app/models/issue_custom_field.rb | ||
---|---|---|
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
|
18 | 18 |
class IssueCustomField < CustomField |
19 |
has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id" |
|
20 |
has_and_belongs_to_many :trackers, :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :foreign_key => "custom_field_id" |
|
19 |
has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id", :autosave => true
|
|
20 |
has_and_belongs_to_many :trackers, :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :foreign_key => "custom_field_id", :autosave => true
|
|
21 | 21 |
has_many :issues, :through => :issue_custom_values |
22 | 22 |
|
23 | 23 |
safe_attributes 'project_ids', |
trunk/app/models/issue_priority.rb | ||
---|---|---|
19 | 19 |
has_many :issues, :foreign_key => 'priority_id' |
20 | 20 |
|
21 | 21 |
after_destroy {|priority| priority.class.compute_position_names} |
22 |
after_save {|priority| priority.class.compute_position_names if (priority.position_changed? && priority.position) || priority.active_changed?}
|
|
22 |
after_save {|priority| priority.class.compute_position_names if (priority.saved_change_to_position? && priority.position) || priority.saved_change_to_active?}
|
|
23 | 23 |
|
24 | 24 |
OptionName = :enumeration_issue_priorities |
25 | 25 |
|
trunk/app/models/issue_relation.rb | ||
---|---|---|
72 | 72 |
validates_uniqueness_of :issue_to_id, :scope => :issue_from_id |
73 | 73 |
validate :validate_issue_relation |
74 | 74 |
|
75 |
attr_protected :issue_from_id, :issue_to_id |
|
76 | 75 |
before_save :handle_issue_order |
77 | 76 |
after_create :call_issues_relation_added_callback |
78 | 77 |
after_destroy :call_issues_relation_removed_callback |
... | ... | |
82 | 81 |
'issue_to_id' |
83 | 82 |
|
84 | 83 |
def safe_attributes=(attrs, user=User.current) |
84 |
if attrs.respond_to?(:to_unsafe_hash) |
|
85 |
attrs = attrs.to_unsafe_hash |
|
86 |
end |
|
87 |
|
|
85 | 88 |
return unless attrs.is_a?(Hash) |
86 | 89 |
attrs = attrs.deep_dup |
87 | 90 |
|
trunk/app/models/issue_status.rb | ||
---|---|---|
30 | 30 |
validates_uniqueness_of :name |
31 | 31 |
validates_length_of :name, :maximum => 30 |
32 | 32 |
validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true |
33 |
attr_protected :id |
|
34 | 33 |
|
35 | 34 |
scope :sorted, lambda { order(:position) } |
36 | 35 |
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} |
... | ... | |
89 | 88 |
|
90 | 89 |
# Updates issues closed_on attribute when an existing status is set as closed. |
91 | 90 |
def handle_is_closed_change |
92 |
if is_closed_changed? && is_closed == true
|
|
91 |
if saved_change_to_is_closed? && is_closed == true
|
|
93 | 92 |
# First we update issues that have a journal for when the current status was set, |
94 | 93 |
# a subselect is used to update all issues with a single query |
95 | 94 |
subquery = Journal.joins(:details). |
trunk/app/models/journal.rb | ||
---|---|---|
26 | 26 |
belongs_to :user |
27 | 27 |
has_many :details, :class_name => "JournalDetail", :dependent => :delete_all, :inverse_of => :journal |
28 | 28 |
attr_accessor :indice |
29 |
attr_protected :id |
|
30 | 29 |
|
31 | 30 |
acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" }, |
32 | 31 |
:description => :notes, |
trunk/app/models/journal_detail.rb | ||
---|---|---|
17 | 17 |
|
18 | 18 |
class JournalDetail < ActiveRecord::Base |
19 | 19 |
belongs_to :journal |
20 |
attr_protected :id |
|
21 | 20 |
|
22 | 21 |
def custom_field |
23 | 22 |
if property == 'cf' |
trunk/app/models/member.rb | ||
---|---|---|
25 | 25 |
validates_presence_of :principal, :project |
26 | 26 |
validates_uniqueness_of :user_id, :scope => :project_id |
27 | 27 |
validate :validate_role |
28 |
attr_protected :id |
|
29 | 28 |
|
30 | 29 |
before_destroy :set_issue_category_nil, :remove_from_project_default_assigned_to |
31 | 30 |
|
trunk/app/models/member_role.rb | ||
---|---|---|
26 | 26 |
|
27 | 27 |
validates_presence_of :role |
28 | 28 |
validate :validate_role_member |
29 |
attr_protected :id |
|
30 | 29 |
|
31 | 30 |
def validate_role_member |
32 | 31 |
errors.add :role_id, :invalid if role && !role.member? |
trunk/app/models/message.rb | ||
---|---|---|
22 | 22 |
acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" |
23 | 23 |
acts_as_attachable |
24 | 24 |
belongs_to :last_reply, :class_name => 'Message' |
25 |
attr_protected :id |
|
26 | 25 |
|
27 | 26 |
acts_as_searchable :columns => ['subject', 'content'], |
28 | 27 |
:preload => {:board => :project}, |
... | ... | |
69 | 68 |
end |
70 | 69 |
|
71 | 70 |
def update_messages_board |
72 |
if board_id_changed?
|
|
71 |
if saved_change_to_board_id?
|
|
73 | 72 |
Message.where(["id = ? OR parent_id = ?", root.id, root.id]).update_all({:board_id => board_id}) |
74 |
Board.reset_counters!(board_id_was)
|
|
73 |
Board.reset_counters!(board_id_before_last_save)
|
|
75 | 74 |
Board.reset_counters!(board_id) |
76 | 75 |
end |
77 | 76 |
end |
trunk/app/models/news.rb | ||
---|---|---|
24 | 24 |
validates_presence_of :title, :description |
25 | 25 |
validates_length_of :title, :maximum => 60 |
26 | 26 |
validates_length_of :summary, :maximum => 255 |
27 |
attr_protected :id |
|
28 | 27 |
|
29 | 28 |
acts_as_attachable :edit_permission => :manage_news, |
30 | 29 |
:delete_permission => :manage_news |
trunk/app/models/project.rb | ||
---|---|---|
67 | 67 |
:url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o}}, |
68 | 68 |
:author => nil |
69 | 69 |
|
70 |
attr_protected :status |
|
71 |
|
|
72 | 70 |
validates_presence_of :name, :identifier |
73 | 71 |
validates_uniqueness_of :identifier, :if => Proc.new {|p| p.identifier_changed?} |
74 | 72 |
validates_length_of :name, :maximum => 255 |
... | ... | |
80 | 78 |
validates_exclusion_of :identifier, :in => %w( new ) |
81 | 79 |
validate :validate_parent |
82 | 80 |
|
83 |
after_save :update_inherited_members, :if => Proc.new {|project| project.inherit_members_changed?}
|
|
84 |
after_save :remove_inherited_member_roles, :add_inherited_member_roles, :if => Proc.new {|project| project.parent_id_changed?}
|
|
85 |
after_update :update_versions_from_hierarchy_change, :if => Proc.new {|project| project.parent_id_changed?}
|
|
81 |
after_save :update_inherited_members, :if => Proc.new {|project| project.saved_change_to_inherit_members?}
|
|
82 |
after_save :remove_inherited_member_roles, :add_inherited_member_roles, :if => Proc.new {|project| project.saved_change_to_parent_id?}
|
|
83 |
after_update :update_versions_from_hierarchy_change, :if => Proc.new {|project| project.saved_change_to_parent_id?}
|
|
86 | 84 |
before_destroy :delete_all_members |
87 | 85 |
|
88 | 86 |
scope :has_module, lambda {|mod| |
... | ... | |
257 | 255 |
scope |
258 | 256 |
end |
259 | 257 |
|
258 |
# Creates or updates project time entry activities |
|
259 |
def update_or_create_time_entry_activities(activities) |
|
260 |
transaction do |
|
261 |
activities.each do |id, activity| |
|
262 |
update_or_create_time_entry_activity(id, activity) |
|
263 |
end |
|
264 |
end |
|
265 |
end |
|
266 |
|
|
260 | 267 |
# Will create a new Project specific Activity or update an existing one |
261 | 268 |
# |
262 | 269 |
# This will raise a ActiveRecord::Rollback if the TimeEntryActivity |
... | ... | |
776 | 783 |
:if => lambda {|project, user| project.parent.nil? || project.parent.visible?(user)} |
777 | 784 |
|
778 | 785 |
def safe_attributes=(attrs, user=User.current) |
786 |
if attrs.respond_to?(:to_unsafe_hash) |
|
787 |
attrs = attrs.to_unsafe_hash |
|
788 |
end |
|
789 |
|
|
779 | 790 |
return unless attrs.is_a?(Hash) |
780 | 791 |
attrs = attrs.deep_dup |
781 | 792 |
|
... | ... | |
872 | 883 |
|
873 | 884 |
def update_inherited_members |
874 | 885 |
if parent |
875 |
if inherit_members? && !inherit_members_was
|
|
886 |
if inherit_members? && !inherit_members_before_last_save
|
|
876 | 887 |
remove_inherited_member_roles |
877 | 888 |
add_inherited_member_roles |
878 |
elsif !inherit_members? && inherit_members_was
|
|
889 |
elsif !inherit_members? && inherit_members_before_last_save
|
|
879 | 890 |
remove_inherited_member_roles |
880 | 891 |
end |
881 | 892 |
end |
trunk/app/models/query.rb | ||
---|---|---|
212 | 212 |
serialize :sort_criteria, Array |
213 | 213 |
serialize :options, Hash |
214 | 214 |
|
215 |
attr_protected :project_id, :user_id |
|
216 |
|
|
217 | 215 |
validates_presence_of :name |
218 | 216 |
validates_length_of :name, :maximum => 255 |
219 | 217 |
validates :visibility, :inclusion => { :in => [VISIBILITY_PUBLIC, VISIBILITY_ROLES, VISIBILITY_PRIVATE] } |
... | ... | |
223 | 221 |
end |
224 | 222 |
|
225 | 223 |
after_save do |query| |
226 |
if query.visibility_changed? && query.visibility != VISIBILITY_ROLES
|
|
224 |
if query.saved_change_to_visibility? && query.visibility != VISIBILITY_ROLES
|
|
227 | 225 |
query.roles.clear |
228 | 226 |
end |
229 | 227 |
end |
... | ... | |
623 | 621 |
|
624 | 622 |
# Add multiple filters using +add_filter+ |
625 | 623 |
def add_filters(fields, operators, values) |
626 |
if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash))
|
|
624 |
if fields.present? && operators.present?
|
|
627 | 625 |
fields.each do |field| |
628 | 626 |
add_filter(field, operators[field], values && values[field]) |
629 | 627 |
end |
trunk/app/models/repository/bazaar.rb | ||
---|---|---|
18 | 18 |
require 'redmine/scm/adapters/bazaar_adapter' |
19 | 19 |
|
20 | 20 |
class Repository::Bazaar < Repository |
21 |
attr_protected :root_url |
|
22 | 21 |
validates_presence_of :url, :log_encoding |
23 | 22 |
|
24 | 23 |
def self.human_attribute_name(attribute_key_name, *args) |
trunk/app/models/repository/filesystem.rb | ||
---|---|---|
21 | 21 |
require 'redmine/scm/adapters/filesystem_adapter' |
22 | 22 |
|
23 | 23 |
class Repository::Filesystem < Repository |
24 |
attr_protected :root_url |
|
25 | 24 |
validates_presence_of :url |
26 | 25 |
|
27 | 26 |
def self.human_attribute_name(attribute_key_name, *args) |
trunk/app/models/repository/git.rb | ||
---|---|---|
19 | 19 |
require 'redmine/scm/adapters/git_adapter' |
20 | 20 |
|
21 | 21 |
class Repository::Git < Repository |
22 |
attr_protected :root_url |
|
23 | 22 |
validates_presence_of :url |
24 | 23 |
|
25 | 24 |
safe_attributes 'report_last_commit' |
trunk/app/models/repository/mercurial.rb | ||
---|---|---|
23 | 23 |
lambda {order("#{Changeset.table_name}.id DESC")}, |
24 | 24 |
:foreign_key => 'repository_id' |
25 | 25 |
|
26 |
attr_protected :root_url |
|
27 | 26 |
validates_presence_of :url |
28 | 27 |
|
29 | 28 |
# number of changesets to fetch at once |
trunk/app/models/repository/subversion.rb | ||
---|---|---|
18 | 18 |
require 'redmine/scm/adapters/subversion_adapter' |
19 | 19 |
|
20 | 20 |
class Repository::Subversion < Repository |
21 |
attr_protected :root_url |
|
22 | 21 |
validates_presence_of :url |
23 | 22 |
validates_format_of :url, :with => %r{\A(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+}i |
24 | 23 |
|
trunk/app/models/repository.rb | ||
---|---|---|
48 | 48 |
# Checks if the SCM is enabled when creating a repository |
49 | 49 |
validate :repo_create_validation, :on => :create |
50 | 50 |
validate :validate_repository_path |
51 |
attr_protected :id |
|
52 | 51 |
|
53 | 52 |
safe_attributes 'identifier', |
54 | 53 |
'login', |
trunk/app/models/role.rb | ||
---|---|---|
77 | 77 |
|
78 | 78 |
serialize :permissions, ::Role::PermissionsAttributeCoder |
79 | 79 |
store :settings, :accessors => [:permissions_all_trackers, :permissions_tracker_ids] |
80 |
attr_protected :builtin |
|
81 | 80 |
|
82 | 81 |
validates_presence_of :name |
83 | 82 |
validates_uniqueness_of :name |
trunk/app/models/setting.rb | ||
---|---|---|
82 | 82 |
validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| |
83 | 83 |
(s = available_settings[setting.name]) && s['format'] == 'int' |
84 | 84 |
} |
85 |
attr_protected :id |
|
86 | 85 |
|
87 | 86 |
# Hash used to cache setting values |
88 | 87 |
@cached_settings = {} |
trunk/app/models/time_entry.rb | ||
---|---|---|
24 | 24 |
belongs_to :user |
25 | 25 |
belongs_to :activity, :class_name => 'TimeEntryActivity' |
26 | 26 |
|
27 |
attr_protected :user_id, :tyear, :tmonth, :tweek |
|
28 |
|
|
29 | 27 |
acts_as_customizable |
30 | 28 |
acts_as_event :title => Proc.new { |o| |
31 | 29 |
related = o.issue if o.issue && o.issue.visible? |
trunk/app/models/token.rb | ||
---|---|---|
18 | 18 |
class Token < ActiveRecord::Base |
19 | 19 |
belongs_to :user |
20 | 20 |
validates_uniqueness_of :value |
21 |
attr_protected :id |
|
22 | 21 |
|
23 | 22 |
before_create :delete_previous_tokens, :generate_new_token |
24 | 23 |
|
trunk/app/models/tracker.rb | ||
---|---|---|
37 | 37 |
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id' |
38 | 38 |
acts_as_positioned |
39 | 39 |
|
40 |
attr_protected :fields_bits |
|
41 |
|
|
42 | 40 |
validates_presence_of :default_status |
43 | 41 |
validates_presence_of :name |
44 | 42 |
validates_uniqueness_of :name |
trunk/app/models/user.rb | ||
---|---|---|
99 | 99 |
attr_accessor :last_before_login_on |
100 | 100 |
attr_accessor :remote_ip |
101 | 101 |
|
102 |
# Prevents unauthorized assignments |
|
103 |
attr_protected :password, :password_confirmation, :hashed_password |
|
104 |
|
|
105 | 102 |
LOGIN_LENGTH_LIMIT = 60 |
106 | 103 |
MAIL_LENGTH_LIMIT = 60 |
107 | 104 |
|
... | ... | |
771 | 768 |
case mail_notification |
772 | 769 |
when 'selected', 'only_my_events' |
773 | 770 |
# user receives notifications for created/assigned issues on unselected projects |
774 |
object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
|
|
771 |
object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.previous_assignee)
|
|
775 | 772 |
when 'only_assigned' |
776 |
is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
|
|
773 |
is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.previous_assignee)
|
|
777 | 774 |
when 'only_owner' |
778 | 775 |
object.author == self |
779 | 776 |
end |
... | ... | |
845 | 842 |
# This helps to keep the account secure in case the associated email account |
846 | 843 |
# was compromised. |
847 | 844 |
def destroy_tokens |
848 |
if hashed_password_changed? || (status_changed? && !active?)
|
|
845 |
if saved_change_to_hashed_password? || (saved_change_to_status? && !active?)
|
|
849 | 846 |
tokens = ['recovery', 'autologin', 'session'] |
850 | 847 |
Token.where(:user_id => id, :action => tokens).delete_all |
851 | 848 |
end |
... | ... | |
900 | 897 |
} |
901 | 898 |
|
902 | 899 |
deliver = false |
903 |
if (admin? && id_changed? && active?) || # newly created admin
|
|
904 |
(admin? && admin_changed? && active?) || # regular user became admin
|
|
905 |
(admin? && status_changed? && active?) # locked admin became active again
|
|
900 |
if (admin? && saved_change_to_id? && active?) || # newly created admin
|
|
901 |
(admin? && saved_change_to_admin? && active?) || # regular user became admin
|
|
902 |
(admin? && saved_change_to_status? && active?) # locked admin became active again
|
|
906 | 903 |
|
907 | 904 |
deliver = true |
908 | 905 |
options[:message] = :mail_body_security_notification_add |
909 | 906 |
|
910 | 907 |
elsif (admin? && destroyed? && active?) || # active admin user was deleted |
911 |
(!admin? && admin_changed? && active?) || # admin is no longer admin
|
|
912 |
(admin? && status_changed? && !active?) # admin was locked
|
|
908 |
(!admin? && saved_change_to_admin? && active?) || # admin is no longer admin
|
|
909 |
(admin? && saved_change_to_status? && !active?) # admin was locked
|
|
913 | 910 |
|
914 | 911 |
deliver = true |
915 | 912 |
options[:message] = :mail_body_security_notification_remove |
trunk/app/models/user_preference.rb | ||
---|---|---|
21 | 21 |
belongs_to :user |
22 | 22 |
serialize :others |
23 | 23 |
|
24 |
attr_protected :others, :user_id |
|
25 |
|
|
26 | 24 |
before_save :set_others_hash, :clear_unused_block_settings |
27 | 25 |
|
28 | 26 |
safe_attributes 'hide_mail', |
trunk/app/models/version.rb | ||
---|---|---|
39 | 39 |
validates :effective_date, :date => true |
40 | 40 |
validates_inclusion_of :status, :in => VERSION_STATUSES |
41 | 41 |
validates_inclusion_of :sharing, :in => VERSION_SHARINGS |
42 |
attr_protected :id |
|
43 | 42 |
|
44 | 43 |
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} |
45 | 44 |
scope :like, lambda {|arg| |
... | ... | |
302 | 301 |
|
303 | 302 |
# Update the issue's fixed versions. Used if a version's sharing changes. |
304 | 303 |
def update_issues_from_sharing_change |
305 |
if sharing_changed?
|
|
306 |
if VERSION_SHARINGS.index(sharing_was).nil? ||
|
|
304 |
if saved_change_to_sharing?
|
|
305 |
if VERSION_SHARINGS.index(sharing_before_last_save).nil? ||
|
|
307 | 306 |
VERSION_SHARINGS.index(sharing).nil? || |
308 |
VERSION_SHARINGS.index(sharing_was) > VERSION_SHARINGS.index(sharing)
|
|
307 |
VERSION_SHARINGS.index(sharing_before_last_save) > VERSION_SHARINGS.index(sharing)
|
|
309 | 308 |
Issue.update_versions_from_sharing_change self |
310 | 309 |
end |
311 | 310 |
end |
trunk/app/models/watcher.rb | ||
---|---|---|
22 | 22 |
validates_presence_of :user |
23 | 23 |
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id] |
24 | 24 |
validate :validate_user |
25 |
attr_protected :id |
|
26 | 25 |
|
27 | 26 |
# Returns true if at least one object among objects is watched by user |
28 | 27 |
def self.any_watched?(objects, user) |
trunk/app/models/wiki.rb | ||
---|---|---|
26 | 26 |
validates_presence_of :start_page |
27 | 27 |
validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/ |
28 | 28 |
validates_length_of :start_page, maximum: 255 |
29 |
attr_protected :id |
|
30 | 29 |
|
31 | 30 |
before_destroy :delete_redirects |
32 | 31 |
|
trunk/app/models/wiki_content.rb | ||
---|---|---|
23 | 23 |
belongs_to :author, :class_name => 'User' |
24 | 24 |
validates_presence_of :text |
25 | 25 |
validates_length_of :comments, :maximum => 1024, :allow_nil => true |
26 |
attr_protected :id |
|
27 | 26 |
|
28 | 27 |
acts_as_versioned |
29 | 28 |
|
... | ... | |
60 | 59 |
class Version |
61 | 60 |
belongs_to :page, :class_name => '::WikiPage' |
62 | 61 |
belongs_to :author, :class_name => '::User' |
63 |
attr_protected :data |
|
64 | 62 |
|
65 | 63 |
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, |
66 | 64 |
:description => :comments, |
... | ... | |
161 | 159 |
|
162 | 160 |
def send_notification |
163 | 161 |
# new_record? returns false in after_save callbacks |
164 |
if id_changed?
|
|
162 |
if saved_change_to_id?
|
|
165 | 163 |
if Setting.notified_events.include?('wiki_content_added') |
166 | 164 |
Mailer.wiki_content_added(self).deliver |
167 | 165 |
end |
168 |
elsif text_changed?
|
|
166 |
elsif saved_change_to_text?
|
|
169 | 167 |
if Setting.notified_events.include?('wiki_content_updated') |
170 | 168 |
Mailer.wiki_content_updated(self).deliver |
171 | 169 |
end |
trunk/app/models/wiki_page.rb | ||
---|---|---|
47 | 47 |
validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false |
48 | 48 |
validates_length_of :title, maximum: 255 |
49 | 49 |
validates_associated :content |
50 |
attr_protected :id |
|
51 | 50 |
|
52 | 51 |
validate :validate_parent_title |
53 | 52 |
before_destroy :delete_redirects |
... | ... | |
80 | 79 |
end |
81 | 80 |
|
82 | 81 |
def safe_attributes=(attrs, user=User.current) |
82 |
if attrs.respond_to?(:to_unsafe_hash) |
|
83 |
attrs = attrs.to_unsafe_hash |
|
84 |
end |
|
85 |
|
|
83 | 86 |
return unless attrs.is_a?(Hash) |
84 | 87 |
attrs = attrs.deep_dup |
85 | 88 |
|
... | ... | |
122 | 125 |
|
123 | 126 |
# Moves child pages if page was moved |
124 | 127 |
def handle_children_move |
125 |
if !new_record? && wiki_id_changed?
|
|
128 |
if !new_record? && saved_change_to_wiki_id?
|
|
126 | 129 |
children.each do |child| |
127 | 130 |
child.wiki_id = wiki_id |
128 | 131 |
child.redirect_existing_links = redirect_existing_links |
trunk/app/models/wiki_redirect.rb | ||
---|---|---|
20 | 20 |
|
21 | 21 |
validates_presence_of :wiki_id, :title, :redirects_to |
22 | 22 |
validates_length_of :title, :redirects_to, :maximum => 255 |
23 |
attr_protected :id |
|
24 | 23 |
|
25 | 24 |
before_save :set_redirects_to_wiki_id |
26 | 25 |
|
trunk/app/models/workflow_rule.rb | ||
---|---|---|
24 | 24 |
belongs_to :new_status, :class_name => 'IssueStatus' |
25 | 25 |
|
26 | 26 |
validates_presence_of :role, :tracker |
27 |
attr_protected :id |
|
28 | 27 |
|
29 | 28 |
# Copies workflows from source to targets |
30 | 29 |
def self.copy(source_tracker, source_role, target_trackers, target_roles) |
trunk/app/views/welcome/robots.html.erb | ||
---|---|---|
1 |
User-agent: * |
|
2 |
<% @projects.each do |p| -%> |
|
3 |
Disallow: /projects/<%= p.to_param %>/repository |
|
4 |
Disallow: /projects/<%= p.to_param %>/issues |
|
5 |
Disallow: /projects/<%= p.to_param %>/activity |
|
6 |
<% end -%> |
|
7 |
Disallow: /issues/gantt |
|
8 |
Disallow: /issues/calendar |
|
9 |
Disallow: /activity |
|
10 |
Disallow: /search |
|
11 | 0 |
trunk/app/views/welcome/robots.text.erb | ||
---|---|---|
1 |
User-agent: * |
|
2 |
<% @projects.each do |p| -%> |
|
3 |
Disallow: /projects/<%= p.to_param %>/repository |
|
4 |
Disallow: /projects/<%= p.to_param %>/issues |
|
5 |
Disallow: /projects/<%= p.to_param %>/activity |
|
6 |
<% end -%> |
|
7 |
Disallow: /issues/gantt |
|
8 |
Disallow: /issues/calendar |
|
9 |
Disallow: /activity |
|
10 |
Disallow: /search |
|
0 | 11 |
trunk/config/application.rb | ||
---|---|---|
47 | 47 |
# Do not include all helpers |
48 | 48 |
config.action_controller.include_all_helpers = false |
49 | 49 |
|
50 |
# Do not suppress errors in after_rollback and after_commit callbacks |
|
51 |
config.active_record.raise_in_transactional_callbacks = true |
|
52 |
|
|
53 |
# XML parameter parser removed from core in Rails 4.0 |
|
54 |
# and extracted to actionpack-xml_parser gem |
|
55 |
config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser |
|
56 |
|
|
57 | 50 |
# Sets the Content-Length header on responses with fixed-length bodies |
58 | 51 |
config.middleware.insert_after Rack::Sendfile, Rack::ContentLength |
59 | 52 |
|
trunk/config/initializers/10-patches.rb | ||
---|---|---|
27 | 27 |
end |
28 | 28 |
end |
29 | 29 |
class Relation ; undef open ; end |
30 |
|
|
31 |
# Workaround for a Rails 5.1 regression that breaks queries with a condition |
|
32 |
# on a table that has a column with the same name as the table |
|
33 |
# (eg. comments.comments). It breaks has_many associations to these tables as well. |
|
34 |
# https://github.com/rails/rails/commit/c6a62dc327c54baec87306f5c381e13cacc00a19 |
|
35 |
# |
|
36 |
# Examples (without the following workaround applied): |
|
37 |
# Comment.where(:comments => {:id => 1}) |
|
38 |
# TypeError: can't cast Hash |
|
39 |
# |
|
40 |
# News.first.comments.count |
|
41 |
# TypeError: can't cast Hash |
|
42 |
class PredicateBuilder |
|
43 |
|
|
44 |
protected |
|
45 |
alias :create_binds_for_hash_without_comments_fix :create_binds_for_hash |
|
46 |
def create_binds_for_hash(attributes) |
|
47 |
if attributes["comments"].is_a?(Hash) |
|
48 |
return create_binds_for_hash_without_comments_fix attributes["comments"] |
|
49 |
else |
|
50 |
create_binds_for_hash_without_comments_fix attributes |
|
51 |
end |
|
52 |
end |
|
53 |
end |
|
30 | 54 |
end |
31 | 55 |
|
32 | 56 |
module ActionView |
... | ... | |
201 | 225 |
unless asset_id.blank? |
202 | 226 |
source += "?#{asset_id}" |
203 | 227 |
end |
204 |
asset_path(source, options) |
|
228 |
asset_path(source, options.merge(skip_pipeline: true))
|
|
205 | 229 |
end |
206 | 230 |
alias :path_to_asset :asset_path_with_asset_id |
207 | 231 |
|
... | ... | |
218 | 242 |
if File.exist? path |
219 | 243 |
exist = true |
220 | 244 |
else |
221 |
path = File.join(Rails.public_path, compute_asset_path("#{source}#{extname}", options)) |
|
245 |
path = File.join(Rails.public_path, public_compute_asset_path("#{source}#{extname}", options))
|
|
222 | 246 |
if File.exist? path |
223 | 247 |
exist = true |
224 | 248 |
end |
trunk/config/initializers/20-mime_types.rb | ||
---|---|---|
1 | 1 |
# Add new mime types for use in respond_to blocks: |
2 |
|
|
3 |
Mime::SET << Mime::CSV unless Mime::SET.include?(Mime::CSV) |
|
4 |
|
trunk/config/routes.rb | ||
---|---|---|
242 | 242 |
get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats' |
243 | 243 |
get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph' |
244 | 244 |
|
245 |
get 'projects/:id/repository/:repository_id/changes(/*path)', |
|
246 |
:to => 'repositories#changes', |
|
247 |
:format => false |
|
248 |
|
|
249 | 245 |
get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision' |
250 | 246 |
get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision' |
251 | 247 |
post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue' |
... | ... | |
255 | 251 |
get "projects/:id/repository/:repository_id/revisions/:rev/#{action}(/*path)", |
256 | 252 |
:controller => 'repositories', |
257 | 253 |
:action => action, |
258 |
:format => false,
|
|
259 |
:constraints => {:rev => /[a-z0-9\.\-_]+/} |
|
254 |
:format => 'html',
|
|
255 |
:constraints => {:rev => /[a-z0-9\.\-_]+/, :path => /.*/}
|
|
260 | 256 |
end |
261 | 257 |
|
262 | 258 |
get 'projects/:id/repository/statistics', :to => 'repositories#stats' |
263 | 259 |
get 'projects/:id/repository/graph', :to => 'repositories#graph' |
264 | 260 |
|
265 |
get 'projects/:id/repository/changes(/*path)', |
|
266 |
:to => 'repositories#changes', |
|
267 |
:format => false |
|
268 |
|
|
269 | 261 |
get 'projects/:id/repository/revisions', :to => 'repositories#revisions' |
270 | 262 |
get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision' |
271 | 263 |
get 'projects/:id/repository/revision', :to => 'repositories#revision' |
... | ... | |
275 | 267 |
get "projects/:id/repository/revisions/:rev/#{action}(/*path)", |
276 | 268 |
:controller => 'repositories', |
277 | 269 |
:action => action, |
278 |
:format => false,
|
|
279 |
:constraints => {:rev => /[a-z0-9\.\-_]+/} |
|
270 |
:format => 'html',
|
|
271 |
:constraints => {:rev => /[a-z0-9\.\-_]+/, :path => /.*/}
|
|
280 | 272 |
end |
281 | 273 |
%w(browse entry raw changes annotate diff).each do |action| |
282 | 274 |
get "projects/:id/repository/:repository_id/#{action}(/*path)", |
283 | 275 |
:controller => 'repositories', |
284 | 276 |
:action => action, |
285 |
:format => false |
|
277 |
:format => 'html', |
|
278 |
:constraints => {:path => /.*/} |
|
286 | 279 |
end |
287 | 280 |
%w(browse entry raw changes annotate diff).each do |action| |
288 | 281 |
get "projects/:id/repository/#{action}(/*path)", |
289 | 282 |
:controller => 'repositories', |
290 | 283 |
:action => action, |
291 |
:format => false |
|
284 |
:format => 'html', |
|
285 |
:constraints => {:path => /.*/} |
|
292 | 286 |
end |
293 | 287 |
|
294 |
get 'projects/:id/repository/:repository_id/show/*path', :to => 'repositories#show', :format => false
|
|
295 |
get 'projects/:id/repository/show/*path', :to => 'repositories#show', :format => false
|
|
288 |
get 'projects/:id/repository/:repository_id/show/*path', :to => 'repositories#show', :format => 'html', :constraints => {:path => /.*/}
|
|
289 |
get 'projects/:id/repository/show/*path', :to => 'repositories#show', :format => 'html', :constraints => {:path => /.*/}
|
|
296 | 290 |
|
297 | 291 |
get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil |
298 | 292 |
get 'projects/:id/repository', :to => 'repositories#show', :path => nil |
299 | 293 |
|
300 | 294 |
# additional routes for having the file name at the end of url |
301 |
get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment' |
|
295 |
get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment', :format => 'html'
|
|
302 | 296 |
get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment' |
303 | 297 |
get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/ |
304 | 298 |
get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail' |
... | ... | |
376 | 370 |
|
377 | 371 |
match 'uploads', :to => 'attachments#upload', :via => :post |
378 | 372 |
|
379 |
get 'robots.txt', :to => 'welcome#robots'
|
|
373 |
get 'robots', :to => 'welcome#robots' |
|
380 | 374 |
|
381 | 375 |
Dir.glob File.expand_path("#{Redmine::Plugin.directory}/*") do |plugin_dir| |
382 | 376 |
file = File.join(plugin_dir, "config/routes.rb") |
trunk/db/migrate/001_setup.rb | ||
---|---|---|
15 | 15 |
# along with this program; if not, write to the Free Software |
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
|
18 |
class Setup < ActiveRecord::Migration |
|
18 |
class Setup < ActiveRecord::Migration[4.2]
|
|
19 | 19 |
|
20 | 20 |
class User < ActiveRecord::Base |
21 |
attr_protected :id |
|
22 | 21 |
end |
23 | 22 |
|
24 | 23 |
# model removed |
trunk/db/migrate/002_issue_move.rb | ||
---|---|---|
1 |
class IssueMove < ActiveRecord::Migration |
|
1 |
class IssueMove < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
# model removed |
3 | 3 |
class Permission < ActiveRecord::Base; end |
4 | 4 |
|
trunk/db/migrate/003_issue_add_note.rb | ||
---|---|---|
1 |
class IssueAddNote < ActiveRecord::Migration |
|
1 |
class IssueAddNote < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
# model removed |
3 | 3 |
class Permission < ActiveRecord::Base; end |
4 | 4 |
|
trunk/db/migrate/004_export_pdf.rb | ||
---|---|---|
1 |
class ExportPdf < ActiveRecord::Migration |
|
1 |
class ExportPdf < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
# model removed |
3 | 3 |
class Permission < ActiveRecord::Base; end |
4 | 4 |
|
trunk/db/migrate/005_issue_start_date.rb | ||
---|---|---|
1 |
class IssueStartDate < ActiveRecord::Migration |
|
1 |
class IssueStartDate < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
def self.up |
3 | 3 |
add_column :issues, :start_date, :date |
4 | 4 |
add_column :issues, :done_ratio, :integer, :default => 0, :null => false |
trunk/db/migrate/006_calendar_and_activity.rb | ||
---|---|---|
1 |
class CalendarAndActivity < ActiveRecord::Migration |
|
1 |
class CalendarAndActivity < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
# model removed |
3 | 3 |
class Permission < ActiveRecord::Base; end |
4 | 4 |
|
trunk/db/migrate/007_create_journals.rb | ||
---|---|---|
1 |
class CreateJournals < ActiveRecord::Migration |
|
1 |
class CreateJournals < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
|
3 | 3 |
# model removed, but needed for data migration |
4 | 4 |
class IssueHistory < ActiveRecord::Base; belongs_to :issue; end |
trunk/db/migrate/008_create_user_preferences.rb | ||
---|---|---|
1 |
class CreateUserPreferences < ActiveRecord::Migration |
|
1 |
class CreateUserPreferences < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
def self.up |
3 | 3 |
create_table :user_preferences do |t| |
4 | 4 |
t.column "user_id", :integer, :default => 0, :null => false |
trunk/db/migrate/009_add_hide_mail_pref.rb | ||
---|---|---|
1 |
class AddHideMailPref < ActiveRecord::Migration |
|
1 |
class AddHideMailPref < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
def self.up |
3 | 3 |
add_column :user_preferences, :hide_mail, :boolean, :default => false |
4 | 4 |
end |
trunk/db/migrate/010_create_comments.rb | ||
---|---|---|
1 |
class CreateComments < ActiveRecord::Migration |
|
1 |
class CreateComments < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
def self.up |
3 | 3 |
create_table :comments do |t| |
4 | 4 |
t.column :commented_type, :string, :limit => 30, :default => "", :null => false |
trunk/db/migrate/011_add_news_comments_count.rb | ||
---|---|---|
1 |
class AddNewsCommentsCount < ActiveRecord::Migration |
|
1 |
class AddNewsCommentsCount < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
def self.up |
3 | 3 |
add_column :news, :comments_count, :integer, :default => 0, :null => false |
4 | 4 |
end |
trunk/db/migrate/012_add_comments_permissions.rb | ||
---|---|---|
1 |
class AddCommentsPermissions < ActiveRecord::Migration |
|
1 |
class AddCommentsPermissions < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
# model removed |
3 | 3 |
class Permission < ActiveRecord::Base; end |
4 | 4 |
|
trunk/db/migrate/013_create_queries.rb | ||
---|---|---|
1 |
class CreateQueries < ActiveRecord::Migration |
|
1 |
class CreateQueries < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
def self.up |
3 | 3 |
create_table :queries, :force => true do |t| |
4 | 4 |
t.column "project_id", :integer |
trunk/db/migrate/014_add_queries_permissions.rb | ||
---|---|---|
1 |
class AddQueriesPermissions < ActiveRecord::Migration |
|
1 |
class AddQueriesPermissions < ActiveRecord::Migration[4.2]
|
|
2 | 2 |
# model removed |
3 | 3 |
class Permission < ActiveRecord::Base; end |
4 | 4 |
|
Also available in: Unified diff
Merged rails-5.1 branch (#23630).